Merge branch 'develop' into incoterms

This commit is contained in:
Raffael Meyer 2022-11-25 16:50:55 +01:00 committed by GitHub
commit 905a50cbb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
103 changed files with 1949 additions and 7368 deletions

View File

@ -76,7 +76,7 @@ def get(
def build_result(account, dates, gl_entries): def build_result(account, dates, gl_entries):
result = [[getdate(date), 0.0] for date in dates] result = [[getdate(date), 0.0] for date in dates]
root_type = frappe.db.get_value("Account", account, "root_type") root_type = frappe.get_cached_value("Account", account, "root_type")
# start with the first date # start with the first date
date_index = 0 date_index = 0

View File

@ -58,7 +58,7 @@ class Account(NestedSet):
def validate_parent(self): def validate_parent(self):
"""Fetch Parent Details and validate parent account""" """Fetch Parent Details and validate parent account"""
if self.parent_account: if self.parent_account:
par = frappe.db.get_value( par = frappe.get_cached_value(
"Account", self.parent_account, ["name", "is_group", "company"], as_dict=1 "Account", self.parent_account, ["name", "is_group", "company"], as_dict=1
) )
if not par: if not par:
@ -82,7 +82,7 @@ class Account(NestedSet):
def set_root_and_report_type(self): def set_root_and_report_type(self):
if self.parent_account: if self.parent_account:
par = frappe.db.get_value( par = frappe.get_cached_value(
"Account", self.parent_account, ["report_type", "root_type"], as_dict=1 "Account", self.parent_account, ["report_type", "root_type"], as_dict=1
) )
@ -92,7 +92,7 @@ class Account(NestedSet):
self.root_type = par.root_type self.root_type = par.root_type
if self.is_group: if self.is_group:
db_value = frappe.db.get_value("Account", self.name, ["report_type", "root_type"], as_dict=1) db_value = self.get_doc_before_save()
if db_value: if db_value:
if self.report_type != db_value.report_type: if self.report_type != db_value.report_type:
frappe.db.sql( frappe.db.sql(
@ -111,13 +111,13 @@ class Account(NestedSet):
) )
def validate_root_details(self): def validate_root_details(self):
# does not exists parent doc_before_save = self.get_doc_before_save()
if frappe.db.exists("Account", self.name):
if not frappe.db.get_value("Account", self.name, "parent_account"): if doc_before_save and not doc_before_save.parent_account:
throw(_("Root cannot be edited."), RootNotEditable) throw(_("Root cannot be edited."), RootNotEditable)
if not self.parent_account and not self.is_group: if not self.parent_account and not self.is_group:
frappe.throw(_("The root account {0} must be a group").format(frappe.bold(self.name))) throw(_("The root account {0} must be a group").format(frappe.bold(self.name)))
def validate_root_company_and_sync_account_to_children(self): def validate_root_company_and_sync_account_to_children(self):
# ignore validation while creating new compnay or while syncing to child companies # ignore validation while creating new compnay or while syncing to child companies
@ -127,7 +127,9 @@ class Account(NestedSet):
return return
ancestors = get_root_company(self.company) ancestors = get_root_company(self.company)
if ancestors: if ancestors:
if frappe.get_value("Company", self.company, "allow_account_creation_against_child_company"): if frappe.get_cached_value(
"Company", self.company, "allow_account_creation_against_child_company"
):
return return
if not frappe.db.get_value( if not frappe.db.get_value(
"Account", {"account_name": self.account_name, "company": ancestors[0]}, "name" "Account", {"account_name": self.account_name, "company": ancestors[0]}, "name"
@ -138,7 +140,7 @@ class Account(NestedSet):
if not descendants: if not descendants:
return return
parent_acc_name_map = {} parent_acc_name_map = {}
parent_acc_name, parent_acc_number = frappe.db.get_value( parent_acc_name, parent_acc_number = frappe.get_cached_value(
"Account", self.parent_account, ["account_name", "account_number"] "Account", self.parent_account, ["account_name", "account_number"]
) )
filters = { filters = {
@ -159,27 +161,28 @@ class Account(NestedSet):
self.create_account_for_child_company(parent_acc_name_map, descendants, parent_acc_name) self.create_account_for_child_company(parent_acc_name_map, descendants, parent_acc_name)
def validate_group_or_ledger(self): def validate_group_or_ledger(self):
if self.get("__islocal"): doc_before_save = self.get_doc_before_save()
if not doc_before_save or cint(doc_before_save.is_group) == cint(self.is_group):
return return
existing_is_group = frappe.db.get_value("Account", self.name, "is_group") if self.check_gle_exists():
if cint(self.is_group) != cint(existing_is_group): throw(_("Account with existing transaction cannot be converted to ledger"))
if self.check_gle_exists(): elif self.is_group:
throw(_("Account with existing transaction cannot be converted to ledger")) if self.account_type and not self.flags.exclude_account_type_check:
elif self.is_group: throw(_("Cannot covert to Group because Account Type is selected."))
if self.account_type and not self.flags.exclude_account_type_check: elif self.check_if_child_exists():
throw(_("Cannot covert to Group because Account Type is selected.")) throw(_("Account with child nodes cannot be set as ledger"))
elif self.check_if_child_exists():
throw(_("Account with child nodes cannot be set as ledger"))
def validate_frozen_accounts_modifier(self): def validate_frozen_accounts_modifier(self):
old_value = frappe.db.get_value("Account", self.name, "freeze_account") doc_before_save = self.get_doc_before_save()
if old_value and old_value != self.freeze_account: if not doc_before_save or doc_before_save.freeze_account == self.freeze_account:
frozen_accounts_modifier = frappe.db.get_value( return
"Accounts Settings", None, "frozen_accounts_modifier"
) frozen_accounts_modifier = frappe.get_cached_value(
if not frozen_accounts_modifier or frozen_accounts_modifier not in frappe.get_roles(): "Accounts Settings", "Accounts Settings", "frozen_accounts_modifier"
throw(_("You are not authorized to set Frozen value")) )
if not frozen_accounts_modifier or frozen_accounts_modifier not in frappe.get_roles():
throw(_("You are not authorized to set Frozen value"))
def validate_balance_must_be_debit_or_credit(self): def validate_balance_must_be_debit_or_credit(self):
from erpnext.accounts.utils import get_balance_on from erpnext.accounts.utils import get_balance_on
@ -223,9 +226,9 @@ class Account(NestedSet):
) )
# validate if parent of child company account to be added is a group # validate if parent of child company account to be added is a group
if frappe.db.get_value("Account", self.parent_account, "is_group") and not frappe.db.get_value( if frappe.get_cached_value(
"Account", parent_acc_name_map[company], "is_group" "Account", self.parent_account, "is_group"
): ) and not frappe.get_cached_value("Account", parent_acc_name_map[company], "is_group"):
msg = _( msg = _(
"While creating account for Child Company {0}, parent account {1} found as a ledger account." "While creating account for Child Company {0}, parent account {1} found as a ledger account."
).format(company_bold, parent_acc_name_bold) ).format(company_bold, parent_acc_name_bold)
@ -377,17 +380,15 @@ def validate_account_number(name, account_number, company):
@frappe.whitelist() @frappe.whitelist()
def update_account_number(name, account_name, account_number=None, from_descendant=False): def update_account_number(name, account_name, account_number=None, from_descendant=False):
account = frappe.db.get_value("Account", name, "company", as_dict=True) account = frappe.get_cached_doc("Account", name)
if not account: if not account:
return return
old_acc_name, old_acc_number = frappe.db.get_value( old_acc_name, old_acc_number = account.account_name, account.account_number
"Account", name, ["account_name", "account_number"]
)
# check if account exists in parent company # check if account exists in parent company
ancestors = get_ancestors_of("Company", account.company) ancestors = get_ancestors_of("Company", account.company)
allow_independent_account_creation = frappe.get_value( allow_independent_account_creation = frappe.get_cached_value(
"Company", account.company, "allow_account_creation_against_child_company" "Company", account.company, "allow_account_creation_against_child_company"
) )
@ -435,22 +436,24 @@ def update_account_number(name, account_name, account_number=None, from_descenda
@frappe.whitelist() @frappe.whitelist()
def merge_account(old, new, is_group, root_type, company): def merge_account(old, new, is_group, root_type, company):
# Validate properties before merging # Validate properties before merging
if not frappe.db.exists("Account", new): new_account = frappe.get_cached_doc("Account", new)
if not new_account:
throw(_("Account {0} does not exist").format(new)) throw(_("Account {0} does not exist").format(new))
val = list(frappe.db.get_value("Account", new, ["is_group", "root_type", "company"])) if (new_account.is_group, new_account.root_type, new_account.company) != (
cint(is_group),
if val != [cint(is_group), root_type, company]: root_type,
company,
):
throw( throw(
_( _(
"""Merging is only possible if following properties are same in both records. Is Group, Root Type, Company""" """Merging is only possible if following properties are same in both records. Is Group, Root Type, Company"""
) )
) )
if is_group and frappe.db.get_value("Account", new, "parent_account") == old: if is_group and new_account.parent_account == old:
frappe.db.set_value( new_account.db_set("parent_account", frappe.get_cached_value("Account", old, "parent_account"))
"Account", new, "parent_account", frappe.db.get_value("Account", old, "parent_account")
)
frappe.rename_doc("Account", old, new, merge=1, force=1) frappe.rename_doc("Account", old, new, merge=1, force=1)

View File

@ -53,7 +53,7 @@ def create_charts(
"account_number": account_number, "account_number": account_number,
"account_type": child.get("account_type"), "account_type": child.get("account_type"),
"account_currency": child.get("account_currency") "account_currency": child.get("account_currency")
or frappe.db.get_value("Company", company, "default_currency"), or frappe.get_cached_value("Company", company, "default_currency"),
"tax_rate": child.get("tax_rate"), "tax_rate": child.get("tax_rate"),
} }
) )
@ -148,7 +148,7 @@ def get_charts_for_country(country, with_standard=False):
) or frappe.local.flags.allow_unverified_charts: ) or frappe.local.flags.allow_unverified_charts:
charts.append(content["name"]) charts.append(content["name"])
country_code = frappe.db.get_value("Country", country, "code") country_code = frappe.get_cached_value("Country", country, "code")
if country_code: if country_code:
folders = ("verified",) folders = ("verified",)
if frappe.local.flags.allow_unverified_charts: if frappe.local.flags.allow_unverified_charts:

View File

@ -77,6 +77,6 @@ def get_party_bank_account(party_type, party):
@frappe.whitelist() @frappe.whitelist()
def get_bank_account_details(bank_account): def get_bank_account_details(bank_account):
return frappe.db.get_value( return frappe.get_cached_value(
"Bank Account", bank_account, ["account", "bank", "bank_account_no"], as_dict=1 "Bank Account", bank_account, ["account", "bank", "bank_account_no"], as_dict=1
) )

View File

@ -57,7 +57,7 @@ def get_bank_transactions(bank_account, from_date=None, to_date=None):
@frappe.whitelist() @frappe.whitelist()
def get_account_balance(bank_account, till_date): def get_account_balance(bank_account, till_date):
# returns account balance till the specified date # returns account balance till the specified date
account = frappe.db.get_value("Bank Account", bank_account, "account") account = frappe.get_cached_value("Bank Account", bank_account, "account")
filters = frappe._dict( filters = frappe._dict(
{"account": account, "report_date": till_date, "include_pos_transactions": 1} {"account": account, "report_date": till_date, "include_pos_transactions": 1}
) )
@ -130,8 +130,10 @@ def create_journal_entry_bts(
fieldname=["name", "deposit", "withdrawal", "bank_account"], fieldname=["name", "deposit", "withdrawal", "bank_account"],
as_dict=True, as_dict=True,
)[0] )[0]
company_account = frappe.get_value("Bank Account", bank_transaction.bank_account, "account") company_account = frappe.get_cached_value(
account_type = frappe.db.get_value("Account", second_account, "account_type") "Bank Account", bank_transaction.bank_account, "account"
)
account_type = frappe.get_cached_value("Account", second_account, "account_type")
if account_type in ["Receivable", "Payable"]: if account_type in ["Receivable", "Payable"]:
if not (party_type and party): if not (party_type and party):
frappe.throw( frappe.throw(
@ -164,7 +166,7 @@ def create_journal_entry_bts(
} }
) )
company = frappe.get_value("Account", company_account, "company") company = frappe.get_cached_value("Account", company_account, "company")
journal_entry_dict = { journal_entry_dict = {
"voucher_type": entry_type, "voucher_type": entry_type,
@ -219,8 +221,10 @@ def create_payment_entry_bts(
paid_amount = bank_transaction.unallocated_amount paid_amount = bank_transaction.unallocated_amount
payment_type = "Receive" if bank_transaction.deposit > 0 else "Pay" payment_type = "Receive" if bank_transaction.deposit > 0 else "Pay"
company_account = frappe.get_value("Bank Account", bank_transaction.bank_account, "account") company_account = frappe.get_cached_value(
company = frappe.get_value("Account", company_account, "company") "Bank Account", bank_transaction.bank_account, "account"
)
company = frappe.get_cached_value("Account", company_account, "company")
payment_entry_dict = { payment_entry_dict = {
"company": company, "company": company,
"payment_type": payment_type, "payment_type": payment_type,
@ -266,7 +270,7 @@ def reconcile_vouchers(bank_transaction_name, vouchers):
# updated clear date of all the vouchers based on the bank transaction # updated clear date of all the vouchers based on the bank transaction
vouchers = json.loads(vouchers) vouchers = json.loads(vouchers)
transaction = frappe.get_doc("Bank Transaction", bank_transaction_name) transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
company_account = frappe.db.get_value("Bank Account", transaction.bank_account, "account") company_account = frappe.get_cached_value("Bank Account", transaction.bank_account, "account")
if transaction.unallocated_amount == 0: if transaction.unallocated_amount == 0:
frappe.throw(_("This bank transaction is already fully reconciled")) frappe.throw(_("This bank transaction is already fully reconciled"))
@ -290,7 +294,7 @@ def reconcile_vouchers(bank_transaction_name, vouchers):
"The sum total of amounts of all selected vouchers should be less than the unallocated amount of the bank transaction" "The sum total of amounts of all selected vouchers should be less than the unallocated amount of the bank transaction"
) )
) )
account = frappe.db.get_value("Bank Account", transaction.bank_account, "account") account = frappe.get_cached_value("Bank Account", transaction.bank_account, "account")
for voucher in vouchers: for voucher in vouchers:
gl_entry = frappe.db.get_value( gl_entry = frappe.db.get_value(

View File

@ -74,7 +74,7 @@ def get_header_mapping(columns, bank_account):
def get_bank_mapping(bank_account): def get_bank_mapping(bank_account):
bank_name = frappe.db.get_value("Bank Account", bank_account, "bank") bank_name = frappe.get_cached_value("Bank Account", bank_account, "bank")
bank = frappe.get_doc("Bank", bank_name) bank = frappe.get_doc("Bank", bank_name)
mapping = {row.file_field: row.bank_transaction_field for row in bank.bank_transaction_mapping} mapping = {row.file_field: row.bank_transaction_field for row in bank.bank_transaction_mapping}

View File

@ -59,7 +59,7 @@ class Budget(Document):
account_list = [] account_list = []
for d in self.get("accounts"): for d in self.get("accounts"):
if d.account: if d.account:
account_details = frappe.db.get_value( account_details = frappe.get_cached_value(
"Account", d.account, ["is_group", "company", "report_type"], as_dict=1 "Account", d.account, ["is_group", "company", "report_type"], as_dict=1
) )
@ -306,7 +306,7 @@ def get_other_condition(args, budget, for_doc):
if args.get("fiscal_year"): if args.get("fiscal_year"):
date_field = "schedule_date" if for_doc == "Material Request" else "transaction_date" date_field = "schedule_date" if for_doc == "Material Request" else "transaction_date"
start_date, end_date = frappe.db.get_value( start_date, end_date = frappe.get_cached_value(
"Fiscal Year", args.get("fiscal_year"), ["year_start_date", "year_end_date"] "Fiscal Year", args.get("fiscal_year"), ["year_start_date", "year_end_date"]
) )
@ -379,7 +379,7 @@ def get_accumulated_monthly_budget(monthly_distribution, posting_date, fiscal_ye
): ):
distribution.setdefault(d.month, d.percentage_allocation) distribution.setdefault(d.month, d.percentage_allocation)
dt = frappe.db.get_value("Fiscal Year", fiscal_year, "year_start_date") dt = frappe.get_cached_value("Fiscal Year", fiscal_year, "year_start_date")
accumulated_percentage = 0.0 accumulated_percentage = 0.0
while dt <= getdate(posting_date): while dt <= getdate(posting_date):

View File

@ -45,8 +45,8 @@ def validate_columns(data):
@frappe.whitelist() @frappe.whitelist()
def validate_company(company): def validate_company(company):
parent_company, allow_account_creation_against_child_company = frappe.db.get_value( parent_company, allow_account_creation_against_child_company = frappe.get_cached_value(
"Company", {"name": company}, ["parent_company", "allow_account_creation_against_child_company"] "Company", company, ["parent_company", "allow_account_creation_against_child_company"]
) )
if parent_company and (not allow_account_creation_against_child_company): if parent_company and (not allow_account_creation_against_child_company):

View File

@ -19,7 +19,7 @@ class Dunning(AccountsController):
self.validate_overdue_days() self.validate_overdue_days()
self.validate_amount() self.validate_amount()
if not self.income_account: if not self.income_account:
self.income_account = frappe.db.get_value("Company", self.company, "default_income_account") self.income_account = frappe.get_cached_value("Company", self.company, "default_income_account")
def validate_overdue_days(self): def validate_overdue_days(self):
self.overdue_days = (getdate(self.posting_date) - getdate(self.due_date)).days or 0 self.overdue_days = (getdate(self.posting_date) - getdate(self.due_date)).days or 0

View File

@ -1,389 +1,138 @@
{ {
"allow_copy": 0, "actions": [],
"allow_guest_to_view": 0, "allow_import": 1,
"allow_import": 1, "autoname": "ACC-ERR-.YYYY.-.#####",
"allow_rename": 0, "creation": "2018-04-13 18:25:55.943587",
"autoname": "ACC-ERR-.YYYY.-.#####", "doctype": "DocType",
"beta": 0, "editable_grid": 1,
"creation": "2018-04-13 18:25:55.943587", "engine": "InnoDB",
"custom": 0, "field_order": [
"docstatus": 0, "posting_date",
"doctype": "DocType", "column_break_2",
"document_type": "", "company",
"editable_grid": 1, "section_break_4",
"engine": "InnoDB", "get_entries",
"accounts",
"section_break_6",
"total_gain_loss",
"amended_from"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "default": "Today",
"allow_in_quick_entry": 0, "fieldname": "posting_date",
"allow_on_submit": 0, "fieldtype": "Date",
"bold": 0, "in_list_view": 1,
"collapsible": 0, "label": "Posting Date",
"columns": 0, "reqd": 1
"default": "Today", },
"fieldname": "posting_date",
"fieldtype": "Date",
"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": "Posting Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "column_break_2",
"allow_in_quick_entry": 0, "fieldtype": "Column Break"
"allow_on_submit": 0, },
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_2",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "company",
"allow_in_quick_entry": 0, "fieldtype": "Link",
"allow_on_submit": 0, "in_list_view": 1,
"bold": 0, "label": "Company",
"collapsible": 0, "options": "Company",
"columns": 0, "reqd": 1
"fieldname": "company", },
"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": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "section_break_4",
"allow_in_quick_entry": 0, "fieldtype": "Section Break"
"allow_on_submit": 0, },
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_4",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "get_entries",
"allow_in_quick_entry": 0, "fieldtype": "Button",
"allow_on_submit": 0, "label": "Get Entries"
"bold": 0, },
"collapsible": 0,
"columns": 0,
"fieldname": "get_entries",
"fieldtype": "Button",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Get Entries",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "accounts",
"allow_in_quick_entry": 0, "fieldtype": "Table",
"allow_on_submit": 0, "label": "Exchange Rate Revaluation Account",
"bold": 0, "no_copy": 1,
"collapsible": 0, "options": "Exchange Rate Revaluation Account",
"columns": 0, "reqd": 1
"fieldname": "accounts", },
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Exchange Rate Revaluation Account",
"length": 0,
"no_copy": 1,
"options": "Exchange Rate Revaluation Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "section_break_6",
"allow_in_quick_entry": 0, "fieldtype": "Section Break"
"allow_on_submit": 0, },
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_6",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "total_gain_loss",
"allow_in_quick_entry": 0, "fieldtype": "Currency",
"allow_on_submit": 0, "label": "Total Gain/Loss",
"bold": 0, "options": "Company:company:default_currency",
"collapsible": 0, "read_only": 1
"columns": 0, },
"fieldname": "total_gain_loss",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Total Gain/Loss",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "amended_from",
"allow_in_quick_entry": 0, "fieldtype": "Link",
"allow_on_submit": 0, "label": "Amended From",
"bold": 0, "no_copy": 1,
"collapsible": 0, "options": "Exchange Rate Revaluation",
"columns": 0, "print_hide": 1,
"fieldname": "amended_from", "read_only": 1
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Amended From",
"length": 0,
"no_copy": 1,
"options": "Exchange Rate Revaluation",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
} }
], ],
"has_web_view": 0, "is_submittable": 1,
"hide_heading": 0, "links": [],
"hide_toolbar": 0, "modified": "2022-11-17 10:28:03.911554",
"idx": 0, "modified_by": "Administrator",
"image_view": 0, "module": "Accounts",
"in_create": 0, "name": "Exchange Rate Revaluation",
"is_submittable": 1, "naming_rule": "Expression (old style)",
"issingle": 0, "owner": "Administrator",
"istable": 0,
"max_attachments": 0,
"modified": "2018-08-21 16:15:34.660715",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Exchange Rate Revaluation",
"name_case": "",
"owner": "Administrator",
"permissions": [ "permissions": [
{ {
"amend": 1, "amend": 1,
"cancel": 1, "cancel": 1,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 1, "export": 1,
"if_owner": 0, "print": 1,
"import": 0, "read": 1,
"permlevel": 0, "report": 1,
"print": 1, "role": "System Manager",
"read": 1, "share": 1,
"report": 1, "submit": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1 "write": 1
}, },
{ {
"amend": 1, "amend": 1,
"cancel": 1, "cancel": 1,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 1, "export": 1,
"if_owner": 0, "print": 1,
"import": 0, "read": 1,
"permlevel": 0, "report": 1,
"print": 1, "role": "Accounts Manager",
"read": 1, "share": 1,
"report": 1, "submit": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1 "write": 1
}, },
{ {
"amend": 1, "amend": 1,
"cancel": 1, "cancel": 1,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 1, "export": 1,
"if_owner": 0, "print": 1,
"import": 0, "read": 1,
"permlevel": 0, "report": 1,
"print": 1, "role": "Accounts User",
"read": 1, "share": 1,
"report": 1, "submit": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1 "write": 1
} }
], ],
"quick_entry": 0, "sort_field": "modified",
"read_only": 0, "sort_order": "DESC",
"read_only_onload": 0, "states": [],
"show_name_in_global_search": 0, "track_changes": 1
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0,
"track_views": 0
} }

View File

@ -222,7 +222,7 @@ class ExchangeRateRevaluation(Document):
@frappe.whitelist() @frappe.whitelist()
def get_account_details(account, company, posting_date, party_type=None, party=None): def get_account_details(account, company, posting_date, party_type=None, party=None):
account_currency, account_type = frappe.db.get_value( account_currency, account_type = frappe.get_cached_value(
"Account", account, ["account_currency", "account_type"] "Account", account, ["account_currency", "account_type"]
) )
if account_type in ["Receivable", "Payable"] and not (party_type and party): if account_type in ["Receivable", "Payable"] and not (party_type and party):
@ -233,6 +233,10 @@ def get_account_details(account, company, posting_date, party_type=None, party=N
balance = get_balance_on( balance = get_balance_on(
account, date=posting_date, party_type=party_type, party=party, in_account_currency=False account, date=posting_date, party_type=party_type, party=party, in_account_currency=False
) )
account_details = {
"account_currency": account_currency,
}
if balance: if balance:
balance_in_account_currency = get_balance_on( balance_in_account_currency = get_balance_on(
account, date=posting_date, party_type=party_type, party=party account, date=posting_date, party_type=party_type, party=party
@ -242,13 +246,14 @@ def get_account_details(account, company, posting_date, party_type=None, party=N
) )
new_exchange_rate = get_exchange_rate(account_currency, company_currency, posting_date) new_exchange_rate = get_exchange_rate(account_currency, company_currency, posting_date)
new_balance_in_base_currency = balance_in_account_currency * new_exchange_rate new_balance_in_base_currency = balance_in_account_currency * new_exchange_rate
account_details = { account_details = account_details.update(
"account_currency": account_currency, {
"balance_in_base_currency": balance, "balance_in_base_currency": balance,
"balance_in_account_currency": balance_in_account_currency, "balance_in_account_currency": balance_in_account_currency,
"current_exchange_rate": current_exchange_rate, "current_exchange_rate": current_exchange_rate,
"new_exchange_rate": new_exchange_rate, "new_exchange_rate": new_exchange_rate,
"new_balance_in_base_currency": new_balance_in_base_currency, "new_balance_in_base_currency": new_balance_in_base_currency,
} }
)
return account_details return account_details

View File

@ -1,475 +1,120 @@
{ {
"allow_copy": 0, "actions": [],
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2018-04-13 18:30:06.110433", "creation": "2018-04-13 18:30:06.110433",
"custom": 0,
"docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "",
"editable_grid": 1, "editable_grid": 1,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [
"account",
"party_type",
"party",
"column_break_2",
"account_currency",
"balance_in_account_currency",
"balances",
"current_exchange_rate",
"balance_in_base_currency",
"column_break_9",
"new_exchange_rate",
"new_balance_in_base_currency",
"gain_loss"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "account", "fieldname": "account",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Account", "label": "Account",
"length": 0,
"no_copy": 0,
"options": "Account", "options": "Account",
"permlevel": 0, "reqd": 1
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "party_type", "fieldname": "party_type",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Party Type", "label": "Party Type",
"length": 0, "options": "DocType"
"no_copy": 0,
"options": "DocType",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "party", "fieldname": "party",
"fieldtype": "Dynamic Link", "fieldtype": "Dynamic Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Party", "label": "Party",
"length": 0, "options": "party_type"
"no_copy": 0,
"options": "party_type",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_2", "fieldname": "column_break_2",
"fieldtype": "Column Break", "fieldtype": "Column Break"
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "account_currency", "fieldname": "account_currency",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Account Currency", "label": "Account Currency",
"length": 0,
"no_copy": 0,
"options": "Currency", "options": "Currency",
"permlevel": 0, "read_only": 1
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "balance_in_account_currency", "fieldname": "balance_in_account_currency",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Balance In Account Currency", "label": "Balance In Account Currency",
"length": 0,
"no_copy": 0,
"options": "account_currency", "options": "account_currency",
"permlevel": 0, "read_only": 1
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "balances", "fieldname": "balances",
"fieldtype": "Section Break", "fieldtype": "Section Break"
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "current_exchange_rate", "fieldname": "current_exchange_rate",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Current Exchange Rate", "label": "Current Exchange Rate",
"length": 0, "read_only": 1
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "balance_in_base_currency", "fieldname": "balance_in_base_currency",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Balance In Base Currency", "label": "Balance In Base Currency",
"length": 0, "options": "Company:company:default_currency",
"no_copy": 0, "read_only": 1
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_9", "fieldname": "column_break_9",
"fieldtype": "Column Break", "fieldtype": "Column Break"
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "new_exchange_rate", "fieldname": "new_exchange_rate",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "New Exchange Rate", "label": "New Exchange Rate",
"length": 0, "reqd": 1
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "new_balance_in_base_currency", "fieldname": "new_balance_in_base_currency",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "New Balance In Base Currency", "label": "New Balance In Base Currency",
"length": 0, "options": "Company:company:default_currency",
"no_copy": 0, "read_only": 1
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "gain_loss", "fieldname": "gain_loss",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Gain/Loss", "label": "Gain/Loss",
"length": 0, "options": "Company:company:default_currency",
"no_copy": 0, "read_only": 1
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
} }
], ],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "links": [],
"modified": "2019-06-26 18:57:51.762345", "modified": "2022-11-17 10:26:18.302728",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Exchange Rate Revaluation Account", "name": "Exchange Rate Revaluation Account",
"name_case": "",
"owner": "Administrator", "owner": "Administrator",
"permissions": [], "permissions": [],
"quick_entry": 1, "quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"track_changes": 1, "states": [],
"track_seen": 0, "track_changes": 1
"track_views": 0
} }

View File

@ -170,4 +170,4 @@ def auto_create_fiscal_year():
def get_from_and_to_date(fiscal_year): def get_from_and_to_date(fiscal_year):
fields = ["year_start_date as from_date", "year_end_date as to_date"] fields = ["year_start_date as from_date", "year_end_date as to_date"]
return frappe.db.get_value("Fiscal Year", fiscal_year, fields, as_dict=1) return frappe.get_cached_value("Fiscal Year", fiscal_year, fields, as_dict=1)

View File

@ -58,7 +58,7 @@ class GLEntry(Document):
validate_balance_type(self.account, adv_adj) validate_balance_type(self.account, adv_adj)
validate_frozen_account(self.account, adv_adj) validate_frozen_account(self.account, adv_adj)
if frappe.db.get_value("Account", self.account, "account_type") not in [ if frappe.get_cached_value("Account", self.account, "account_type") not in [
"Receivable", "Receivable",
"Payable", "Payable",
]: ]:
@ -120,7 +120,7 @@ class GLEntry(Document):
frappe.throw(msg, title=_("Missing Cost Center")) frappe.throw(msg, title=_("Missing Cost Center"))
def validate_dimensions_for_pl_and_bs(self): def validate_dimensions_for_pl_and_bs(self):
account_type = frappe.db.get_value("Account", self.account, "report_type") account_type = frappe.get_cached_value("Account", self.account, "report_type")
for dimension in get_checks_for_pl_and_bs_accounts(): for dimension in get_checks_for_pl_and_bs_accounts():
if ( if (
@ -188,7 +188,7 @@ class GLEntry(Document):
def check_pl_account(self): def check_pl_account(self):
if ( if (
self.is_opening == "Yes" self.is_opening == "Yes"
and frappe.db.get_value("Account", self.account, "report_type") == "Profit and Loss" and frappe.get_cached_value("Account", self.account, "report_type") == "Profit and Loss"
and not self.is_cancelled and not self.is_cancelled
): ):
frappe.throw( frappe.throw(
@ -281,7 +281,7 @@ class GLEntry(Document):
def validate_balance_type(account, adv_adj=False): def validate_balance_type(account, adv_adj=False):
if not adv_adj and account: if not adv_adj and account:
balance_must_be = frappe.db.get_value("Account", account, "balance_must_be") balance_must_be = frappe.get_cached_value("Account", account, "balance_must_be")
if balance_must_be: if balance_must_be:
balance = frappe.db.sql( balance = frappe.db.sql(
"""select sum(debit) - sum(credit) """select sum(debit) - sum(credit)

View File

@ -21,7 +21,7 @@ class ItemTaxTemplate(Document):
check_list = [] check_list = []
for d in self.get("taxes"): for d in self.get("taxes"):
if d.tax_type: if d.tax_type:
account_type = frappe.db.get_value("Account", d.tax_type, "account_type") account_type = frappe.get_cached_value("Account", d.tax_type, "account_type")
if account_type not in [ if account_type not in [
"Tax", "Tax",

View File

@ -253,9 +253,6 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro
var party_account_field = jvd.reference_type==="Sales Invoice" ? "debit_to": "credit_to"; var party_account_field = jvd.reference_type==="Sales Invoice" ? "debit_to": "credit_to";
out.filters.push([jvd.reference_type, party_account_field, "=", jvd.account]); out.filters.push([jvd.reference_type, party_account_field, "=", jvd.account]);
if (in_list(['Debit Note', 'Credit Note'], doc.voucher_type)) {
out.filters.push([jvd.reference_type, "is_return", "=", 1]);
}
} }
if(in_list(["Sales Order", "Purchase Order"], jvd.reference_type)) { if(in_list(["Sales Order", "Purchase Order"], jvd.reference_type)) {

View File

@ -319,7 +319,7 @@ class JournalEntry(AccountsController):
def validate_party(self): def validate_party(self):
for d in self.get("accounts"): for d in self.get("accounts"):
account_type = frappe.db.get_value("Account", d.account, "account_type") account_type = frappe.get_cached_value("Account", d.account, "account_type")
if account_type in ["Receivable", "Payable"]: if account_type in ["Receivable", "Payable"]:
if not (d.party_type and d.party): if not (d.party_type and d.party):
frappe.throw( frappe.throw(
@ -382,7 +382,7 @@ class JournalEntry(AccountsController):
def validate_against_jv(self): def validate_against_jv(self):
for d in self.get("accounts"): for d in self.get("accounts"):
if d.reference_type == "Journal Entry": if d.reference_type == "Journal Entry":
account_root_type = frappe.db.get_value("Account", d.account, "root_type") account_root_type = frappe.get_cached_value("Account", d.account, "root_type")
if account_root_type == "Asset" and flt(d.debit) > 0: if account_root_type == "Asset" and flt(d.debit) > 0:
frappe.throw( frappe.throw(
_( _(
@ -631,7 +631,7 @@ class JournalEntry(AccountsController):
def validate_multi_currency(self): def validate_multi_currency(self):
alternate_currency = [] alternate_currency = []
for d in self.get("accounts"): for d in self.get("accounts"):
account = frappe.db.get_value( account = frappe.get_cached_value(
"Account", d.account, ["account_currency", "account_type"], as_dict=1 "Account", d.account, ["account_currency", "account_type"], as_dict=1
) )
if account: if account:
@ -762,7 +762,7 @@ class JournalEntry(AccountsController):
party_amount += d.debit_in_account_currency or d.credit_in_account_currency party_amount += d.debit_in_account_currency or d.credit_in_account_currency
party_account_currency = d.account_currency party_account_currency = d.account_currency
elif frappe.db.get_value("Account", d.account, "account_type") in ["Bank", "Cash"]: elif frappe.get_cached_value("Account", d.account, "account_type") in ["Bank", "Cash"]:
bank_amount += d.debit_in_account_currency or d.credit_in_account_currency bank_amount += d.debit_in_account_currency or d.credit_in_account_currency
bank_account_currency = d.account_currency bank_account_currency = d.account_currency
@ -987,7 +987,7 @@ def get_default_bank_cash_account(company, account_type=None, mode_of_payment=No
account = account_list[0].name account = account_list[0].name
if account: if account:
account_details = frappe.db.get_value( account_details = frappe.get_cached_value(
"Account", account, ["account_currency", "account_type"], as_dict=1 "Account", account, ["account_currency", "account_type"], as_dict=1
) )
@ -1116,7 +1116,7 @@ def get_payment_entry(ref_doc, args):
"party_type": args.get("party_type"), "party_type": args.get("party_type"),
"party": ref_doc.get(args.get("party_type").lower()), "party": ref_doc.get(args.get("party_type").lower()),
"cost_center": cost_center, "cost_center": cost_center,
"account_type": frappe.db.get_value("Account", args.get("party_account"), "account_type"), "account_type": frappe.get_cached_value("Account", args.get("party_account"), "account_type"),
"account_currency": args.get("party_account_currency") "account_currency": args.get("party_account_currency")
or get_account_currency(args.get("party_account")), or get_account_currency(args.get("party_account")),
"balance": get_balance_on(args.get("party_account")), "balance": get_balance_on(args.get("party_account")),
@ -1283,7 +1283,7 @@ def get_party_account_and_balance(company, party_type, party, cost_center=None):
"account": account, "account": account,
"balance": account_balance, "balance": account_balance,
"party_balance": party_balance, "party_balance": party_balance,
"account_currency": frappe.db.get_value("Account", account, "account_currency"), "account_currency": frappe.get_cached_value("Account", account, "account_currency"),
} }
@ -1296,7 +1296,7 @@ def get_account_balance_and_party_type(
frappe.msgprint(_("No Permission"), raise_exception=1) frappe.msgprint(_("No Permission"), raise_exception=1)
company_currency = erpnext.get_company_currency(company) company_currency = erpnext.get_company_currency(company)
account_details = frappe.db.get_value( account_details = frappe.get_cached_value(
"Account", account, ["account_type", "account_currency"], as_dict=1 "Account", account, ["account_type", "account_currency"], as_dict=1
) )
@ -1349,7 +1349,7 @@ def get_exchange_rate(
): ):
from erpnext.setup.utils import get_exchange_rate from erpnext.setup.utils import get_exchange_rate
account_details = frappe.db.get_value( account_details = frappe.get_cached_value(
"Account", account, ["account_type", "root_type", "account_currency", "company"], as_dict=1 "Account", account, ["account_type", "root_type", "account_currency", "company"], as_dict=1
) )

View File

@ -25,7 +25,7 @@ class ModeofPayment(Document):
def validate_accounts(self): def validate_accounts(self):
for entry in self.accounts: for entry in self.accounts:
"""Error when Company of Ledger account doesn't match with Company Selected""" """Error when Company of Ledger account doesn't match with Company Selected"""
if frappe.db.get_value("Account", entry.default_account, "company") != entry.company: if frappe.get_cached_value("Account", entry.default_account, "company") != entry.company:
frappe.throw( frappe.throw(
_("Account {0} does not match with Company {1} in Mode of Account: {2}").format( _("Account {0} does not match with Company {1} in Mode of Account: {2}").format(
entry.default_account, entry.company, self.name entry.default_account, entry.company, self.name

View File

@ -20,7 +20,6 @@ frappe.ui.form.on('Opening Invoice Creation Tool', {
frm.dashboard.reset(); frm.dashboard.reset();
frm.doc.import_in_progress = true; frm.doc.import_in_progress = true;
} }
if (data.user != frappe.session.user) return;
if (data.count == data.total) { if (data.count == data.total) {
setTimeout(() => { setTimeout(() => {
frm.doc.import_in_progress = false; frm.doc.import_in_progress = false;

View File

@ -260,10 +260,10 @@ def publish(index, total, doctype):
dict( dict(
title=_("Opening Invoice Creation In Progress"), title=_("Opening Invoice Creation In Progress"),
message=_("Creating {} out of {} {}").format(index + 1, total, doctype), message=_("Creating {} out of {} {}").format(index + 1, total, doctype),
user=frappe.session.user,
count=index + 1, count=index + 1,
total=total, total=total,
), ),
user=frappe.session.user,
) )

View File

@ -725,7 +725,7 @@ class PaymentEntry(AccountsController):
def validate_transaction_reference(self): def validate_transaction_reference(self):
bank_account = self.paid_to if self.payment_type == "Receive" else self.paid_from bank_account = self.paid_to if self.payment_type == "Receive" else self.paid_from
bank_account_type = frappe.db.get_value("Account", bank_account, "account_type") bank_account_type = frappe.get_cached_value("Account", bank_account, "account_type")
if bank_account_type == "Bank": if bank_account_type == "Bank":
if not self.reference_no or not self.reference_date: if not self.reference_no or not self.reference_date:
@ -1303,7 +1303,7 @@ def split_invoices_based_on_payment_terms(outstanding_invoices):
d.voucher_type, d.voucher_no, "payment_terms_template" d.voucher_type, d.voucher_no, "payment_terms_template"
) )
if payment_term_template: if payment_term_template:
allocate_payment_based_on_payment_terms = frappe.db.get_value( allocate_payment_based_on_payment_terms = frappe.get_cached_value(
"Payment Terms Template", payment_term_template, "allocate_payment_based_on_payment_terms" "Payment Terms Template", payment_term_template, "allocate_payment_based_on_payment_terms"
) )
if allocate_payment_based_on_payment_terms: if allocate_payment_based_on_payment_terms:
@ -1535,7 +1535,7 @@ def get_account_details(account, date, cost_center=None):
{ {
"account_currency": get_account_currency(account), "account_currency": get_account_currency(account),
"account_balance": account_balance, "account_balance": account_balance,
"account_type": frappe.db.get_value("Account", account, "account_type"), "account_type": frappe.get_cached_value("Account", account, "account_type"),
} }
) )
@ -1704,9 +1704,9 @@ def get_payment_entry(
if doc.doctype == "Purchase Invoice" and doc.invoice_is_blocked(): if doc.doctype == "Purchase Invoice" and doc.invoice_is_blocked():
frappe.msgprint(_("{0} is on hold till {1}").format(doc.name, doc.release_date)) frappe.msgprint(_("{0} is on hold till {1}").format(doc.name, doc.release_date))
else: else:
if doc.doctype in ("Sales Invoice", "Purchase Invoice") and frappe.get_value( if doc.doctype in ("Sales Invoice", "Purchase Invoice") and frappe.get_cached_value(
"Payment Terms Template", "Payment Terms Template",
{"name": doc.payment_terms_template}, doc.payment_terms_template,
"allocate_payment_based_on_payment_terms", "allocate_payment_based_on_payment_terms",
): ):

View File

@ -11,7 +11,7 @@ class PaymentGatewayAccount(Document):
self.name = self.payment_gateway + " - " + self.currency self.name = self.payment_gateway + " - " + self.currency
def validate(self): def validate(self):
self.currency = frappe.db.get_value("Account", self.payment_account, "account_currency") self.currency = frappe.get_cached_value("Account", self.payment_account, "account_currency")
self.update_default_payment_gateway() self.update_default_payment_gateway()
self.set_as_default_if_not_set() self.set_as_default_if_not_set()

View File

@ -97,7 +97,7 @@ class PaymentLedgerEntry(Document):
) )
def validate_dimensions_for_pl_and_bs(self): def validate_dimensions_for_pl_and_bs(self):
account_type = frappe.db.get_value("Account", self.account, "report_type") account_type = frappe.get_cached_value("Account", self.account, "report_type")
for dimension in get_checks_for_pl_and_bs_accounts(): for dimension in get_checks_for_pl_and_bs_accounts():
if ( if (

View File

@ -53,7 +53,7 @@ class PaymentRequest(Document):
def validate_currency(self): def validate_currency(self):
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name) ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
if self.payment_account and ref_doc.currency != frappe.db.get_value( if self.payment_account and ref_doc.currency != frappe.get_cached_value(
"Account", self.payment_account, "account_currency" "Account", self.payment_account, "account_currency"
): ):
frappe.throw(_("Transaction currency must be same as Payment Gateway currency")) frappe.throw(_("Transaction currency must be same as Payment Gateway currency"))

View File

@ -43,7 +43,7 @@ class PeriodClosingVoucher(AccountsController):
make_reverse_gl_entries(voucher_type="Period Closing Voucher", voucher_no=self.name) make_reverse_gl_entries(voucher_type="Period Closing Voucher", voucher_no=self.name)
def validate_account_head(self): def validate_account_head(self):
closing_account_type = frappe.db.get_value("Account", self.closing_account_head, "root_type") closing_account_type = frappe.get_cached_value("Account", self.closing_account_head, "root_type")
if closing_account_type not in ["Liability", "Equity"]: if closing_account_type not in ["Liability", "Equity"]:
frappe.throw( frappe.throw(

View File

@ -25,7 +25,7 @@ frappe.ui.form.on('POS Closing Entry', {
frappe.realtime.on('closing_process_complete', async function(data) { frappe.realtime.on('closing_process_complete', async function(data) {
await frm.reload_doc(); await frm.reload_doc();
if (frm.doc.status == 'Failed' && frm.doc.error_message && data.user == frappe.session.user) { if (frm.doc.status == 'Failed' && frm.doc.error_message) {
frappe.msgprint({ frappe.msgprint({
title: __('POS Closing Failed'), title: __('POS Closing Failed'),
message: frm.doc.error_message, message: frm.doc.error_message,

View File

@ -335,7 +335,8 @@ class POSInvoice(SalesInvoice):
if ( if (
self.change_amount self.change_amount
and self.account_for_change_amount and self.account_for_change_amount
and frappe.db.get_value("Account", self.account_for_change_amount, "company") != self.company and frappe.get_cached_value("Account", self.account_for_change_amount, "company")
!= self.company
): ):
frappe.throw( frappe.throw(
_("The selected change account {} doesn't belongs to Company {}.").format( _("The selected change account {} doesn't belongs to Company {}.").format(
@ -486,7 +487,7 @@ class POSInvoice(SalesInvoice):
customer_price_list, customer_group, customer_currency = frappe.db.get_value( customer_price_list, customer_group, customer_currency = frappe.db.get_value(
"Customer", self.customer, ["default_price_list", "customer_group", "default_currency"] "Customer", self.customer, ["default_price_list", "customer_group", "default_currency"]
) )
customer_group_price_list = frappe.db.get_value( customer_group_price_list = frappe.get_cached_value(
"Customer Group", customer_group, "default_price_list" "Customer Group", customer_group, "default_price_list"
) )
selling_price_list = ( selling_price_list = (
@ -532,8 +533,8 @@ class POSInvoice(SalesInvoice):
if not self.debit_to: if not self.debit_to:
self.debit_to = get_party_account("Customer", self.customer, self.company) self.debit_to = get_party_account("Customer", self.customer, self.company)
self.party_account_currency = frappe.db.get_value( self.party_account_currency = frappe.get_cached_value(
"Account", self.debit_to, "account_currency", cache=True "Account", self.debit_to, "account_currency"
) )
if not self.due_date and self.customer: if not self.due_date and self.customer:
self.due_date = get_due_date(self.posting_date, "Customer", self.customer, self.company) self.due_date = get_due_date(self.posting_date, "Customer", self.customer, self.company)

View File

@ -430,7 +430,7 @@ def create_merge_logs(invoice_by_customer, closing_entry=None):
finally: finally:
frappe.db.commit() frappe.db.commit()
frappe.publish_realtime("closing_process_complete", {"user": frappe.session.user}) frappe.publish_realtime("closing_process_complete", user=frappe.session.user)
def cancel_merge_logs(merge_logs, closing_entry=None): def cancel_merge_logs(merge_logs, closing_entry=None):
@ -457,7 +457,7 @@ def cancel_merge_logs(merge_logs, closing_entry=None):
finally: finally:
frappe.db.commit() frappe.db.commit()
frappe.publish_realtime("closing_process_complete", {"user": frappe.session.user}) frappe.publish_realtime("closing_process_complete", user=frappe.session.user)
def enqueue_job(job, **kwargs): def enqueue_job(job, **kwargs):

View File

@ -81,7 +81,7 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
} }
if(doc.docstatus == 1 && doc.outstanding_amount != 0 if(doc.docstatus == 1 && doc.outstanding_amount != 0
&& !(doc.is_return && doc.return_against)) { && !(doc.is_return && doc.return_against) && !doc.on_hold) {
this.frm.add_custom_button(__('Payment'), this.make_payment_entry, __('Create')); this.frm.add_custom_button(__('Payment'), this.make_payment_entry, __('Create'));
cur_frm.page.set_inner_btn_group_as_primary(__('Create')); cur_frm.page.set_inner_btn_group_as_primary(__('Create'));
} }
@ -99,7 +99,7 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
} }
} }
if (doc.outstanding_amount > 0 && !cint(doc.is_return)) { if (doc.outstanding_amount > 0 && !cint(doc.is_return) && !doc.on_hold) {
cur_frm.add_custom_button(__('Payment Request'), function() { cur_frm.add_custom_button(__('Payment Request'), function() {
me.make_payment_request() me.make_payment_request()
}, __('Create')); }, __('Create'));

View File

@ -25,6 +25,10 @@
"apply_tds", "apply_tds",
"tax_withholding_category", "tax_withholding_category",
"amended_from", "amended_from",
"supplier_invoice_details",
"bill_no",
"column_break_15",
"bill_date",
"accounting_dimensions_section", "accounting_dimensions_section",
"cost_center", "cost_center",
"dimension_col_break", "dimension_col_break",
@ -152,10 +156,6 @@
"status", "status",
"column_break_177", "column_break_177",
"per_received", "per_received",
"supplier_invoice_details",
"bill_no",
"column_break_15",
"bill_date",
"accounting_details_section", "accounting_details_section",
"credit_to", "credit_to",
"party_account_currency", "party_account_currency",
@ -1547,7 +1547,7 @@
"idx": 204, "idx": 204,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2022-11-17 17:30:45.559785", "modified": "2022-11-25 12:44:29.935567",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Purchase Invoice", "name": "Purchase Invoice",

View File

@ -153,8 +153,8 @@ class PurchaseInvoice(BuyingController):
def set_missing_values(self, for_validate=False): def set_missing_values(self, for_validate=False):
if not self.credit_to: if not self.credit_to:
self.credit_to = get_party_account("Supplier", self.supplier, self.company) self.credit_to = get_party_account("Supplier", self.supplier, self.company)
self.party_account_currency = frappe.db.get_value( self.party_account_currency = frappe.get_cached_value(
"Account", self.credit_to, "account_currency", cache=True "Account", self.credit_to, "account_currency"
) )
if not self.due_date: if not self.due_date:
self.due_date = get_due_date( self.due_date = get_due_date(
@ -175,7 +175,7 @@ class PurchaseInvoice(BuyingController):
if not self.credit_to: if not self.credit_to:
self.raise_missing_debit_credit_account_error("Supplier", self.supplier) self.raise_missing_debit_credit_account_error("Supplier", self.supplier)
account = frappe.db.get_value( account = frappe.get_cached_value(
"Account", self.credit_to, ["account_type", "report_type", "account_currency"], as_dict=True "Account", self.credit_to, ["account_type", "report_type", "account_currency"], as_dict=True
) )
@ -606,7 +606,7 @@ class PurchaseInvoice(BuyingController):
def make_supplier_gl_entry(self, gl_entries): def make_supplier_gl_entry(self, gl_entries):
# Checked both rounding_adjustment and rounded_total # Checked both rounding_adjustment and rounded_total
# because rounded_total had value even before introcution of posting GLE based on rounded total # because rounded_total had value even before introduction of posting GLE based on rounded total
grand_total = ( grand_total = (
self.rounded_total if (self.rounding_adjustment and self.rounded_total) else self.grand_total self.rounded_total if (self.rounding_adjustment and self.rounded_total) else self.grand_total
) )
@ -673,7 +673,7 @@ class PurchaseInvoice(BuyingController):
exchange_rate_map, net_rate_map = get_purchase_document_details(self) exchange_rate_map, net_rate_map = get_purchase_document_details(self)
provisional_accounting_for_non_stock_items = cint( provisional_accounting_for_non_stock_items = cint(
frappe.db.get_value( frappe.get_cached_value(
"Company", self.company, "enable_provisional_accounting_for_non_stock_items" "Company", self.company, "enable_provisional_accounting_for_non_stock_items"
) )
) )
@ -809,10 +809,7 @@ class PurchaseInvoice(BuyingController):
else item.deferred_expense_account else item.deferred_expense_account
) )
if not item.is_fixed_asset: dummy, amount = self.get_amount_and_base_amount(item, None)
dummy, amount = self.get_amount_and_base_amount(item, None)
else:
amount = flt(item.base_net_amount + item.item_tax_amount, item.precision("base_net_amount"))
if provisional_accounting_for_non_stock_items: if provisional_accounting_for_non_stock_items:
if item.purchase_receipt: if item.purchase_receipt:
@ -984,7 +981,7 @@ class PurchaseInvoice(BuyingController):
asset_amount = flt(item.net_amount) + flt(item.item_tax_amount / self.conversion_rate) asset_amount = flt(item.net_amount) + flt(item.item_tax_amount / self.conversion_rate)
base_asset_amount = flt(item.base_net_amount + item.item_tax_amount) base_asset_amount = flt(item.base_net_amount + item.item_tax_amount)
item_exp_acc_type = frappe.db.get_value("Account", item.expense_account, "account_type") item_exp_acc_type = frappe.get_cached_value("Account", item.expense_account, "account_type")
if not item.expense_account or item_exp_acc_type not in [ if not item.expense_account or item_exp_acc_type not in [
"Asset Received But Not Billed", "Asset Received But Not Billed",
"Fixed Asset", "Fixed Asset",

View File

@ -63,7 +63,7 @@ frappe.listview_settings["Purchase Invoice"] = {
}); });
listview.page.add_action_item(__("Payment"), ()=>{ listview.page.add_action_item(__("Payment"), ()=>{
erpnext.bulk_transaction_processing.create(listview, "Purchase Invoice", "Payment"); erpnext.bulk_transaction_processing.create(listview, "Purchase Invoice", "Payment Entry");
}); });
} }
}; };

View File

@ -2165,6 +2165,8 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
if source.doctype == "Purchase Order Item" and target.doctype == "Sales Order Item": if source.doctype == "Purchase Order Item" and target.doctype == "Sales Order Item":
target.purchase_order = source.parent target.purchase_order = source.parent
target.purchase_order_item = source.name target.purchase_order_item = source.name
target.material_request = source.material_request
target.material_request_item = source.material_request_item
if ( if (
source.get("purchase_order") source.get("purchase_order")

View File

@ -29,7 +29,7 @@ frappe.listview_settings['Sales Invoice'] = {
}); });
listview.page.add_action_item(__("Payment"), ()=>{ listview.page.add_action_item(__("Payment"), ()=>{
erpnext.bulk_transaction_processing.create(listview, "Sales Invoice", "Payment"); erpnext.bulk_transaction_processing.create(listview, "Sales Invoice", "Payment Entry");
}); });
} }
}; };

View File

@ -27,7 +27,7 @@ class SalesTaxesandChargesTemplate(Document):
def set_missing_values(self): def set_missing_values(self):
for data in self.taxes: for data in self.taxes:
if data.charge_type == "On Net Total" and flt(data.rate) == 0.0: if data.charge_type == "On Net Total" and flt(data.rate) == 0.0:
data.rate = frappe.db.get_value("Account", data.account_head, "tax_rate") data.rate = frappe.get_cached_value("Account", data.account_head, "tax_rate")
def valdiate_taxes_and_charges_template(doc): def valdiate_taxes_and_charges_template(doc):

View File

@ -226,6 +226,42 @@ class TestTaxWithholdingCategory(unittest.TestCase):
for d in reversed(invoices): for d in reversed(invoices):
d.cancel() d.cancel()
orders = []
po = create_purchase_order(supplier="Test TDS Supplier4", rate=20000, do_not_save=True)
po.extend(
"items",
[
{
"doctype": "Purchase Order Item",
"item_code": frappe.db.get_value("Item", {"item_name": "TDS Item"}, "name"),
"qty": 1,
"rate": 20000,
"cost_center": "Main - _TC",
"expense_account": "Stock Received But Not Billed - _TC",
"apply_tds": 0,
},
{
"doctype": "Purchase Order Item",
"item_code": frappe.db.get_value("Item", {"item_name": "TDS Item"}, "name"),
"qty": 1,
"rate": 35000,
"cost_center": "Main - _TC",
"expense_account": "Stock Received But Not Billed - _TC",
"apply_tds": 1,
},
],
)
po.save()
po.submit()
orders.append(po)
self.assertEqual(po.taxes[0].tax_amount, 5500)
# cancel orders to avoid clashing
for d in reversed(orders):
d.cancel()
def test_multi_category_single_supplier(self): def test_multi_category_single_supplier(self):
frappe.db.set_value( frappe.db.set_value(
"Supplier", "Test TDS Supplier5", "tax_withholding_category", "Test Service Category" "Supplier", "Test TDS Supplier5", "tax_withholding_category", "Test Service Category"
@ -348,6 +384,39 @@ def create_purchase_invoice(**args):
return pi return pi
def create_purchase_order(**args):
# return purchase order doc object
item = frappe.db.get_value("Item", {"item_name": "TDS Item"}, "name")
args = frappe._dict(args)
po = frappe.get_doc(
{
"doctype": "Purchase Order",
"transaction_date": today(),
"schedule_date": today(),
"apply_tds": 0 if args.do_not_apply_tds else 1,
"supplier": args.supplier,
"company": "_Test Company",
"taxes_and_charges": "",
"currency": "INR",
"taxes": [],
"items": [
{
"doctype": "Purchase Order Item",
"item_code": item,
"qty": args.qty or 1,
"rate": args.rate or 10000,
"cost_center": "Main - _TC",
"expense_account": "Stock Received But Not Billed - _TC",
}
],
}
)
po.save()
return po
def create_sales_invoice(**args): def create_sales_invoice(**args):
# return sales invoice doc object # return sales invoice doc object
item = frappe.db.get_value("Item", {"item_name": "TCS Item"}, "name") item = frappe.db.get_value("Item", {"item_name": "TCS Item"}, "name")

View File

@ -394,20 +394,22 @@ def make_round_off_gle(gl_map, debit_credit_diff, precision):
round_off_account, round_off_cost_center = get_round_off_account_and_cost_center( round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(
gl_map[0].company, gl_map[0].voucher_type, gl_map[0].voucher_no gl_map[0].company, gl_map[0].voucher_type, gl_map[0].voucher_no
) )
round_off_account_exists = False
round_off_gle = frappe._dict() round_off_gle = frappe._dict()
for d in gl_map: round_off_account_exists = False
if d.account == round_off_account:
round_off_gle = d
if d.debit:
debit_credit_diff -= flt(d.debit)
else:
debit_credit_diff += flt(d.credit)
round_off_account_exists = True
if round_off_account_exists and abs(debit_credit_diff) < (1.0 / (10**precision)): if gl_map[0].voucher_type != "Period Closing Voucher":
gl_map.remove(round_off_gle) for d in gl_map:
return if d.account == round_off_account:
round_off_gle = d
if d.debit:
debit_credit_diff -= flt(d.debit) - flt(d.credit)
else:
debit_credit_diff += flt(d.credit)
round_off_account_exists = True
if round_off_account_exists and abs(debit_credit_diff) < (1.0 / (10**precision)):
gl_map.remove(round_off_gle)
return
if not round_off_gle: if not round_off_gle:
for k in ["voucher_type", "voucher_no", "company", "posting_date", "remarks"]: for k in ["voucher_type", "voucher_no", "company", "posting_date", "remarks"]:
@ -430,7 +432,6 @@ def make_round_off_gle(gl_map, debit_credit_diff, precision):
) )
update_accounting_dimensions(round_off_gle) update_accounting_dimensions(round_off_gle)
if not round_off_account_exists: if not round_off_account_exists:
gl_map.append(round_off_gle) gl_map.append(round_off_gle)

View File

@ -296,7 +296,7 @@ def get_default_price_list(party):
return party.default_price_list return party.default_price_list
if party.doctype == "Customer": if party.doctype == "Customer":
return frappe.db.get_value("Customer Group", party.customer_group, "default_price_list") return frappe.get_cached_value("Customer Group", party.customer_group, "default_price_list")
def set_price_list(party_details, party, party_type, given_price_list, pos=None): def set_price_list(party_details, party, party_type, given_price_list, pos=None):
@ -385,7 +385,7 @@ def get_party_account(party_type, party=None, company=None):
existing_gle_currency = get_party_gle_currency(party_type, party, company) existing_gle_currency = get_party_gle_currency(party_type, party, company)
if existing_gle_currency: if existing_gle_currency:
if account: if account:
account_currency = frappe.db.get_value("Account", account, "account_currency", cache=True) account_currency = frappe.get_cached_value("Account", account, "account_currency")
if (account and account_currency != existing_gle_currency) or not account: if (account and account_currency != existing_gle_currency) or not account:
account = get_party_gle_account(party_type, party, company) account = get_party_gle_account(party_type, party, company)
@ -402,7 +402,7 @@ def get_party_bank_account(party_type, party):
def get_party_account_currency(party_type, party, company): def get_party_account_currency(party_type, party, company):
def generator(): def generator():
party_account = get_party_account(party_type, party, company) party_account = get_party_account(party_type, party, company)
return frappe.db.get_value("Account", party_account, "account_currency", cache=True) return frappe.get_cached_value("Account", party_account, "account_currency")
return frappe.local_cache("party_account_currency", (party_type, party, company), generator) return frappe.local_cache("party_account_currency", (party_type, party, company), generator)
@ -474,15 +474,15 @@ def validate_party_accounts(doc):
else: else:
companies.append(account.company) companies.append(account.company)
party_account_currency = frappe.db.get_value( party_account_currency = frappe.get_cached_value("Account", account.account, "account_currency")
"Account", account.account, "account_currency", cache=True
)
if frappe.db.get_default("Company"): if frappe.db.get_default("Company"):
company_default_currency = frappe.get_cached_value( company_default_currency = frappe.get_cached_value(
"Company", frappe.db.get_default("Company"), "default_currency" "Company", frappe.db.get_default("Company"), "default_currency"
) )
else: else:
company_default_currency = frappe.db.get_value("Company", account.company, "default_currency") company_default_currency = frappe.get_cached_value(
"Company", account.company, "default_currency"
)
validate_party_gle_currency(doc.doctype, doc.name, account.company, party_account_currency) validate_party_gle_currency(doc.doctype, doc.name, account.company, party_account_currency)
@ -801,7 +801,7 @@ def get_dashboard_info(party_type, party, loyalty_program=None):
) )
for d in companies: for d in companies:
company_default_currency = frappe.db.get_value("Company", d.company, "default_currency") company_default_currency = frappe.get_cached_value("Company", d.company, "default_currency")
party_account_currency = get_party_account_currency(party_type, party, d.company) party_account_currency = get_party_account_currency(party_type, party, d.company)
if party_account_currency == company_default_currency: if party_account_currency == company_default_currency:

View File

@ -21,7 +21,7 @@ def execute(filters=None):
if not filters.get("account"): if not filters.get("account"):
return columns, [] return columns, []
account_currency = frappe.db.get_value("Account", filters.account, "account_currency") account_currency = frappe.get_cached_value("Account", filters.account, "account_currency")
data = get_entries(filters) data = get_entries(filters)

View File

@ -180,7 +180,7 @@ def get_account_type_based_gl_data(company, start_date, end_date, account_type,
filters = frappe._dict(filters or {}) filters = frappe._dict(filters or {})
if filters.include_default_book_entries: if filters.include_default_book_entries:
company_fb = frappe.db.get_value("Company", company, "default_finance_book") company_fb = frappe.get_cached_value("Company", company, "default_finance_book")
cond = """ AND (finance_book in (%s, %s, '') OR finance_book IS NULL) cond = """ AND (finance_book in (%s, %s, '') OR finance_book IS NULL)
""" % ( """ % (
frappe.db.escape(filters.finance_book), frappe.db.escape(filters.finance_book),

View File

@ -641,7 +641,7 @@ def set_gl_entries_by_account(
"rgt": root_rgt, "rgt": root_rgt,
"company": d.name, "company": d.name,
"finance_book": filters.get("finance_book"), "finance_book": filters.get("finance_book"),
"company_fb": frappe.db.get_value("Company", d.name, "default_finance_book"), "company_fb": frappe.get_cached_value("Company", d.name, "default_finance_book"),
}, },
as_dict=True, as_dict=True,
) )

View File

@ -220,8 +220,8 @@ class PartyLedgerSummaryReport(object):
if self.filters.party_type == "Customer": if self.filters.party_type == "Customer":
if self.filters.get("customer_group"): if self.filters.get("customer_group"):
lft, rgt = frappe.db.get_value( lft, rgt = frappe.get_cached_value(
"Customer Group", self.filters.get("customer_group"), ["lft", "rgt"] "Customer Group", self.filters["customer_group"], ["lft", "rgt"]
) )
conditions.append( conditions.append(

View File

@ -90,7 +90,7 @@ def set_gl_entries_by_account(dimension_list, filters, account, gl_entries_by_ac
gl_filters["dimensions"] = set(dimension_list) gl_filters["dimensions"] = set(dimension_list)
if filters.get("include_default_book_entries"): if filters.get("include_default_book_entries"):
gl_filters["company_fb"] = frappe.db.get_value( gl_filters["company_fb"] = frappe.get_cached_value(
"Company", filters.company, "default_finance_book" "Company", filters.company, "default_finance_book"
) )

View File

@ -440,7 +440,7 @@ def set_gl_entries_by_account(
} }
if filters.get("include_default_book_entries"): if filters.get("include_default_book_entries"):
gl_filters["company_fb"] = frappe.db.get_value("Company", company, "default_finance_book") gl_filters["company_fb"] = frappe.get_cached_value("Company", company, "default_finance_book")
for key, value in filters.items(): for key, value in filters.items():
if value: if value:

View File

@ -121,7 +121,7 @@ def set_account_currency(filters):
if is_same_account_currency: if is_same_account_currency:
account_currency = currency account_currency = currency
elif filters.get("party"): elif filters.get("party") and filters.get("party_type"):
gle_currency = frappe.db.get_value( gle_currency = frappe.db.get_value(
"GL Entry", "GL Entry",
{"party_type": filters.party_type, "party": filters.party[0], "company": filters.company}, {"party_type": filters.party_type, "party": filters.party[0], "company": filters.company},
@ -134,7 +134,7 @@ def set_account_currency(filters):
account_currency = ( account_currency = (
None None
if filters.party_type in ["Employee", "Shareholder", "Member"] if filters.party_type in ["Employee", "Shareholder", "Member"]
else frappe.db.get_value(filters.party_type, filters.party[0], "default_currency") else frappe.get_cached_value(filters.party_type, filters.party[0], "default_currency")
) )
filters["account_currency"] = account_currency or filters.company_currency filters["account_currency"] = account_currency or filters.company_currency
@ -174,7 +174,7 @@ def get_gl_entries(filters, accounting_dimensions):
order_by_statement = "order by account, posting_date, creation" order_by_statement = "order by account, posting_date, creation"
if filters.get("include_default_book_entries"): if filters.get("include_default_book_entries"):
filters["company_fb"] = frappe.db.get_value( filters["company_fb"] = frappe.get_cached_value(
"Company", filters.get("company"), "default_finance_book" "Company", filters.get("company"), "default_finance_book"
) )
@ -286,9 +286,11 @@ def get_accounts_with_children(accounts):
all_accounts = [] all_accounts = []
for d in accounts: for d in accounts:
if frappe.db.exists("Account", d): account = frappe.get_cached_doc("Account", d)
lft, rgt = frappe.db.get_value("Account", d, ["lft", "rgt"]) if account:
children = frappe.get_all("Account", filters={"lft": [">=", lft], "rgt": ["<=", rgt]}) children = frappe.get_all(
"Account", filters={"lft": [">=", account.lft], "rgt": ["<=", account.rgt]}
)
all_accounts += [c.name for c in children] all_accounts += [c.name for c in children]
else: else:
frappe.throw(_("Account: {0} does not exist").format(d)) frappe.throw(_("Account: {0} does not exist").format(d))

View File

@ -232,12 +232,12 @@ def get_conditions(filters):
conditions += ( conditions += (
common_condition common_condition
+ "and ifnull(`tabPurchase Invoice Item`.{0}, '') in %({0})s)".format(dimension.fieldname) + "and ifnull(`tabPurchase Invoice`.{0}, '') in %({0})s)".format(dimension.fieldname)
) )
else: else:
conditions += ( conditions += (
common_condition common_condition
+ "and ifnull(`tabPurchase Invoice Item`.{0}, '') in %({0})s)".format(dimension.fieldname) + "and ifnull(`tabPurchase Invoice`.{0}, '') in %({0})s)".format(dimension.fieldname)
) )
return conditions return conditions

View File

@ -390,12 +390,12 @@ def get_conditions(filters):
conditions += ( conditions += (
common_condition common_condition
+ "and ifnull(`tabSales Invoice Item`.{0}, '') in %({0})s)".format(dimension.fieldname) + "and ifnull(`tabSales Invoice`.{0}, '') in %({0})s)".format(dimension.fieldname)
) )
else: else:
conditions += ( conditions += (
common_condition common_condition
+ "and ifnull(`tabSales Invoice Item`.{0}, '') in %({0})s)".format(dimension.fieldname) + "and ifnull(`tabSales Invoice`.{0}, '') in %({0})s)".format(dimension.fieldname)
) )
return conditions return conditions

View File

@ -38,7 +38,7 @@ def validate_filters(filters):
if not filters.fiscal_year: if not filters.fiscal_year:
frappe.throw(_("Fiscal Year {0} is required").format(filters.fiscal_year)) frappe.throw(_("Fiscal Year {0} is required").format(filters.fiscal_year))
fiscal_year = frappe.db.get_value( fiscal_year = frappe.get_cached_value(
"Fiscal Year", filters.fiscal_year, ["year_start_date", "year_end_date"], as_dict=True "Fiscal Year", filters.fiscal_year, ["year_start_date", "year_end_date"], as_dict=True
) )
if not fiscal_year: if not fiscal_year:
@ -177,7 +177,7 @@ def get_rootwise_opening_balances(filters, report_type):
"year_start_date": filters.year_start_date, "year_start_date": filters.year_start_date,
"project": filters.project, "project": filters.project,
"finance_book": filters.finance_book, "finance_book": filters.finance_book,
"company_fb": frappe.db.get_value("Company", filters.company, "default_finance_book"), "company_fb": frappe.get_cached_value("Company", filters.company, "default_finance_book"),
} }
if accounting_dimensions: if accounting_dimensions:

View File

@ -975,7 +975,7 @@ def get_account_balances(accounts, company):
def create_payment_gateway_account(gateway, payment_channel="Email"): def create_payment_gateway_account(gateway, payment_channel="Email"):
from erpnext.setup.setup_wizard.operations.install_fixtures import create_bank_account from erpnext.setup.setup_wizard.operations.install_fixtures import create_bank_account
company = frappe.db.get_value("Global Defaults", None, "default_company") company = frappe.get_cached_value("Global Defaults", "Global Defaults", "default_company")
if not company: if not company:
return return

View File

@ -224,7 +224,10 @@ class TestAsset(AssetSetup):
asset.finance_books[0], 9000, get_last_day(add_months(purchase_date, 1)), date asset.finance_books[0], 9000, get_last_day(add_months(purchase_date, 1)), date
) )
pro_rata_amount = flt(pro_rata_amount, asset.precision("gross_purchase_amount")) pro_rata_amount = flt(pro_rata_amount, asset.precision("gross_purchase_amount"))
self.assertEquals(accumulated_depr_amount, 18000.00 + pro_rata_amount) self.assertEquals(
accumulated_depr_amount,
flt(18000.0 + pro_rata_amount, asset.precision("gross_purchase_amount")),
)
self.assertEqual(asset.status, "Scrapped") self.assertEqual(asset.status, "Scrapped")
self.assertTrue(asset.journal_entry_for_scrap) self.assertTrue(asset.journal_entry_for_scrap)

View File

@ -54,6 +54,8 @@
"column_break_26", "column_break_26",
"total", "total",
"net_total", "net_total",
"tax_withholding_net_total",
"base_tax_withholding_net_total",
"section_break_48", "section_break_48",
"pricing_rules", "pricing_rules",
"raw_material_details", "raw_material_details",
@ -1221,6 +1223,26 @@
"label": "Additional Info", "label": "Additional Info",
"oldfieldtype": "Section Break" "oldfieldtype": "Section Break"
}, },
{
"default": "0",
"fieldname": "tax_withholding_net_total",
"fieldtype": "Currency",
"hidden": 1,
"label": "Tax Withholding Net Total",
"no_copy": 1,
"options": "currency",
"read_only": 1
},
{
"fieldname": "base_tax_withholding_net_total",
"fieldtype": "Currency",
"hidden": 1,
"label": "Base Tax Withholding Net Total",
"no_copy": 1,
"options": "currency",
"print_hide": 1,
"read_only": 1
},
{ {
"fieldname": "column_break_99", "fieldname": "column_break_99",
"fieldtype": "Column Break" "fieldtype": "Column Break"

View File

@ -736,27 +736,29 @@ class TestPurchaseOrder(FrappeTestCase):
def test_advance_paid_upon_payment_entry_cancellation(self): def test_advance_paid_upon_payment_entry_cancellation(self):
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
po_doc = create_purchase_order() po_doc = create_purchase_order(supplier="_Test Supplier USD", currency="USD", do_not_submit=1)
po_doc.conversion_rate = 80
po_doc.submit()
pe = get_payment_entry("Purchase Order", po_doc.name, bank_account="_Test Bank - _TC") pe = get_payment_entry("Purchase Order", po_doc.name)
pe.reference_no = "1" pe.mode_of_payment = "Cash"
pe.reference_date = nowdate() pe.paid_from = "Cash - _TC"
pe.paid_from_account_currency = po_doc.currency pe.source_exchange_rate = 80
pe.paid_to_account_currency = po_doc.currency
pe.source_exchange_rate = 1
pe.target_exchange_rate = 1 pe.target_exchange_rate = 1
pe.paid_amount = po_doc.grand_total pe.paid_amount = po_doc.grand_total
pe.save(ignore_permissions=True) pe.save(ignore_permissions=True)
pe.submit() pe.submit()
po_doc.reload() po_doc.reload()
self.assertEqual(po_doc.advance_paid, po_doc.base_grand_total) self.assertEqual(po_doc.advance_paid, po_doc.grand_total)
self.assertEqual(po_doc.party_account_currency, "USD")
pe_doc = frappe.get_doc("Payment Entry", pe.name) pe_doc = frappe.get_doc("Payment Entry", pe.name)
pe_doc.cancel() pe_doc.cancel()
po_doc.reload() po_doc.reload()
self.assertEqual(po_doc.advance_paid, 0) self.assertEqual(po_doc.advance_paid, 0)
self.assertEqual(po_doc.party_account_currency, "USD")
def test_schedule_date(self): def test_schedule_date(self):
po = create_purchase_order(do_not_submit=True) po = create_purchase_order(do_not_submit=True)
@ -833,6 +835,10 @@ class TestPurchaseOrder(FrappeTestCase):
prepare_data_for_internal_transfer() prepare_data_for_internal_transfer()
supplier = "_Test Internal Supplier 2" supplier = "_Test Internal Supplier 2"
mr = make_material_request(
qty=2, company="_Test Company with perpetual inventory", warehouse="Stores - TCP1"
)
po = create_purchase_order( po = create_purchase_order(
company="_Test Company with perpetual inventory", company="_Test Company with perpetual inventory",
supplier=supplier, supplier=supplier,
@ -840,6 +846,8 @@ class TestPurchaseOrder(FrappeTestCase):
from_warehouse="_Test Internal Warehouse New 1 - TCP1", from_warehouse="_Test Internal Warehouse New 1 - TCP1",
qty=2, qty=2,
rate=1, rate=1,
material_request=mr.name,
material_request_item=mr.items[0].name,
) )
so = make_inter_company_sales_order(po.name) so = make_inter_company_sales_order(po.name)
@ -875,9 +883,11 @@ class TestPurchaseOrder(FrappeTestCase):
self.assertTrue(pi.items[0].purchase_order) self.assertTrue(pi.items[0].purchase_order)
self.assertTrue(pi.items[0].po_detail) self.assertTrue(pi.items[0].po_detail)
pi.submit() pi.submit()
mr.reload()
po.load_from_db() po.load_from_db()
self.assertEqual(po.status, "Completed") self.assertEqual(po.status, "Completed")
self.assertEqual(mr.status, "Received")
def prepare_data_for_internal_transfer(): def prepare_data_for_internal_transfer():
@ -979,6 +989,8 @@ def create_purchase_order(**args):
"schedule_date": add_days(nowdate(), 1), "schedule_date": add_days(nowdate(), 1),
"include_exploded_items": args.get("include_exploded_items", 1), "include_exploded_items": args.get("include_exploded_items", 1),
"against_blanket_order": args.against_blanket_order, "against_blanket_order": args.against_blanket_order,
"material_request": args.material_request,
"material_request_item": args.material_request_item,
}, },
) )

View File

@ -44,6 +44,7 @@
"discount_amount", "discount_amount",
"base_rate_with_margin", "base_rate_with_margin",
"sec_break2", "sec_break2",
"apply_tds",
"rate", "rate",
"amount", "amount",
"item_tax_template", "item_tax_template",
@ -889,6 +890,12 @@
{ {
"fieldname": "column_break_54", "fieldname": "column_break_54",
"fieldtype": "Column Break" "fieldtype": "Column Break"
},
{
"default": "1",
"fieldname": "apply_tds",
"fieldtype": "Check",
"label": "Apply TDS"
} }
], ],
"idx": 1, "idx": 1,

View File

@ -1352,12 +1352,12 @@ class AccountsController(TransactionBase):
party = self.customer if self.doctype == "Sales Order" else self.supplier party = self.customer if self.doctype == "Sales Order" else self.supplier
advance = ( advance = (
frappe.qb.from_(ple) frappe.qb.from_(ple)
.select(ple.account_currency, Abs(Sum(ple.amount)).as_("amount")) .select(ple.account_currency, Abs(Sum(ple.amount_in_account_currency)).as_("amount"))
.where( .where(
(ple.against_voucher_type == self.doctype) (ple.against_voucher_type == self.doctype)
& (ple.against_voucher_no == self.name) & (ple.against_voucher_no == self.name)
& (ple.party == party) & (ple.party == party)
& (ple.delinked == 0) & (ple.docstatus == 1)
& (ple.company == self.company) & (ple.company == self.company)
) )
.run(as_dict=True) .run(as_dict=True)

View File

@ -404,12 +404,17 @@ def make_return_doc(doctype: str, source_name: str, target_doc=None):
returned_qty_map = get_returned_qty_map_for_row( returned_qty_map = get_returned_qty_map_for_row(
source_parent.name, source_parent.supplier, source_doc.name, doctype source_parent.name, source_parent.supplier, source_doc.name, doctype
) )
target_doc.received_qty = -1 * flt(
source_doc.received_qty - (returned_qty_map.get("received_qty") or 0) if doctype == "Subcontracting Receipt":
) target_doc.received_qty = -1 * flt(source_doc.qty)
target_doc.rejected_qty = -1 * flt( else:
source_doc.rejected_qty - (returned_qty_map.get("rejected_qty") or 0) target_doc.received_qty = -1 * flt(
) source_doc.received_qty - (returned_qty_map.get("received_qty") or 0)
)
target_doc.rejected_qty = -1 * flt(
source_doc.rejected_qty - (returned_qty_map.get("rejected_qty") or 0)
)
target_doc.qty = -1 * flt(source_doc.qty - (returned_qty_map.get("qty") or 0)) target_doc.qty = -1 * flt(source_doc.qty - (returned_qty_map.get("qty") or 0))
if hasattr(target_doc, "stock_qty"): if hasattr(target_doc, "stock_qty"):

View File

@ -581,6 +581,7 @@ class SellingController(StockController):
"customer_address": "address_display", "customer_address": "address_display",
"shipping_address_name": "shipping_address", "shipping_address_name": "shipping_address",
"company_address": "company_address_display", "company_address": "company_address_display",
"dispatch_address_name": "dispatch_address",
} }
for address_field, address_display_field in address_dict.items(): for address_field, address_display_field in address_dict.items():

View File

@ -1345,7 +1345,7 @@ class QuickBooksMigrator(Document):
)[0]["name"] )[0]["name"]
def _publish(self, *args, **kwargs): def _publish(self, *args, **kwargs):
frappe.publish_realtime("quickbooks_progress_update", *args, **kwargs) frappe.publish_realtime("quickbooks_progress_update", *args, **kwargs, user=self.modified_by)
def _get_unique_account_name(self, quickbooks_name, number=0): def _get_unique_account_name(self, quickbooks_name, number=0):
if number: if number:

View File

@ -304,6 +304,7 @@ class TallyMigration(Document):
frappe.publish_realtime( frappe.publish_realtime(
"tally_migration_progress_update", "tally_migration_progress_update",
{"title": title, "message": message, "count": count, "total": total}, {"title": title, "message": message, "count": count, "total": total},
user=self.modified_by,
) )
def _import_master_data(self): def _import_master_data(self):

View File

@ -1,51 +0,0 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2021-09-11 05:09:53.773838",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"region",
"region_code",
"country",
"country_code"
],
"fields": [
{
"fieldname": "region",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Region"
},
{
"fieldname": "region_code",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Region Code"
},
{
"fieldname": "country",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Country"
},
{
"fieldname": "country_code",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Country Code"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-09-14 05:33:06.444710",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "TaxJar Nexus",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -1,9 +0,0 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class TaxJarNexus(Document):
pass

View File

@ -1,37 +0,0 @@
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('TaxJar Settings', {
is_sandbox: (frm) => {
frm.toggle_reqd("api_key", !frm.doc.is_sandbox);
frm.toggle_reqd("sandbox_api_key", frm.doc.is_sandbox);
},
on_load: (frm) => {
frm.set_query('shipping_account_head', function() {
return {
filters: {
'company': frm.doc.company
}
};
});
frm.set_query('tax_account_head', function() {
return {
filters: {
'company': frm.doc.company
}
};
});
},
refresh: (frm) => {
frm.add_custom_button(__('Update Nexus List'), function() {
frm.call({
doc: frm.doc,
method: 'update_nexus_list'
});
});
},
});

View File

@ -1,139 +0,0 @@
{
"actions": [],
"creation": "2017-06-15 08:21:24.624315",
"doctype": "DocType",
"document_type": "Setup",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"taxjar_calculate_tax",
"is_sandbox",
"taxjar_create_transactions",
"credentials",
"api_key",
"cb_keys",
"sandbox_api_key",
"configuration",
"company",
"column_break_10",
"tax_account_head",
"configuration_cb",
"shipping_account_head",
"section_break_12",
"nexus"
],
"fields": [
{
"fieldname": "credentials",
"fieldtype": "Section Break",
"label": "Credentials"
},
{
"fieldname": "api_key",
"fieldtype": "Password",
"in_list_view": 1,
"label": "Live API Key",
"reqd": 1
},
{
"fieldname": "configuration",
"fieldtype": "Section Break",
"label": "Configuration"
},
{
"fieldname": "tax_account_head",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Tax Account Head",
"options": "Account",
"reqd": 1
},
{
"fieldname": "shipping_account_head",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Shipping Account Head",
"options": "Account",
"reqd": 1
},
{
"default": "0",
"depends_on": "taxjar_calculate_tax",
"fieldname": "is_sandbox",
"fieldtype": "Check",
"label": "Sandbox Mode"
},
{
"fieldname": "sandbox_api_key",
"fieldtype": "Password",
"label": "Sandbox API Key"
},
{
"default": "0",
"depends_on": "taxjar_calculate_tax",
"fieldname": "taxjar_create_transactions",
"fieldtype": "Check",
"label": "Create TaxJar Transaction"
},
{
"default": "0",
"fieldname": "taxjar_calculate_tax",
"fieldtype": "Check",
"label": "Enable Tax Calculation"
},
{
"fieldname": "cb_keys",
"fieldtype": "Column Break"
},
{
"depends_on": "nexus",
"fieldname": "section_break_12",
"fieldtype": "Section Break",
"label": "Nexus List"
},
{
"fieldname": "nexus",
"fieldtype": "Table",
"label": "Nexus",
"options": "TaxJar Nexus",
"read_only": 1
},
{
"fieldname": "configuration_cb",
"fieldtype": "Column Break"
},
{
"fieldname": "company",
"fieldtype": "Link",
"label": "Company",
"options": "Company"
},
{
"fieldname": "column_break_10",
"fieldtype": "Column Break"
}
],
"issingle": 1,
"links": [],
"modified": "2021-11-30 12:17:24.647979",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "TaxJar Settings",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -1,146 +0,0 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import json
import os
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from frappe.model.document import Document
from frappe.permissions import add_permission, update_permission_property
from erpnext.erpnext_integrations.taxjar_integration import get_client
class TaxJarSettings(Document):
def on_update(self):
TAXJAR_CREATE_TRANSACTIONS = self.taxjar_create_transactions
TAXJAR_CALCULATE_TAX = self.taxjar_calculate_tax
TAXJAR_SANDBOX_MODE = self.is_sandbox
fields_already_exist = frappe.db.exists(
"Custom Field",
{"dt": ("in", ["Item", "Sales Invoice Item"]), "fieldname": "product_tax_category"},
)
fields_hidden = frappe.get_value(
"Custom Field", {"dt": ("in", ["Sales Invoice Item"])}, "hidden"
)
if TAXJAR_CREATE_TRANSACTIONS or TAXJAR_CALCULATE_TAX or TAXJAR_SANDBOX_MODE:
if not fields_already_exist:
add_product_tax_categories()
make_custom_fields()
add_permissions()
frappe.enqueue("erpnext.regional.united_states.setup.add_product_tax_categories", now=False)
elif fields_already_exist and fields_hidden:
toggle_tax_category_fields(hidden="0")
elif fields_already_exist:
toggle_tax_category_fields(hidden="1")
def validate(self):
self.calculate_taxes_validation_for_create_transactions()
@frappe.whitelist()
def update_nexus_list(self):
client = get_client()
nexus = client.nexus_regions()
new_nexus_list = [frappe._dict(address) for address in nexus]
self.set("nexus", [])
self.set("nexus", new_nexus_list)
self.save()
def calculate_taxes_validation_for_create_transactions(self):
if not self.taxjar_calculate_tax and (self.taxjar_create_transactions or self.is_sandbox):
frappe.throw(
frappe._(
"Before enabling <b>Create Transaction</b> or <b>Sandbox Mode</b>, you need to check the <b>Enable Tax Calculation</b> box"
)
)
def toggle_tax_category_fields(hidden):
frappe.set_value(
"Custom Field",
{"dt": "Sales Invoice Item", "fieldname": "product_tax_category"},
"hidden",
hidden,
)
frappe.set_value(
"Custom Field", {"dt": "Item", "fieldname": "product_tax_category"}, "hidden", hidden
)
def add_product_tax_categories():
with open(os.path.join(os.path.dirname(__file__), "product_tax_category_data.json"), "r") as f:
tax_categories = json.loads(f.read())
create_tax_categories(tax_categories["categories"])
def create_tax_categories(data):
for d in data:
if not frappe.db.exists("Product Tax Category", {"product_tax_code": d.get("product_tax_code")}):
tax_category = frappe.new_doc("Product Tax Category")
tax_category.description = d.get("description")
tax_category.product_tax_code = d.get("product_tax_code")
tax_category.category_name = d.get("name")
tax_category.db_insert()
def make_custom_fields(update=True):
custom_fields = {
"Sales Invoice Item": [
dict(
fieldname="product_tax_category",
fieldtype="Link",
insert_after="description",
options="Product Tax Category",
label="Product Tax Category",
fetch_from="item_code.product_tax_category",
),
dict(
fieldname="tax_collectable",
fieldtype="Currency",
insert_after="net_amount",
label="Tax Collectable",
read_only=1,
options="currency",
),
dict(
fieldname="taxable_amount",
fieldtype="Currency",
insert_after="tax_collectable",
label="Taxable Amount",
read_only=1,
options="currency",
),
],
"Item": [
dict(
fieldname="product_tax_category",
fieldtype="Link",
insert_after="item_group",
options="Product Tax Category",
label="Product Tax Category",
)
],
}
create_custom_fields(custom_fields, update=update)
def add_permissions():
doctype = "Product Tax Category"
for role in (
"Accounts Manager",
"Accounts User",
"System Manager",
"Item Manager",
"Stock Manager",
):
add_permission(doctype, role, 0)
update_permission_property(doctype, role, 0, "write", 1)
update_permission_property(doctype, role, 0, "create", 1)

View File

@ -1,9 +0,0 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
# import frappe
import unittest
class TestTaxJarSettings(unittest.TestCase):
pass

View File

@ -1,419 +0,0 @@
import traceback
import frappe
import taxjar
from frappe import _
from frappe.contacts.doctype.address.address import get_company_address
from frappe.utils import cint, flt
from erpnext import get_default_company, get_region
SUPPORTED_COUNTRY_CODES = [
"AT",
"AU",
"BE",
"BG",
"CA",
"CY",
"CZ",
"DE",
"DK",
"EE",
"ES",
"FI",
"FR",
"GB",
"GR",
"HR",
"HU",
"IE",
"IT",
"LT",
"LU",
"LV",
"MT",
"NL",
"PL",
"PT",
"RO",
"SE",
"SI",
"SK",
"US",
]
SUPPORTED_STATE_CODES = [
"AL",
"AK",
"AZ",
"AR",
"CA",
"CO",
"CT",
"DE",
"DC",
"FL",
"GA",
"HI",
"ID",
"IL",
"IN",
"IA",
"KS",
"KY",
"LA",
"ME",
"MD",
"MA",
"MI",
"MN",
"MS",
"MO",
"MT",
"NE",
"NV",
"NH",
"NJ",
"NM",
"NY",
"NC",
"ND",
"OH",
"OK",
"OR",
"PA",
"RI",
"SC",
"SD",
"TN",
"TX",
"UT",
"VT",
"VA",
"WA",
"WV",
"WI",
"WY",
]
def get_client():
taxjar_settings = frappe.get_single("TaxJar Settings")
if not taxjar_settings.is_sandbox:
api_key = taxjar_settings.api_key and taxjar_settings.get_password("api_key")
api_url = taxjar.DEFAULT_API_URL
else:
api_key = taxjar_settings.sandbox_api_key and taxjar_settings.get_password("sandbox_api_key")
api_url = taxjar.SANDBOX_API_URL
if api_key and api_url:
client = taxjar.Client(api_key=api_key, api_url=api_url)
client.set_api_config("headers", {"x-api-version": "2022-01-24"})
return client
def create_transaction(doc, method):
TAXJAR_CREATE_TRANSACTIONS = frappe.db.get_single_value(
"TaxJar Settings", "taxjar_create_transactions"
)
"""Create an order transaction in TaxJar"""
if not TAXJAR_CREATE_TRANSACTIONS:
return
client = get_client()
if not client:
return
TAX_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "tax_account_head")
sales_tax = sum([tax.tax_amount for tax in doc.taxes if tax.account_head == TAX_ACCOUNT_HEAD])
if not sales_tax:
return
tax_dict = get_tax_data(doc)
if not tax_dict:
return
tax_dict["transaction_id"] = doc.name
tax_dict["transaction_date"] = frappe.utils.today()
tax_dict["sales_tax"] = sales_tax
tax_dict["amount"] = doc.total + tax_dict["shipping"]
try:
if doc.is_return:
client.create_refund(tax_dict)
else:
client.create_order(tax_dict)
except taxjar.exceptions.TaxJarResponseError as err:
frappe.throw(_(sanitize_error_response(err)))
except Exception as ex:
print(traceback.format_exc(ex))
def delete_transaction(doc, method):
"""Delete an existing TaxJar order transaction"""
TAXJAR_CREATE_TRANSACTIONS = frappe.db.get_single_value(
"TaxJar Settings", "taxjar_create_transactions"
)
if not TAXJAR_CREATE_TRANSACTIONS:
return
client = get_client()
if not client:
return
client.delete_order(doc.name)
def get_tax_data(doc):
SHIP_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "shipping_account_head")
from_address = get_company_address_details(doc)
from_shipping_state = from_address.get("state")
from_country_code = frappe.db.get_value("Country", from_address.country, "code")
from_country_code = from_country_code.upper()
to_address = get_shipping_address_details(doc)
to_shipping_state = to_address.get("state")
to_country_code = frappe.db.get_value("Country", to_address.country, "code")
to_country_code = to_country_code.upper()
shipping = sum([tax.tax_amount for tax in doc.taxes if tax.account_head == SHIP_ACCOUNT_HEAD])
line_items = [get_line_item_dict(item, doc.docstatus) for item in doc.items]
if from_shipping_state not in SUPPORTED_STATE_CODES:
from_shipping_state = get_state_code(from_address, "Company")
if to_shipping_state not in SUPPORTED_STATE_CODES:
to_shipping_state = get_state_code(to_address, "Shipping")
tax_dict = {
"from_country": from_country_code,
"from_zip": from_address.pincode,
"from_state": from_shipping_state,
"from_city": from_address.city,
"from_street": from_address.address_line1,
"to_country": to_country_code,
"to_zip": to_address.pincode,
"to_city": to_address.city,
"to_street": to_address.address_line1,
"to_state": to_shipping_state,
"shipping": shipping,
"amount": doc.net_total,
"plugin": "erpnext",
"line_items": line_items,
}
return tax_dict
def get_state_code(address, location):
if address is not None:
state_code = get_iso_3166_2_state_code(address)
if state_code not in SUPPORTED_STATE_CODES:
frappe.throw(_("Please enter a valid State in the {0} Address").format(location))
else:
frappe.throw(_("Please enter a valid State in the {0} Address").format(location))
return state_code
def get_line_item_dict(item, docstatus):
tax_dict = dict(
id=item.get("idx"),
quantity=item.get("qty"),
unit_price=item.get("rate"),
product_tax_code=item.get("product_tax_category"),
)
if docstatus == 1:
tax_dict.update({"sales_tax": item.get("tax_collectable")})
return tax_dict
def set_sales_tax(doc, method):
TAX_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "tax_account_head")
TAXJAR_CALCULATE_TAX = frappe.db.get_single_value("TaxJar Settings", "taxjar_calculate_tax")
if not TAXJAR_CALCULATE_TAX:
return
if get_region(doc.company) != "United States":
return
if not doc.items:
return
if check_sales_tax_exemption(doc):
return
tax_dict = get_tax_data(doc)
if not tax_dict:
# Remove existing tax rows if address is changed from a taxable state/country
setattr(doc, "taxes", [tax for tax in doc.taxes if tax.account_head != TAX_ACCOUNT_HEAD])
return
# check if delivering within a nexus
check_for_nexus(doc, tax_dict)
tax_data = validate_tax_request(tax_dict)
if tax_data is not None:
if not tax_data.amount_to_collect:
setattr(doc, "taxes", [tax for tax in doc.taxes if tax.account_head != TAX_ACCOUNT_HEAD])
elif tax_data.amount_to_collect > 0:
# Loop through tax rows for existing Sales Tax entry
# If none are found, add a row with the tax amount
for tax in doc.taxes:
if tax.account_head == TAX_ACCOUNT_HEAD:
tax.tax_amount = tax_data.amount_to_collect
doc.run_method("calculate_taxes_and_totals")
break
else:
doc.append(
"taxes",
{
"charge_type": "Actual",
"description": "Sales Tax",
"account_head": TAX_ACCOUNT_HEAD,
"tax_amount": tax_data.amount_to_collect,
},
)
# Assigning values to tax_collectable and taxable_amount fields in sales item table
for item in tax_data.breakdown.line_items:
doc.get("items")[cint(item.id) - 1].tax_collectable = item.tax_collectable
doc.get("items")[cint(item.id) - 1].taxable_amount = item.taxable_amount
doc.run_method("calculate_taxes_and_totals")
def check_for_nexus(doc, tax_dict):
TAX_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "tax_account_head")
if not frappe.db.get_value("TaxJar Nexus", {"region_code": tax_dict["to_state"]}):
for item in doc.get("items"):
item.tax_collectable = flt(0)
item.taxable_amount = flt(0)
for tax in doc.taxes:
if tax.account_head == TAX_ACCOUNT_HEAD:
doc.taxes.remove(tax)
return
def check_sales_tax_exemption(doc):
# if the party is exempt from sales tax, then set all tax account heads to zero
TAX_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "tax_account_head")
sales_tax_exempted = (
hasattr(doc, "exempt_from_sales_tax")
and doc.exempt_from_sales_tax
or frappe.db.has_column("Customer", "exempt_from_sales_tax")
and frappe.db.get_value("Customer", doc.customer, "exempt_from_sales_tax")
)
if sales_tax_exempted:
for tax in doc.taxes:
if tax.account_head == TAX_ACCOUNT_HEAD:
tax.tax_amount = 0
break
doc.run_method("calculate_taxes_and_totals")
return True
else:
return False
def validate_tax_request(tax_dict):
"""Return the sales tax that should be collected for a given order."""
client = get_client()
if not client:
return
try:
tax_data = client.tax_for_order(tax_dict)
except taxjar.exceptions.TaxJarResponseError as err:
frappe.throw(_(sanitize_error_response(err)))
else:
return tax_data
def get_company_address_details(doc):
"""Return default company address details"""
company_address = get_company_address(get_default_company()).company_address
if not company_address:
frappe.throw(_("Please set a default company address"))
company_address = frappe.get_doc("Address", company_address)
return company_address
def get_shipping_address_details(doc):
"""Return customer shipping address details"""
if doc.shipping_address_name:
shipping_address = frappe.get_doc("Address", doc.shipping_address_name)
elif doc.customer_address:
shipping_address = frappe.get_doc("Address", doc.customer_address)
else:
shipping_address = get_company_address_details(doc)
return shipping_address
def get_iso_3166_2_state_code(address):
import pycountry
country_code = frappe.db.get_value("Country", address.get("country"), "code")
error_message = _(
"""{0} is not a valid state! Check for typos or enter the ISO code for your state."""
).format(address.get("state"))
state = address.get("state").upper().strip()
# The max length for ISO state codes is 3, excluding the country code
if len(state) <= 3:
# PyCountry returns state code as {country_code}-{state-code} (e.g. US-FL)
address_state = (country_code + "-" + state).upper()
states = pycountry.subdivisions.get(country_code=country_code.upper())
states = [pystate.code for pystate in states]
if address_state in states:
return state
frappe.throw(_(error_message))
else:
try:
lookup_state = pycountry.subdivisions.lookup(state)
except LookupError:
frappe.throw(_(error_message))
else:
return lookup_state.code.split("-")[1]
def sanitize_error_response(response):
response = response.full_response.get("detail")
response = response.replace("_", " ")
sanitized_responses = {
"to zip": "Zipcode",
"to city": "City",
"to state": "State",
"to country": "Country",
}
for k, v in sanitized_responses.items():
response = response.replace(k, v)
return response

View File

@ -175,6 +175,7 @@ website_route_rules = [
}, },
}, },
{"from_route": "/project", "to_route": "Project"}, {"from_route": "/project", "to_route": "Project"},
{"from_route": "/tasks", "to_route": "Task"},
] ]
standard_portal_menu_items = [ standard_portal_menu_items = [
@ -312,11 +313,9 @@ doc_events = {
"erpnext.regional.create_transaction_log", "erpnext.regional.create_transaction_log",
"erpnext.regional.italy.utils.sales_invoice_on_submit", "erpnext.regional.italy.utils.sales_invoice_on_submit",
"erpnext.regional.saudi_arabia.utils.create_qr_code", "erpnext.regional.saudi_arabia.utils.create_qr_code",
"erpnext.erpnext_integrations.taxjar_integration.create_transaction",
], ],
"on_cancel": [ "on_cancel": [
"erpnext.regional.italy.utils.sales_invoice_on_cancel", "erpnext.regional.italy.utils.sales_invoice_on_cancel",
"erpnext.erpnext_integrations.taxjar_integration.delete_transaction",
"erpnext.regional.saudi_arabia.utils.delete_qr_code_file", "erpnext.regional.saudi_arabia.utils.delete_qr_code_file",
], ],
"on_trash": "erpnext.regional.check_deletion_permission", "on_trash": "erpnext.regional.check_deletion_permission",
@ -349,9 +348,6 @@ doc_events = {
"Email Unsubscribe": { "Email Unsubscribe": {
"after_insert": "erpnext.crm.doctype.email_campaign.email_campaign.unsubscribe_recipient" "after_insert": "erpnext.crm.doctype.email_campaign.email_campaign.unsubscribe_recipient"
}, },
("Quotation", "Sales Order", "Sales Invoice"): {
"validate": ["erpnext.erpnext_integrations.taxjar_integration.set_sales_tax"]
},
"Company": {"on_trash": ["erpnext.regional.saudi_arabia.utils.delete_vat_settings_for_company"]}, "Company": {"on_trash": ["erpnext.regional.saudi_arabia.utils.delete_vat_settings_for_company"]},
"Integration Request": { "Integration Request": {
"validate": "erpnext.accounts.doctype.payment_request.payment_request.validate_payment" "validate": "erpnext.accounts.doctype.payment_request.payment_request.validate_payment"

View File

@ -191,7 +191,9 @@ def get_total_pledged_security_value(loan):
for security, qty in pledged_securities.items(): for security, qty in pledged_securities.items():
after_haircut_percentage = 100 - hair_cut_map.get(security) after_haircut_percentage = 100 - hair_cut_map.get(security)
security_value += (loan_security_price_map.get(security) * qty * after_haircut_percentage) / 100 security_value += (
loan_security_price_map.get(security, 0) * qty * after_haircut_percentage
) / 100
return security_value return security_value

View File

@ -33,6 +33,11 @@ frappe.ui.form.on('Job Card', {
return; return;
} }
let has_stock_entry = frm.doc.__onload &&
frm.doc.__onload.has_stock_entry ? true : false;
frm.toggle_enable("for_quantity", !has_stock_entry);
if (!frm.is_new() && has_items && frm.doc.docstatus < 2) { if (!frm.is_new() && has_items && frm.doc.docstatus < 2) {
let to_request = frm.doc.for_quantity > frm.doc.transferred_qty; let to_request = frm.doc.for_quantity > frm.doc.transferred_qty;
let excess_transfer_allowed = frm.doc.__onload.job_card_excess_transfer; let excess_transfer_allowed = frm.doc.__onload.job_card_excess_transfer;

View File

@ -57,6 +57,10 @@ class JobCard(Document):
) )
self.set_onload("job_card_excess_transfer", excess_transfer) self.set_onload("job_card_excess_transfer", excess_transfer)
self.set_onload("work_order_closed", self.is_work_order_closed()) self.set_onload("work_order_closed", self.is_work_order_closed())
self.set_onload("has_stock_entry", self.has_stock_entry())
def has_stock_entry(self):
return frappe.db.exists("Stock Entry", {"job_card": self.name, "docstatus": ["!=", 2]})
def before_validate(self): def before_validate(self):
self.set_wip_warehouse() self.set_wip_warehouse()

View File

@ -169,7 +169,6 @@ erpnext.patches.v13_0.delete_old_sales_reports
execute:frappe.delete_doc_if_exists("DocType", "Bank Reconciliation") execute:frappe.delete_doc_if_exists("DocType", "Bank Reconciliation")
execute:frappe.reload_doc("regional", "doctype", "e_invoice_settings") execute:frappe.reload_doc("regional", "doctype", "e_invoice_settings")
erpnext.patches.v13_0.loyalty_points_entry_for_pos_invoice #22-07-2020 erpnext.patches.v13_0.loyalty_points_entry_for_pos_invoice #22-07-2020
erpnext.patches.v12_0.add_taxjar_integration_field
erpnext.patches.v12_0.fix_percent_complete_for_projects erpnext.patches.v12_0.fix_percent_complete_for_projects
erpnext.patches.v13_0.delete_report_requested_items_to_order erpnext.patches.v13_0.delete_report_requested_items_to_order
erpnext.patches.v12_0.update_item_tax_template_company erpnext.patches.v12_0.update_item_tax_template_company
@ -228,7 +227,6 @@ erpnext.patches.v13_0.migrate_stripe_api
erpnext.patches.v13_0.reset_clearance_date_for_intracompany_payment_entries erpnext.patches.v13_0.reset_clearance_date_for_intracompany_payment_entries
execute:frappe.reload_doc("erpnext_integrations", "doctype", "TaxJar Settings") execute:frappe.reload_doc("erpnext_integrations", "doctype", "TaxJar Settings")
execute:frappe.reload_doc("erpnext_integrations", "doctype", "Product Tax Category") execute:frappe.reload_doc("erpnext_integrations", "doctype", "Product Tax Category")
erpnext.patches.v13_0.custom_fields_for_taxjar_integration #08-11-2021
erpnext.patches.v13_0.set_operation_time_based_on_operating_cost erpnext.patches.v13_0.set_operation_time_based_on_operating_cost
erpnext.patches.v13_0.create_gst_payment_entry_fields #27-11-2021 erpnext.patches.v13_0.create_gst_payment_entry_fields #27-11-2021
erpnext.patches.v13_0.fix_invoice_statuses erpnext.patches.v13_0.fix_invoice_statuses
@ -269,6 +267,7 @@ erpnext.patches.v13_0.show_india_localisation_deprecation_warning
erpnext.patches.v13_0.show_hr_payroll_deprecation_warning erpnext.patches.v13_0.show_hr_payroll_deprecation_warning
erpnext.patches.v13_0.reset_corrupt_defaults erpnext.patches.v13_0.reset_corrupt_defaults
erpnext.patches.v13_0.create_accounting_dimensions_for_asset_repair erpnext.patches.v13_0.create_accounting_dimensions_for_asset_repair
erpnext.patches.v15_0.delete_taxjar_doctypes
[post_model_sync] [post_model_sync]
execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings') execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings')
@ -317,5 +316,5 @@ erpnext.patches.v14_0.fix_subcontracting_receipt_gl_entries
erpnext.patches.v14_0.migrate_remarks_from_gl_to_payment_ledger erpnext.patches.v14_0.migrate_remarks_from_gl_to_payment_ledger
erpnext.patches.v13_0.update_schedule_type_in_loans erpnext.patches.v13_0.update_schedule_type_in_loans
erpnext.patches.v14_0.create_accounting_dimensions_for_asset_capitalization erpnext.patches.v14_0.create_accounting_dimensions_for_asset_capitalization
erpnext.patches.v14_0.update_tds_fields erpnext.patches.v14_0.update_partial_tds_fields
erpnext.patches.v14_0.create_incoterms_and_migrate_shipment erpnext.patches.v14_0.create_incoterms_and_migrate_shipment

View File

@ -1,11 +0,0 @@
import frappe
from erpnext.regional.united_states.setup import make_custom_fields
def execute():
company = frappe.get_all("Company", filters={"country": "United States"})
if not company:
return
make_custom_fields()

View File

@ -1,72 +0,0 @@
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from erpnext.erpnext_integrations.doctype.taxjar_settings.taxjar_settings import add_permissions
def execute():
company = frappe.get_all("Company", filters={"country": "United States"}, fields=["name"])
if not company:
return
TAXJAR_CREATE_TRANSACTIONS = frappe.db.get_single_value(
"TaxJar Settings", "taxjar_create_transactions"
)
TAXJAR_CALCULATE_TAX = frappe.db.get_single_value("TaxJar Settings", "taxjar_calculate_tax")
TAXJAR_SANDBOX_MODE = frappe.db.get_single_value("TaxJar Settings", "is_sandbox")
if not TAXJAR_CREATE_TRANSACTIONS and not TAXJAR_CALCULATE_TAX and not TAXJAR_SANDBOX_MODE:
return
custom_fields = {
"Sales Invoice Item": [
dict(
fieldname="product_tax_category",
fieldtype="Link",
insert_after="description",
options="Product Tax Category",
label="Product Tax Category",
fetch_from="item_code.product_tax_category",
),
dict(
fieldname="tax_collectable",
fieldtype="Currency",
insert_after="net_amount",
label="Tax Collectable",
read_only=1,
options="currency",
),
dict(
fieldname="taxable_amount",
fieldtype="Currency",
insert_after="tax_collectable",
label="Taxable Amount",
read_only=1,
options="currency",
),
],
"Item": [
dict(
fieldname="product_tax_category",
fieldtype="Link",
insert_after="item_group",
options="Product Tax Category",
label="Product Tax Category",
)
],
"TaxJar Settings": [
dict(
fieldname="company",
fieldtype="Link",
insert_after="configuration",
options="Company",
label="Company",
)
],
}
create_custom_fields(custom_fields, update=True)
add_permissions()
frappe.enqueue(
"erpnext.erpnext_integrations.doctype.taxjar_settings.taxjar_settings.add_product_tax_categories",
now=True,
)

View File

@ -25,5 +25,21 @@ def execute():
).where( ).where(
purchase_invoice.docstatus == 1 purchase_invoice.docstatus == 1
).run() ).run()
purchase_order = frappe.qb.DocType("Purchase Order")
frappe.qb.update(purchase_order).set(
purchase_order.tax_withholding_net_total, purchase_order.net_total
).set(
purchase_order.base_tax_withholding_net_total, purchase_order.base_net_total
).where(
purchase_order.company == company.name
).where(
purchase_order.apply_tds == 1
).where(
purchase_order.transaction_date >= fiscal_year_details.year_start_date
).where(
purchase_order.docstatus == 1
).run()
except FiscalYearError: except FiscalYearError:
pass pass

View File

@ -0,0 +1,17 @@
import click
import frappe
def execute():
if "taxjar_integration" in frappe.get_installed_apps():
return
doctypes = ["TaxJar Settings", "TaxJar Nexus", "Product Tax Category"]
for doctype in doctypes:
frappe.delete_doc("DocType", doctype, ignore_missing=True)
click.secho(
"Taxjar Integration is moved to a separate app"
"Please install the app to continue using the module: https://github.com/frappe/taxjar_integration",
fg="yellow",
)

View File

@ -48,21 +48,23 @@ erpnext.timesheet.control_timer = function(frm, dialog, row, timestamp=0) {
var $btn_complete = dialog.$wrapper.find(".playpause .btn-complete"); var $btn_complete = dialog.$wrapper.find(".playpause .btn-complete");
var interval = null; var interval = null;
var currentIncrement = timestamp; var currentIncrement = timestamp;
var initialised = row ? true : false; var initialized = row ? true : false;
var clicked = false; var clicked = false;
var flag = true; // Alert only once var flag = true; // Alert only once
// If row with not completed status, initialize timer with the time elapsed on click of 'Start Timer'. // If row with not completed status, initialize timer with the time elapsed on click of 'Start Timer'.
if (row) { if (row) {
initialised = true; initialized = true;
$btn_start.hide(); $btn_start.hide();
$btn_complete.show(); $btn_complete.show();
initialiseTimer(); initializeTimer();
} }
if (!initialised) {
if (!initialized) {
$btn_complete.hide(); $btn_complete.hide();
} }
$btn_start.click(function(e) { $btn_start.click(function(e) {
if (!initialised) { if (!initialized) {
// New activity if no activities found // New activity if no activities found
var args = dialog.get_values(); var args = dialog.get_values();
if(!args) return; if(!args) return;
@ -90,11 +92,11 @@ erpnext.timesheet.control_timer = function(frm, dialog, row, timestamp=0) {
return false; return false;
} }
if (!initialised) { if (!initialized) {
initialised = true; initialized = true;
$btn_start.hide(); $btn_start.hide();
$btn_complete.show(); $btn_complete.show();
initialiseTimer(); initializeTimer();
} }
}); });
@ -110,11 +112,13 @@ erpnext.timesheet.control_timer = function(frm, dialog, row, timestamp=0) {
grid_row.doc.hours = currentIncrement / 3600; grid_row.doc.hours = currentIncrement / 3600;
grid_row.doc.to_time = frappe.datetime.now_datetime(); grid_row.doc.to_time = frappe.datetime.now_datetime();
grid_row.refresh(); grid_row.refresh();
frm.dirty();
frm.save(); frm.save();
reset(); reset();
dialog.hide(); dialog.hide();
}); });
function initialiseTimer() {
function initializeTimer() {
interval = setInterval(function() { interval = setInterval(function() {
var current = setCurrentIncrement(); var current = setCurrentIncrement();
updateStopwatch(current); updateStopwatch(current);
@ -151,7 +155,7 @@ erpnext.timesheet.control_timer = function(frm, dialog, row, timestamp=0) {
function reset() { function reset() {
currentIncrement = 0; currentIncrement = 0;
initialised = false; initialized = false;
clearInterval(interval); clearInterval(interval);
$(".hours").text("00"); $(".hours").text("00");
$(".minutes").text("00"); $(".minutes").text("00");

View File

@ -146,7 +146,9 @@ class ImportSupplierInvoice(Document):
def publish(self, title, message, count, total): def publish(self, title, message, count, total):
frappe.publish_realtime( frappe.publish_realtime(
"import_invoice_update", {"title": title, "message": message, "count": count, "total": total} "import_invoice_update",
{"title": title, "message": message, "count": count, "total": total},
user=self.modified_by,
) )

View File

@ -1,8 +0,0 @@
// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Product Tax Category', {
// refresh: function(frm) {
// }
});

View File

@ -1,70 +0,0 @@
{
"actions": [],
"autoname": "field:product_tax_code",
"creation": "2021-08-23 12:33:37.910225",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"product_tax_code",
"column_break_2",
"category_name",
"section_break_4",
"description"
],
"fields": [
{
"fieldname": "product_tax_code",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Product Tax Code",
"reqd": 1,
"unique": 1
},
{
"fieldname": "description",
"fieldtype": "Small Text",
"label": "Description"
},
{
"fieldname": "category_name",
"fieldtype": "Data",
"label": "Category Name",
"length": 255
},
{
"fieldname": "column_break_2",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_4",
"fieldtype": "Section Break"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-08-24 09:10:25.313642",
"modified_by": "Administrator",
"module": "Regional",
"name": "Product Tax Category",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "category_name",
"track_changes": 1
}

View File

@ -1,9 +0,0 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class ProductTaxCategory(Document):
pass

View File

@ -1,9 +0,0 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
# import frappe
import unittest
class TestProductTaxCategory(unittest.TestCase):
pass

View File

@ -2,9 +2,6 @@
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
import frappe import frappe
import os
import json
from frappe.permissions import add_permission, update_permission_property
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields from frappe.custom.doctype.custom_field.custom_field import create_custom_fields

View File

@ -95,8 +95,10 @@
"item_tax_rate", "item_tax_rate",
"transaction_date", "transaction_date",
"inter_transfer_reference_section", "inter_transfer_reference_section",
"material_request",
"purchase_order", "purchase_order",
"column_break_89", "column_break_89",
"material_request_item",
"purchase_order_item" "purchase_order_item"
], ],
"fields": [ "fields": [
@ -847,12 +849,23 @@
"label": "quotation_item", "label": "quotation_item",
"no_copy": 1, "no_copy": 1,
"read_only": 1 "read_only": 1
},
{
"fieldname": "material_request",
"fieldtype": "Link",
"label": "Material Request",
"options": "Material Request"
},
{
"fieldname": "material_request_item",
"fieldtype": "Data",
"label": "Material Request Item"
} }
], ],
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2022-11-10 18:20:30.137455", "modified": "2022-11-18 11:39:01.741665",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Selling", "module": "Selling",
"name": "Sales Order Item", "name": "Sales Order Item",

View File

@ -902,6 +902,8 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
"serial_no": "serial_no", "serial_no": "serial_no",
"purchase_order": "purchase_order", "purchase_order": "purchase_order",
"purchase_order_item": "purchase_order_item", "purchase_order_item": "purchase_order_item",
"material_request": "material_request",
"Material_request_item": "material_request_item",
}, },
"field_no_map": ["warehouse"], "field_no_map": ["warehouse"],
}, },

View File

@ -11,11 +11,14 @@ def get_data():
}, },
"internal_links": { "internal_links": {
"Sales Order": ["items", "against_sales_order"], "Sales Order": ["items", "against_sales_order"],
"Material Request": ["items", "material_request"],
"Purchase Order": ["items", "purchase_order"],
}, },
"transactions": [ "transactions": [
{"label": _("Related"), "items": ["Sales Invoice", "Packing Slip", "Delivery Trip"]}, {"label": _("Related"), "items": ["Sales Invoice", "Packing Slip", "Delivery Trip"]},
{"label": _("Reference"), "items": ["Sales Order", "Shipment", "Quality Inspection"]}, {"label": _("Reference"), "items": ["Sales Order", "Shipment", "Quality Inspection"]},
{"label": _("Returns"), "items": ["Stock Entry"]}, {"label": _("Returns"), "items": ["Stock Entry"]},
{"label": _("Subscription"), "items": ["Auto Repeat"]}, {"label": _("Subscription"), "items": ["Auto Repeat"]},
{"label": _("Internal Transfer"), "items": ["Material Request", "Purchase Order"]},
], ],
} }

View File

@ -88,9 +88,11 @@
"allow_zero_valuation_rate", "allow_zero_valuation_rate",
"column_break_71", "column_break_71",
"internal_transfer_section", "internal_transfer_section",
"material_request",
"purchase_order", "purchase_order",
"column_break_82", "column_break_82",
"purchase_order_item", "purchase_order_item",
"material_request_item",
"accounting_dimensions_section", "accounting_dimensions_section",
"cost_center", "cost_center",
"dimension_col_break", "dimension_col_break",
@ -818,13 +820,24 @@
"fieldtype": "Check", "fieldtype": "Check",
"label": "Has Item Scanned", "label": "Has Item Scanned",
"read_only": 1 "read_only": 1
},
{
"fieldname": "material_request",
"fieldtype": "Link",
"label": "Material Request",
"options": "Material Request"
},
{
"fieldname": "material_request_item",
"fieldtype": "Data",
"label": "Material Request Item"
} }
], ],
"idx": 1, "idx": 1,
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2022-11-02 12:54:07.225623", "modified": "2022-11-09 12:17:50.850142",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Delivery Note Item", "name": "Delivery Note Item",

View File

@ -71,6 +71,8 @@ frappe.ui.form.on('Inventory Dimension', {
if (r.message && r.message.length) { if (r.message && r.message.length) {
frm.set_df_property("fetch_from_parent", "options", frm.set_df_property("fetch_from_parent", "options",
[""].concat(r.message)); [""].concat(r.message));
} else {
frm.set_df_property("fetch_from_parent", "hidden", 1);
} }
} }
}); });

View File

@ -11,20 +11,20 @@
"reference_document", "reference_document",
"column_break_4", "column_break_4",
"disabled", "disabled",
"section_break_7",
"field_mapping_section", "field_mapping_section",
"source_fieldname", "source_fieldname",
"column_break_9", "column_break_9",
"target_fieldname", "target_fieldname",
"applicable_for_documents_tab", "applicable_for_documents_tab",
"apply_to_all_doctypes", "apply_to_all_doctypes",
"column_break_13",
"document_type", "document_type",
"istable",
"type_of_transaction", "type_of_transaction",
"fetch_from_parent", "fetch_from_parent",
"column_break_16", "istable",
"condition",
"applicable_condition_example_section", "applicable_condition_example_section",
"condition",
"conditional_rule_examples_section",
"html_19" "html_19"
], ],
"fields": [ "fields": [
@ -52,13 +52,13 @@
{ {
"fieldname": "applicable_for_documents_tab", "fieldname": "applicable_for_documents_tab",
"fieldtype": "Tab Break", "fieldtype": "Tab Break",
"label": "Applicable For Documents" "label": "Applicable For"
}, },
{ {
"depends_on": "eval:!doc.apply_to_all_doctypes", "depends_on": "eval:!doc.apply_to_all_doctypes",
"fieldname": "document_type", "fieldname": "document_type",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Applicable to Document", "label": "Apply to Document",
"mandatory_depends_on": "eval:!doc.apply_to_all_doctypes", "mandatory_depends_on": "eval:!doc.apply_to_all_doctypes",
"options": "DocType" "options": "DocType"
}, },
@ -72,6 +72,7 @@
"fetch_from": "document_type.istable", "fetch_from": "document_type.istable",
"fieldname": "istable", "fieldname": "istable",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 1,
"label": " Is Child Table", "label": " Is Child Table",
"read_only": 1 "read_only": 1
}, },
@ -79,13 +80,13 @@
"depends_on": "eval:!doc.apply_to_all_doctypes", "depends_on": "eval:!doc.apply_to_all_doctypes",
"fieldname": "condition", "fieldname": "condition",
"fieldtype": "Code", "fieldtype": "Code",
"label": "Applicable Condition" "label": "Conditional Rule"
}, },
{ {
"default": "0", "default": "1",
"fieldname": "apply_to_all_doctypes", "fieldname": "apply_to_all_doctypes",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Apply to All Inventory Document Types" "label": "Apply to All Inventory Documents"
}, },
{ {
"default": "0", "default": "0",
@ -93,10 +94,6 @@
"fieldtype": "Check", "fieldtype": "Check",
"label": "Disabled" "label": "Disabled"
}, },
{
"fieldname": "section_break_7",
"fieldtype": "Section Break"
},
{ {
"fieldname": "target_fieldname", "fieldname": "target_fieldname",
"fieldtype": "Data", "fieldtype": "Data",
@ -115,13 +112,11 @@
"collapsible": 1, "collapsible": 1,
"fieldname": "field_mapping_section", "fieldname": "field_mapping_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 1,
"label": "Field Mapping" "label": "Field Mapping"
}, },
{ {
"fieldname": "column_break_16", "depends_on": "eval:!doc.apply_to_all_doctypes",
"fieldtype": "Column Break"
},
{
"fieldname": "type_of_transaction", "fieldname": "type_of_transaction",
"fieldtype": "Select", "fieldtype": "Select",
"label": "Type of Transaction", "label": "Type of Transaction",
@ -136,23 +131,33 @@
"collapsible": 1, "collapsible": 1,
"depends_on": "eval:!doc.apply_to_all_doctypes", "depends_on": "eval:!doc.apply_to_all_doctypes",
"fieldname": "applicable_condition_example_section", "fieldname": "applicable_condition_example_section",
"fieldtype": "Section Break", "fieldtype": "Column Break"
"label": "Applicable Condition Examples"
}, },
{ {
"fieldname": "column_break_4", "fieldname": "column_break_4",
"fieldtype": "Column Break" "fieldtype": "Column Break"
}, },
{ {
"description": "Set fieldname or DocType name like Supplier, Customer etc.", "depends_on": "eval:!doc.apply_to_all_doctypes",
"description": "Set fieldname from which you want to fetch the data from the parent form.",
"fieldname": "fetch_from_parent", "fieldname": "fetch_from_parent",
"fieldtype": "Select", "fieldtype": "Select",
"label": "Fetch Value From Parent Form" "label": "Fetch Value From"
},
{
"fieldname": "column_break_13",
"fieldtype": "Section Break"
},
{
"depends_on": "eval:!doc.apply_to_all_doctypes",
"fieldname": "conditional_rule_examples_section",
"fieldtype": "Section Break",
"label": "Conditional Rule Examples"
} }
], ],
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"links": [], "links": [],
"modified": "2022-09-02 13:29:04.098469", "modified": "2022-11-15 15:50:16.767105",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Inventory Dimension", "name": "Inventory Dimension",

View File

@ -33,10 +33,22 @@ class InventoryDimension(Document):
) )
def validate(self): def validate(self):
self.validate_reference_document()
def before_save(self):
self.do_not_update_document() self.do_not_update_document()
self.reset_value() self.reset_value()
self.validate_reference_document()
self.set_source_and_target_fieldname() self.set_source_and_target_fieldname()
self.set_type_of_transaction()
self.set_fetch_value_from()
def set_type_of_transaction(self):
if self.apply_to_all_doctypes:
self.type_of_transaction = "Both"
def set_fetch_value_from(self):
if self.apply_to_all_doctypes:
self.fetch_from_parent = self.reference_document
def do_not_update_document(self): def do_not_update_document(self):
if self.is_new() or not self.has_stock_ledger(): if self.is_new() or not self.has_stock_ledger():

View File

@ -140,14 +140,13 @@ class TestInventoryDimension(FrappeTestCase):
self.assertRaises(DoNotChangeError, inv_dim1.save) self.assertRaises(DoNotChangeError, inv_dim1.save)
def test_inventory_dimension_for_purchase_receipt_and_delivery_note(self): def test_inventory_dimension_for_purchase_receipt_and_delivery_note(self):
create_inventory_dimension( inv_dimension = create_inventory_dimension(
reference_document="Rack", reference_document="Rack", dimension_name="Rack", apply_to_all_doctypes=1
type_of_transaction="Both",
dimension_name="Rack",
apply_to_all_doctypes=1,
fetch_from_parent="Rack",
) )
self.assertEqual(inv_dimension.type_of_transaction, "Both")
self.assertEqual(inv_dimension.fetch_from_parent, "Rack")
create_custom_field( create_custom_field(
"Purchase Receipt", dict(fieldname="rack", label="Rack", fieldtype="Link", options="Rack") "Purchase Receipt", dict(fieldname="rack", label="Rack", fieldtype="Link", options="Rack")
) )

View File

@ -1,6 +1,7 @@
{ {
"actions": [], "actions": [],
"allow_import": 1, "allow_import": 1,
"autoname": "hash",
"creation": "2013-05-02 16:29:48", "creation": "2013-05-02 16:29:48",
"description": "Multiple Item prices.", "description": "Multiple Item prices.",
"doctype": "DocType", "doctype": "DocType",
@ -77,9 +78,10 @@
{ {
"fetch_from": "item_code.brand", "fetch_from": "item_code.brand",
"fieldname": "brand", "fieldname": "brand",
"fieldtype": "Read Only", "fieldtype": "Link",
"in_list_view": 1, "in_list_view": 1,
"label": "Brand", "label": "Brand",
"options": "Brand",
"read_only": 1 "read_only": 1
}, },
{ {
@ -218,11 +220,11 @@
"idx": 1, "idx": 1,
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"links": [], "links": [],
"modified": "2022-09-02 16:33:55.612992", "modified": "2022-11-15 08:26:04.041861",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Item Price", "name": "Item Price",
"name_case": "Title Case", "naming_rule": "Random",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {

View File

@ -370,9 +370,6 @@ frappe.ui.form.on("Material Request Item", {
if (flt(d.qty) < flt(d.min_order_qty)) { if (flt(d.qty) < flt(d.min_order_qty)) {
frappe.msgprint(__("Warning: Material Requested Qty is less than Minimum Order Qty")); frappe.msgprint(__("Warning: Material Requested Qty is less than Minimum Order Qty"));
} }
const item = locals[doctype][name];
frm.events.get_item_data(frm, item, false);
}, },
from_warehouse: function(frm, doctype, name) { from_warehouse: function(frm, doctype, name) {

View File

@ -14,5 +14,6 @@ def get_data():
}, },
{"label": _("Stock"), "items": ["Stock Entry", "Purchase Receipt", "Pick List"]}, {"label": _("Stock"), "items": ["Stock Entry", "Purchase Receipt", "Pick List"]},
{"label": _("Manufacturing"), "items": ["Work Order"]}, {"label": _("Manufacturing"), "items": ["Work Order"]},
{"label": _("Internal Transfer"), "items": ["Sales Order"]},
], ],
} }

View File

@ -58,6 +58,12 @@ def execute(filters=None):
if sle.serial_no: if sle.serial_no:
update_available_serial_nos(available_serial_nos, sle) update_available_serial_nos(available_serial_nos, sle)
if sle.actual_qty:
sle["in_out_rate"] = flt(sle.stock_value_difference / sle.actual_qty, precision)
elif sle.voucher_type == "Stock Reconciliation":
sle["in_out_rate"] = sle.valuation_rate
data.append(sle) data.append(sle)
if include_uom: if include_uom:
@ -185,10 +191,18 @@ def get_columns(filters):
"convertible": "rate", "convertible": "rate",
}, },
{ {
"label": _("Valuation Rate"), "label": _("Avg Rate (Balance Stock)"),
"fieldname": "valuation_rate", "fieldname": "valuation_rate",
"fieldtype": "Currency", "fieldtype": "Currency",
"width": 110, "width": 180,
"options": "Company:company:default_currency",
"convertible": "rate",
},
{
"label": _("Valuation Rate"),
"fieldname": "in_out_rate",
"fieldtype": "Currency",
"width": 140,
"options": "Company:company:default_currency", "options": "Company:company:default_currency",
"convertible": "rate", "convertible": "rate",
}, },
@ -394,7 +408,7 @@ def get_opening_balance(filters, columns, sl_entries):
) )
# check if any SLEs are actually Opening Stock Reconciliation # check if any SLEs are actually Opening Stock Reconciliation
for sle in sl_entries: for sle in list(sl_entries):
if ( if (
sle.get("voucher_type") == "Stock Reconciliation" sle.get("voucher_type") == "Stock Reconciliation"
and sle.posting_date == filters.from_date and sle.posting_date == filters.from_date

View File

@ -1,488 +1,490 @@
{ {
"actions": [], "actions": [],
"autoname": "hash", "autoname": "hash",
"creation": "2022-04-13 16:05:55.395695", "creation": "2022-04-13 16:05:55.395695",
"doctype": "DocType", "doctype": "DocType",
"document_type": "Document", "document_type": "Document",
"editable_grid": 1, "editable_grid": 1,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [ "field_order": [
"item_code", "item_code",
"column_break_2", "column_break_2",
"item_name", "item_name",
"section_break_4", "section_break_4",
"description", "description",
"brand", "brand",
"image_column", "image_column",
"image", "image",
"image_view", "image_view",
"received_and_accepted", "received_and_accepted",
"received_qty", "received_qty",
"qty", "qty",
"rejected_qty", "rejected_qty",
"returned_qty", "returned_qty",
"col_break2", "col_break2",
"stock_uom", "stock_uom",
"conversion_factor", "conversion_factor",
"tracking_section", "tracking_section",
"col_break_tracking_section", "col_break_tracking_section",
"rate_and_amount", "rate_and_amount",
"rate", "rate",
"amount", "amount",
"recalculate_rate", "recalculate_rate",
"column_break_19", "column_break_19",
"rm_cost_per_qty", "rm_cost_per_qty",
"service_cost_per_qty", "service_cost_per_qty",
"additional_cost_per_qty", "additional_cost_per_qty",
"rm_supp_cost", "rm_supp_cost",
"warehouse_and_reference", "warehouse_and_reference",
"warehouse", "warehouse",
"rejected_warehouse", "rejected_warehouse",
"subcontracting_order", "subcontracting_order",
"column_break_40", "column_break_40",
"schedule_date", "schedule_date",
"quality_inspection", "quality_inspection",
"subcontracting_order_item", "subcontracting_order_item",
"subcontracting_receipt_item", "subcontracting_receipt_item",
"section_break_45", "section_break_45",
"bom", "bom",
"serial_no", "serial_no",
"col_break5", "col_break5",
"batch_no", "batch_no",
"rejected_serial_no", "rejected_serial_no",
"manufacture_details", "manufacture_details",
"manufacturer", "manufacturer",
"column_break_16", "column_break_16",
"manufacturer_part_no", "manufacturer_part_no",
"accounting_details_section", "accounting_details_section",
"expense_account", "expense_account",
"accounting_dimensions_section", "accounting_dimensions_section",
"cost_center", "cost_center",
"dimension_col_break", "dimension_col_break",
"project", "project",
"section_break_80", "section_break_80",
"page_break" "page_break"
], ],
"fields": [ "fields": [
{ {
"bold": 1, "bold": 1,
"columns": 3, "columns": 3,
"fieldname": "item_code", "fieldname": "item_code",
"fieldtype": "Link", "fieldtype": "Link",
"in_global_search": 1, "in_global_search": 1,
"in_list_view": 1, "in_list_view": 1,
"label": "Item Code", "label": "Item Code",
"options": "Item", "options": "Item",
"print_width": "100px", "print_width": "100px",
"reqd": 1, "reqd": 1,
"search_index": 1, "search_index": 1,
"width": "100px" "width": "100px"
}, },
{ {
"fieldname": "column_break_2", "fieldname": "column_break_2",
"fieldtype": "Column Break" "fieldtype": "Column Break"
}, },
{ {
"fieldname": "item_name", "fieldname": "item_name",
"fieldtype": "Data", "fieldtype": "Data",
"in_global_search": 1, "in_global_search": 1,
"label": "Item Name", "label": "Item Name",
"print_hide": 1, "print_hide": 1,
"reqd": 1 "reqd": 1
}, },
{ {
"collapsible": 1, "collapsible": 1,
"fieldname": "section_break_4", "fieldname": "section_break_4",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Description" "label": "Description"
}, },
{ {
"fieldname": "description", "fieldname": "description",
"fieldtype": "Text Editor", "fieldtype": "Text Editor",
"label": "Description", "label": "Description",
"print_width": "300px", "print_width": "300px",
"reqd": 1, "reqd": 1,
"width": "300px" "width": "300px"
}, },
{ {
"fieldname": "image", "fieldname": "image",
"fieldtype": "Attach", "fieldtype": "Attach",
"hidden": 1, "hidden": 1,
"label": "Image" "label": "Image"
}, },
{ {
"fieldname": "image_view", "fieldname": "image_view",
"fieldtype": "Image", "fieldtype": "Image",
"label": "Image View", "label": "Image View",
"options": "image", "options": "image",
"print_hide": 1 "print_hide": 1
}, },
{ {
"fieldname": "received_and_accepted", "fieldname": "received_and_accepted",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Received and Accepted" "label": "Received and Accepted"
}, },
{ {
"bold": 1, "bold": 1,
"default": "0", "default": "0",
"fieldname": "received_qty", "fieldname": "received_qty",
"fieldtype": "Float", "fieldtype": "Float",
"label": "Received Quantity", "label": "Received Quantity",
"no_copy": 1, "no_copy": 1,
"print_hide": 1, "print_hide": 1,
"print_width": "100px", "print_width": "100px",
"read_only": 1, "read_only": 1,
"reqd": 1, "reqd": 1,
"width": "100px" "width": "100px"
}, },
{ {
"columns": 2, "columns": 2,
"fieldname": "qty", "fieldname": "qty",
"fieldtype": "Float", "fieldtype": "Float",
"in_list_view": 1, "in_list_view": 1,
"label": "Accepted Quantity", "label": "Accepted Quantity",
"no_copy": 1, "no_copy": 1,
"print_width": "100px", "print_width": "100px",
"width": "100px" "width": "100px"
}, },
{ {
"columns": 1, "columns": 1,
"fieldname": "rejected_qty", "depends_on": "eval: !parent.is_return",
"fieldtype": "Float", "fieldname": "rejected_qty",
"in_list_view": 1, "fieldtype": "Float",
"label": "Rejected Quantity", "in_list_view": 1,
"no_copy": 1, "label": "Rejected Quantity",
"print_hide": 1, "no_copy": 1,
"print_width": "100px", "print_hide": 1,
"width": "100px" "print_width": "100px",
}, "width": "100px"
{ },
"fieldname": "col_break2", {
"fieldtype": "Column Break", "fieldname": "col_break2",
"print_hide": 1 "fieldtype": "Column Break",
}, "print_hide": 1
{ },
"fieldname": "stock_uom", {
"fieldtype": "Link", "fieldname": "stock_uom",
"label": "Stock UOM", "fieldtype": "Link",
"options": "UOM", "label": "Stock UOM",
"print_hide": 1, "options": "UOM",
"print_width": "100px", "print_hide": 1,
"read_only": 1, "print_width": "100px",
"reqd": 1, "read_only": 1,
"width": "100px" "reqd": 1,
}, "width": "100px"
{ },
"default": "1", {
"fieldname": "conversion_factor", "default": "1",
"fieldtype": "Float", "fieldname": "conversion_factor",
"hidden": 1, "fieldtype": "Float",
"label": "Conversion Factor", "hidden": 1,
"read_only": 1 "label": "Conversion Factor",
}, "read_only": 1
{ },
"fieldname": "rate_and_amount", {
"fieldtype": "Section Break", "fieldname": "rate_and_amount",
"label": "Rate and Amount" "fieldtype": "Section Break",
}, "label": "Rate and Amount"
{ },
"bold": 1, {
"columns": 2, "bold": 1,
"fieldname": "rate", "columns": 2,
"fieldtype": "Currency", "fieldname": "rate",
"in_list_view": 1, "fieldtype": "Currency",
"label": "Rate", "in_list_view": 1,
"options": "currency", "label": "Rate",
"print_width": "100px", "options": "currency",
"read_only": 1, "print_width": "100px",
"read_only_depends_on": "eval: doc.recalculate_rate", "read_only": 1,
"width": "100px" "read_only_depends_on": "eval: doc.recalculate_rate",
}, "width": "100px"
{ },
"fieldname": "amount", {
"fieldtype": "Currency", "fieldname": "amount",
"in_list_view": 1, "fieldtype": "Currency",
"label": "Amount", "in_list_view": 1,
"options": "currency", "label": "Amount",
"read_only": 1 "options": "currency",
}, "read_only": 1
{ },
"fieldname": "column_break_19", {
"fieldtype": "Column Break" "fieldname": "column_break_19",
}, "fieldtype": "Column Break"
{ },
"fieldname": "rm_cost_per_qty", {
"fieldtype": "Currency", "fieldname": "rm_cost_per_qty",
"label": "Raw Material Cost Per Qty", "fieldtype": "Currency",
"no_copy": 1, "label": "Raw Material Cost Per Qty",
"read_only": 1 "no_copy": 1,
}, "read_only": 1
{ },
"fieldname": "service_cost_per_qty", {
"fieldtype": "Currency", "fieldname": "service_cost_per_qty",
"label": "Service Cost Per Qty", "fieldtype": "Currency",
"read_only": 1, "label": "Service Cost Per Qty",
"reqd": 1 "read_only": 1,
}, "reqd": 1
{ },
"default": "0", {
"fieldname": "additional_cost_per_qty", "default": "0",
"fieldtype": "Currency", "fieldname": "additional_cost_per_qty",
"label": "Additional Cost Per Qty", "fieldtype": "Currency",
"read_only": 1 "label": "Additional Cost Per Qty",
}, "read_only": 1
{ },
"fieldname": "warehouse_and_reference", {
"fieldtype": "Section Break", "fieldname": "warehouse_and_reference",
"label": "Warehouse and Reference" "fieldtype": "Section Break",
}, "label": "Warehouse and Reference"
{ },
"bold": 1, {
"fieldname": "warehouse", "bold": 1,
"fieldtype": "Link", "fieldname": "warehouse",
"in_list_view": 1, "fieldtype": "Link",
"label": "Accepted Warehouse", "in_list_view": 1,
"options": "Warehouse", "label": "Accepted Warehouse",
"print_hide": 1, "options": "Warehouse",
"print_width": "100px", "print_hide": 1,
"width": "100px" "print_width": "100px",
}, "width": "100px"
{ },
"fieldname": "rejected_warehouse", {
"fieldtype": "Link", "depends_on": "eval: !parent.is_return",
"label": "Rejected Warehouse", "fieldname": "rejected_warehouse",
"no_copy": 1, "fieldtype": "Link",
"options": "Warehouse", "label": "Rejected Warehouse",
"print_hide": 1, "no_copy": 1,
"print_width": "100px", "options": "Warehouse",
"width": "100px" "print_hide": 1,
}, "print_width": "100px",
{ "width": "100px"
"depends_on": "eval:!doc.__islocal", },
"fieldname": "quality_inspection", {
"fieldtype": "Link", "depends_on": "eval:!doc.__islocal",
"label": "Quality Inspection", "fieldname": "quality_inspection",
"no_copy": 1, "fieldtype": "Link",
"options": "Quality Inspection", "label": "Quality Inspection",
"print_hide": 1 "no_copy": 1,
}, "options": "Quality Inspection",
{ "print_hide": 1
"fieldname": "column_break_40", },
"fieldtype": "Column Break" {
}, "fieldname": "column_break_40",
{ "fieldtype": "Column Break"
"fieldname": "subcontracting_order", },
"fieldtype": "Link", {
"label": "Subcontracting Order", "fieldname": "subcontracting_order",
"no_copy": 1, "fieldtype": "Link",
"options": "Subcontracting Order", "label": "Subcontracting Order",
"print_width": "150px", "no_copy": 1,
"read_only": 1, "options": "Subcontracting Order",
"search_index": 1, "print_width": "150px",
"width": "150px" "read_only": 1,
}, "search_index": 1,
{ "width": "150px"
"fieldname": "schedule_date", },
"fieldtype": "Date", {
"label": "Required By", "fieldname": "schedule_date",
"print_hide": 1, "fieldtype": "Date",
"read_only": 1 "label": "Required By",
}, "print_hide": 1,
{ "read_only": 1
"fieldname": "section_break_45", },
"fieldtype": "Section Break" {
}, "fieldname": "section_break_45",
{ "fieldtype": "Section Break"
"depends_on": "eval:!doc.is_fixed_asset", },
"fieldname": "serial_no", {
"fieldtype": "Small Text", "depends_on": "eval:!doc.is_fixed_asset",
"in_list_view": 1, "fieldname": "serial_no",
"label": "Serial No", "fieldtype": "Small Text",
"no_copy": 1 "in_list_view": 1,
}, "label": "Serial No",
{ "no_copy": 1
"depends_on": "eval:!doc.is_fixed_asset", },
"fieldname": "batch_no", {
"fieldtype": "Link", "depends_on": "eval:!doc.is_fixed_asset",
"in_list_view": 1, "fieldname": "batch_no",
"label": "Batch No", "fieldtype": "Link",
"no_copy": 1, "in_list_view": 1,
"options": "Batch", "label": "Batch No",
"print_hide": 1 "no_copy": 1,
}, "options": "Batch",
{ "print_hide": 1
"depends_on": "eval:!doc.is_fixed_asset", },
"fieldname": "rejected_serial_no", {
"fieldtype": "Small Text", "depends_on": "eval: !parent.is_return",
"label": "Rejected Serial No", "fieldname": "rejected_serial_no",
"no_copy": 1, "fieldtype": "Small Text",
"print_hide": 1 "label": "Rejected Serial No",
}, "no_copy": 1,
{ "print_hide": 1
"fieldname": "subcontracting_order_item", },
"fieldtype": "Data", {
"hidden": 1, "fieldname": "subcontracting_order_item",
"label": "Subcontracting Order Item", "fieldtype": "Data",
"no_copy": 1, "hidden": 1,
"print_hide": 1, "label": "Subcontracting Order Item",
"print_width": "150px", "no_copy": 1,
"read_only": 1, "print_hide": 1,
"search_index": 1, "print_width": "150px",
"width": "150px" "read_only": 1,
}, "search_index": 1,
{ "width": "150px"
"fieldname": "col_break5", },
"fieldtype": "Column Break" {
}, "fieldname": "col_break5",
{ "fieldtype": "Column Break"
"fieldname": "bom", },
"fieldtype": "Link", {
"label": "BOM", "fieldname": "bom",
"no_copy": 1, "fieldtype": "Link",
"options": "BOM", "label": "BOM",
"print_hide": 1 "no_copy": 1,
}, "options": "BOM",
{ "print_hide": 1
"fetch_from": "item_code.brand", },
"fieldname": "brand", {
"fieldtype": "Link", "fetch_from": "item_code.brand",
"hidden": 1, "fieldname": "brand",
"label": "Brand", "fieldtype": "Link",
"options": "Brand", "hidden": 1,
"print_hide": 1, "label": "Brand",
"read_only": 1 "options": "Brand",
}, "print_hide": 1,
{ "read_only": 1
"fieldname": "rm_supp_cost", },
"fieldtype": "Currency", {
"hidden": 1, "fieldname": "rm_supp_cost",
"label": "Raw Materials Supplied Cost", "fieldtype": "Currency",
"no_copy": 1, "hidden": 1,
"options": "Company:company:default_currency", "label": "Raw Materials Supplied Cost",
"print_hide": 1, "no_copy": 1,
"print_width": "150px", "options": "Company:company:default_currency",
"read_only": 1, "print_hide": 1,
"width": "150px" "print_width": "150px",
}, "read_only": 1,
{ "width": "150px"
"fieldname": "expense_account", },
"fieldtype": "Link", {
"label": "Expense Account", "fieldname": "expense_account",
"options": "Account" "fieldtype": "Link",
}, "label": "Expense Account",
{ "options": "Account"
"collapsible": 1, },
"fieldname": "manufacture_details", {
"fieldtype": "Section Break", "collapsible": 1,
"label": "Manufacture" "fieldname": "manufacture_details",
}, "fieldtype": "Section Break",
{ "label": "Manufacture"
"fieldname": "manufacturer", },
"fieldtype": "Link", {
"label": "Manufacturer", "fieldname": "manufacturer",
"options": "Manufacturer" "fieldtype": "Link",
}, "label": "Manufacturer",
{ "options": "Manufacturer"
"fieldname": "column_break_16", },
"fieldtype": "Column Break" {
}, "fieldname": "column_break_16",
{ "fieldtype": "Column Break"
"fieldname": "manufacturer_part_no", },
"fieldtype": "Data", {
"label": "Manufacturer Part Number" "fieldname": "manufacturer_part_no",
}, "fieldtype": "Data",
{ "label": "Manufacturer Part Number"
"fieldname": "subcontracting_receipt_item", },
"fieldtype": "Data", {
"hidden": 1, "fieldname": "subcontracting_receipt_item",
"label": "Subcontracting Receipt Item", "fieldtype": "Data",
"no_copy": 1, "hidden": 1,
"print_hide": 1, "label": "Subcontracting Receipt Item",
"read_only": 1 "no_copy": 1,
}, "print_hide": 1,
{ "read_only": 1
"collapsible": 1, },
"fieldname": "image_column", {
"fieldtype": "Column Break" "collapsible": 1,
}, "fieldname": "image_column",
{ "fieldtype": "Column Break"
"fieldname": "tracking_section", },
"fieldtype": "Section Break" {
}, "fieldname": "tracking_section",
{ "fieldtype": "Section Break"
"fieldname": "col_break_tracking_section", },
"fieldtype": "Column Break" {
}, "fieldname": "col_break_tracking_section",
{ "fieldtype": "Column Break"
"fieldname": "accounting_dimensions_section", },
"fieldtype": "Section Break", {
"label": "Accounting Dimensions" "fieldname": "accounting_dimensions_section",
}, "fieldtype": "Section Break",
{ "label": "Accounting Dimensions"
"fieldname": "project", },
"fieldtype": "Link", {
"label": "Project", "fieldname": "project",
"options": "Project", "fieldtype": "Link",
"print_hide": 1 "label": "Project",
}, "options": "Project",
{ "print_hide": 1
"fieldname": "dimension_col_break", },
"fieldtype": "Column Break" {
}, "fieldname": "dimension_col_break",
{ "fieldtype": "Column Break"
"default": ":Company", },
"depends_on": "eval:cint(erpnext.is_perpetual_inventory_enabled(parent.company))", {
"fieldname": "cost_center", "default": ":Company",
"fieldtype": "Link", "depends_on": "eval:cint(erpnext.is_perpetual_inventory_enabled(parent.company))",
"label": "Cost Center", "fieldname": "cost_center",
"options": "Cost Center", "fieldtype": "Link",
"print_hide": 1 "label": "Cost Center",
}, "options": "Cost Center",
{ "print_hide": 1
"fieldname": "section_break_80", },
"fieldtype": "Section Break" {
}, "fieldname": "section_break_80",
{ "fieldtype": "Section Break"
"allow_on_submit": 1, },
"default": "0", {
"fieldname": "page_break", "allow_on_submit": 1,
"fieldtype": "Check", "default": "0",
"label": "Page Break", "fieldname": "page_break",
"print_hide": 1 "fieldtype": "Check",
}, "label": "Page Break",
{ "print_hide": 1
"depends_on": "returned_qty", },
"fieldname": "returned_qty", {
"fieldtype": "Float", "depends_on": "returned_qty",
"label": "Returned Qty", "fieldname": "returned_qty",
"no_copy": 1, "fieldtype": "Float",
"print_hide": 1, "label": "Returned Qty",
"read_only": 1 "no_copy": 1,
}, "print_hide": 1,
{ "read_only": 1
"fieldname": "accounting_details_section", },
"fieldtype": "Section Break", {
"label": "Accounting Details" "fieldname": "accounting_details_section",
}, "fieldtype": "Section Break",
{ "label": "Accounting Details"
"default": "1", },
"fieldname": "recalculate_rate", {
"fieldtype": "Check", "default": "1",
"label": "Recalculate Rate" "fieldname": "recalculate_rate",
} "fieldtype": "Check",
], "label": "Recalculate Rate"
"idx": 1, }
"istable": 1, ],
"links": [], "idx": 1,
"modified": "2022-08-20 17:16:48.269164", "istable": 1,
"modified_by": "Administrator", "links": [],
"module": "Subcontracting", "modified": "2022-11-16 14:21:26.125815",
"name": "Subcontracting Receipt Item", "modified_by": "Administrator",
"naming_rule": "Random", "module": "Subcontracting",
"owner": "Administrator", "name": "Subcontracting Receipt Item",
"permissions": [], "naming_rule": "Random",
"quick_entry": 1, "owner": "Administrator",
"sort_field": "modified", "permissions": [],
"sort_order": "DESC", "quick_entry": 1,
"states": [] "sort_field": "modified",
"sort_order": "DESC",
"states": []
} }

View File

@ -1,5 +1,57 @@
{% macro task_row(task, indent) %}
<div class="row mt-5 {% if task.children %} font-weight-bold {% endif %}">
<div class="col-sm-4">
<a class="nav-link " style="color: inherit; {% if task.parent_task %} margin-left: {{ indent }}px {% endif %}"
href="/tasks/{{ task.name | urlencode }}">
{% if task.parent_task %}
<span class="">
<i class="fa fa-level-up fa-rotate-90"></i>
</span>
{% endif %}
{{ task.subject }}</a>
</div>
<div class="col-sm-2">{{ task.status }}</div>
<div class="col-sm-2 small text-muted">
{% if task.exp_end_date %}
{{ task.exp_end_date }}
{% else %}
--
{% endif %}
</div>
<div class="col-sm-2">
{% if task["_assign"] %}
{% set assigned_users = json.loads(task["_assign"])%}
{% for user in assigned_users %}
{% set user_details = frappe.db.get_value("User", user,
["full_name", "user_image"],
as_dict = True)%}
{% if user_details.user_image %}
<span class="avatar avatar-small" style="width:32px; height:32px;" title="{{ user_details.full_name }}">
<img src="{{ user_details.user_image }}">
</span>
{% else %}
<span class="avatar avatar-small" style="width:32px; height:32px;" title="{{ user_details.full_name }}">
<div class='standard-image' style='background-color: #F5F4F4; color: #000;'>
{{ frappe.utils.get_abbr(user_details.full_name) }}
</div>
</span>
{% endif %}
{% endfor %}
{% endif %}
</div>
<div class="col-xs-2 text-right small text-muted">
{{ frappe.utils.pretty_date(task.modified) }}
</div>
</div>
{% if task.children %}
{% for child in task.children %}
{{ task_row(child, indent + 30) }}
{% endfor %}
{% endif %}
{% endmacro %}
{% for task in doc.tasks %} {% for task in doc.tasks %}
<div class="web-list-item transaction-list-item"> <div class="web-list-item transaction-list-item">
{{ task_row(task, 0) }} {{ task_row(task, 0) }}
</div> </div>
{% endfor %} {% endfor %}

Some files were not shown because too many files have changed in this diff Show More