Merge branch 'develop' into fix/pos/partial_return_amount
This commit is contained in:
commit
56b96f0a9c
@ -76,7 +76,7 @@ def get(
|
||||
|
||||
def build_result(account, dates, gl_entries):
|
||||
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
|
||||
date_index = 0
|
||||
|
@ -58,7 +58,7 @@ class Account(NestedSet):
|
||||
def validate_parent(self):
|
||||
"""Fetch Parent Details and validate 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
|
||||
)
|
||||
if not par:
|
||||
@ -82,7 +82,7 @@ class Account(NestedSet):
|
||||
|
||||
def set_root_and_report_type(self):
|
||||
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
|
||||
)
|
||||
|
||||
@ -92,7 +92,7 @@ class Account(NestedSet):
|
||||
self.root_type = par.root_type
|
||||
|
||||
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 self.report_type != db_value.report_type:
|
||||
frappe.db.sql(
|
||||
@ -111,13 +111,13 @@ class Account(NestedSet):
|
||||
)
|
||||
|
||||
def validate_root_details(self):
|
||||
# does not exists parent
|
||||
if frappe.db.exists("Account", self.name):
|
||||
if not frappe.db.get_value("Account", self.name, "parent_account"):
|
||||
throw(_("Root cannot be edited."), RootNotEditable)
|
||||
doc_before_save = self.get_doc_before_save()
|
||||
|
||||
if doc_before_save and not doc_before_save.parent_account:
|
||||
throw(_("Root cannot be edited."), RootNotEditable)
|
||||
|
||||
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):
|
||||
# ignore validation while creating new compnay or while syncing to child companies
|
||||
@ -127,7 +127,9 @@ class Account(NestedSet):
|
||||
return
|
||||
ancestors = get_root_company(self.company)
|
||||
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
|
||||
if not frappe.db.get_value(
|
||||
"Account", {"account_name": self.account_name, "company": ancestors[0]}, "name"
|
||||
@ -138,7 +140,7 @@ class Account(NestedSet):
|
||||
if not descendants:
|
||||
return
|
||||
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"]
|
||||
)
|
||||
filters = {
|
||||
@ -159,27 +161,28 @@ class Account(NestedSet):
|
||||
self.create_account_for_child_company(parent_acc_name_map, descendants, parent_acc_name)
|
||||
|
||||
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
|
||||
|
||||
existing_is_group = frappe.db.get_value("Account", self.name, "is_group")
|
||||
if cint(self.is_group) != cint(existing_is_group):
|
||||
if self.check_gle_exists():
|
||||
throw(_("Account with existing transaction cannot be converted to ledger"))
|
||||
elif self.is_group:
|
||||
if self.account_type and not self.flags.exclude_account_type_check:
|
||||
throw(_("Cannot covert to Group because Account Type is selected."))
|
||||
elif self.check_if_child_exists():
|
||||
throw(_("Account with child nodes cannot be set as ledger"))
|
||||
if self.check_gle_exists():
|
||||
throw(_("Account with existing transaction cannot be converted to ledger"))
|
||||
elif self.is_group:
|
||||
if self.account_type and not self.flags.exclude_account_type_check:
|
||||
throw(_("Cannot covert to Group because Account Type is selected."))
|
||||
elif self.check_if_child_exists():
|
||||
throw(_("Account with child nodes cannot be set as ledger"))
|
||||
|
||||
def validate_frozen_accounts_modifier(self):
|
||||
old_value = frappe.db.get_value("Account", self.name, "freeze_account")
|
||||
if old_value and old_value != self.freeze_account:
|
||||
frozen_accounts_modifier = frappe.db.get_value(
|
||||
"Accounts Settings", None, "frozen_accounts_modifier"
|
||||
)
|
||||
if not frozen_accounts_modifier or frozen_accounts_modifier not in frappe.get_roles():
|
||||
throw(_("You are not authorized to set Frozen value"))
|
||||
doc_before_save = self.get_doc_before_save()
|
||||
if not doc_before_save or doc_before_save.freeze_account == self.freeze_account:
|
||||
return
|
||||
|
||||
frozen_accounts_modifier = frappe.get_cached_value(
|
||||
"Accounts Settings", "Accounts Settings", "frozen_accounts_modifier"
|
||||
)
|
||||
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):
|
||||
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
|
||||
if frappe.db.get_value("Account", self.parent_account, "is_group") and not frappe.db.get_value(
|
||||
"Account", parent_acc_name_map[company], "is_group"
|
||||
):
|
||||
if frappe.get_cached_value(
|
||||
"Account", self.parent_account, "is_group"
|
||||
) and not frappe.get_cached_value("Account", parent_acc_name_map[company], "is_group"):
|
||||
msg = _(
|
||||
"While creating account for Child Company {0}, parent account {1} found as a ledger account."
|
||||
).format(company_bold, parent_acc_name_bold)
|
||||
@ -377,17 +380,15 @@ def validate_account_number(name, account_number, company):
|
||||
|
||||
@frappe.whitelist()
|
||||
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:
|
||||
return
|
||||
|
||||
old_acc_name, old_acc_number = frappe.db.get_value(
|
||||
"Account", name, ["account_name", "account_number"]
|
||||
)
|
||||
old_acc_name, old_acc_number = account.account_name, account.account_number
|
||||
|
||||
# check if account exists in parent 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"
|
||||
)
|
||||
|
||||
@ -435,22 +436,24 @@ def update_account_number(name, account_name, account_number=None, from_descenda
|
||||
@frappe.whitelist()
|
||||
def merge_account(old, new, is_group, root_type, company):
|
||||
# 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))
|
||||
|
||||
val = list(frappe.db.get_value("Account", new, ["is_group", "root_type", "company"]))
|
||||
|
||||
if val != [cint(is_group), root_type, company]:
|
||||
if (new_account.is_group, new_account.root_type, new_account.company) != (
|
||||
cint(is_group),
|
||||
root_type,
|
||||
company,
|
||||
):
|
||||
throw(
|
||||
_(
|
||||
"""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:
|
||||
frappe.db.set_value(
|
||||
"Account", new, "parent_account", frappe.db.get_value("Account", old, "parent_account")
|
||||
)
|
||||
if is_group and new_account.parent_account == old:
|
||||
new_account.db_set("parent_account", frappe.get_cached_value("Account", old, "parent_account"))
|
||||
|
||||
frappe.rename_doc("Account", old, new, merge=1, force=1)
|
||||
|
||||
|
@ -53,7 +53,7 @@ def create_charts(
|
||||
"account_number": account_number,
|
||||
"account_type": child.get("account_type"),
|
||||
"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"),
|
||||
}
|
||||
)
|
||||
@ -148,7 +148,7 @@ def get_charts_for_country(country, with_standard=False):
|
||||
) or frappe.local.flags.allow_unverified_charts:
|
||||
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:
|
||||
folders = ("verified",)
|
||||
if frappe.local.flags.allow_unverified_charts:
|
||||
|
@ -91,7 +91,7 @@
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "Enabling ensure each Sales Invoice has a unique value in Supplier Invoice No. field",
|
||||
"description": "Enabling ensure each Purchase Invoice has a unique value in Supplier Invoice No. field",
|
||||
"fieldname": "check_supplier_invoice_uniqueness",
|
||||
"fieldtype": "Check",
|
||||
"label": "Check Supplier Invoice Number Uniqueness"
|
||||
@ -354,7 +354,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2022-07-11 13:37:50.605141",
|
||||
"modified": "2022-11-27 21:49:52.538655",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounts Settings",
|
||||
|
@ -77,6 +77,6 @@ def get_party_bank_account(party_type, party):
|
||||
|
||||
@frappe.whitelist()
|
||||
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
|
||||
)
|
||||
|
@ -37,6 +37,14 @@ frappe.ui.form.on("Bank Clearance", {
|
||||
|
||||
refresh: function(frm) {
|
||||
frm.disable_save();
|
||||
|
||||
if (frm.doc.account && frm.doc.from_date && frm.doc.to_date) {
|
||||
frm.add_custom_button(__('Get Payment Entries'), () =>
|
||||
frm.trigger("get_payment_entries")
|
||||
);
|
||||
|
||||
frm.change_custom_button_type('Get Payment Entries', null, 'primary');
|
||||
}
|
||||
},
|
||||
|
||||
update_clearance_date: function(frm) {
|
||||
@ -46,22 +54,30 @@ frappe.ui.form.on("Bank Clearance", {
|
||||
callback: function(r, rt) {
|
||||
frm.refresh_field("payment_entries");
|
||||
frm.refresh_fields();
|
||||
|
||||
if (!frm.doc.payment_entries.length) {
|
||||
frm.change_custom_button_type('Get Payment Entries', null, 'primary');
|
||||
frm.change_custom_button_type('Update Clearance Date', null, 'default');
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
get_payment_entries: function(frm) {
|
||||
return frappe.call({
|
||||
method: "get_payment_entries",
|
||||
doc: frm.doc,
|
||||
callback: function(r, rt) {
|
||||
frm.refresh_field("payment_entries");
|
||||
frm.refresh_fields();
|
||||
|
||||
$(frm.fields_dict.payment_entries.wrapper).find("[data-fieldname=amount]").each(function(i,v){
|
||||
if (i !=0){
|
||||
$(v).addClass("text-right")
|
||||
}
|
||||
})
|
||||
if (frm.doc.payment_entries.length) {
|
||||
frm.add_custom_button(__('Update Clearance Date'), () =>
|
||||
frm.trigger("update_clearance_date")
|
||||
);
|
||||
|
||||
frm.change_custom_button_type('Get Payment Entries', null, 'default');
|
||||
frm.change_custom_button_type('Update Clearance Date', null, 'primary');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_copy": 1,
|
||||
"creation": "2013-01-10 16:34:05",
|
||||
"doctype": "DocType",
|
||||
@ -13,11 +14,8 @@
|
||||
"bank_account",
|
||||
"include_reconciled_entries",
|
||||
"include_pos_transactions",
|
||||
"get_payment_entries",
|
||||
"section_break_10",
|
||||
"payment_entries",
|
||||
"update_clearance_date",
|
||||
"total_amount"
|
||||
"payment_entries"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@ -76,11 +74,6 @@
|
||||
"fieldtype": "Check",
|
||||
"label": "Include POS Transactions"
|
||||
},
|
||||
{
|
||||
"fieldname": "get_payment_entries",
|
||||
"fieldtype": "Button",
|
||||
"label": "Get Payment Entries"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_10",
|
||||
"fieldtype": "Section Break"
|
||||
@ -91,25 +84,14 @@
|
||||
"fieldtype": "Table",
|
||||
"label": "Payment Entries",
|
||||
"options": "Bank Clearance Detail"
|
||||
},
|
||||
{
|
||||
"fieldname": "update_clearance_date",
|
||||
"fieldtype": "Button",
|
||||
"label": "Update Clearance Date"
|
||||
},
|
||||
{
|
||||
"fieldname": "total_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Total Amount",
|
||||
"options": "account_currency",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"hide_toolbar": 1,
|
||||
"icon": "fa fa-check",
|
||||
"idx": 1,
|
||||
"issingle": 1,
|
||||
"modified": "2020-04-06 16:12:06.628008",
|
||||
"links": [],
|
||||
"modified": "2022-11-28 17:24:13.008692",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Bank Clearance",
|
||||
@ -126,5 +108,6 @@
|
||||
"quick_entry": 1,
|
||||
"read_only": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "ASC"
|
||||
"sort_order": "ASC",
|
||||
"states": []
|
||||
}
|
@ -179,7 +179,6 @@ class BankClearance(Document):
|
||||
)
|
||||
|
||||
self.set("payment_entries", [])
|
||||
self.total_amount = 0.0
|
||||
default_currency = erpnext.get_default_currency()
|
||||
|
||||
for d in entries:
|
||||
@ -198,7 +197,6 @@ class BankClearance(Document):
|
||||
d.pop("debit")
|
||||
d.pop("account_currency")
|
||||
row.update(d)
|
||||
self.total_amount += flt(amount)
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_clearance_date(self):
|
||||
|
@ -57,7 +57,7 @@ def get_bank_transactions(bank_account, from_date=None, to_date=None):
|
||||
@frappe.whitelist()
|
||||
def get_account_balance(bank_account, till_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(
|
||||
{"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"],
|
||||
as_dict=True,
|
||||
)[0]
|
||||
company_account = frappe.get_value("Bank Account", bank_transaction.bank_account, "account")
|
||||
account_type = frappe.db.get_value("Account", second_account, "account_type")
|
||||
company_account = frappe.get_cached_value(
|
||||
"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 not (party_type and party):
|
||||
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 = {
|
||||
"voucher_type": entry_type,
|
||||
@ -219,8 +221,10 @@ def create_payment_entry_bts(
|
||||
paid_amount = bank_transaction.unallocated_amount
|
||||
payment_type = "Receive" if bank_transaction.deposit > 0 else "Pay"
|
||||
|
||||
company_account = frappe.get_value("Bank Account", bank_transaction.bank_account, "account")
|
||||
company = frappe.get_value("Account", company_account, "company")
|
||||
company_account = frappe.get_cached_value(
|
||||
"Bank Account", bank_transaction.bank_account, "account"
|
||||
)
|
||||
company = frappe.get_cached_value("Account", company_account, "company")
|
||||
payment_entry_dict = {
|
||||
"company": company,
|
||||
"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
|
||||
vouchers = json.loads(vouchers)
|
||||
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:
|
||||
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"
|
||||
)
|
||||
)
|
||||
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:
|
||||
gl_entry = frappe.db.get_value(
|
||||
|
@ -74,7 +74,7 @@ def get_header_mapping(columns, 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)
|
||||
|
||||
mapping = {row.file_field: row.bank_transaction_field for row in bank.bank_transaction_mapping}
|
||||
|
@ -59,7 +59,7 @@ class Budget(Document):
|
||||
account_list = []
|
||||
for d in self.get("accounts"):
|
||||
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
|
||||
)
|
||||
|
||||
@ -306,7 +306,7 @@ def get_other_condition(args, budget, for_doc):
|
||||
|
||||
if args.get("fiscal_year"):
|
||||
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"]
|
||||
)
|
||||
|
||||
@ -379,7 +379,7 @@ def get_accumulated_monthly_budget(monthly_distribution, posting_date, fiscal_ye
|
||||
):
|
||||
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
|
||||
|
||||
while dt <= getdate(posting_date):
|
||||
|
@ -45,8 +45,8 @@ def validate_columns(data):
|
||||
|
||||
@frappe.whitelist()
|
||||
def validate_company(company):
|
||||
parent_company, allow_account_creation_against_child_company = frappe.db.get_value(
|
||||
"Company", {"name": company}, ["parent_company", "allow_account_creation_against_child_company"]
|
||||
parent_company, allow_account_creation_against_child_company = frappe.get_cached_value(
|
||||
"Company", company, ["parent_company", "allow_account_creation_against_child_company"]
|
||||
)
|
||||
|
||||
if parent_company and (not allow_account_creation_against_child_company):
|
||||
|
@ -19,7 +19,7 @@ class Dunning(AccountsController):
|
||||
self.validate_overdue_days()
|
||||
self.validate_amount()
|
||||
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):
|
||||
self.overdue_days = (getdate(self.posting_date) - getdate(self.due_date)).days or 0
|
||||
|
@ -222,7 +222,7 @@ class ExchangeRateRevaluation(Document):
|
||||
|
||||
@frappe.whitelist()
|
||||
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"]
|
||||
)
|
||||
if account_type in ["Receivable", "Payable"] and not (party_type and party):
|
||||
|
@ -170,4 +170,4 @@ def auto_create_fiscal_year():
|
||||
|
||||
def get_from_and_to_date(fiscal_year):
|
||||
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)
|
||||
|
@ -58,7 +58,7 @@ class GLEntry(Document):
|
||||
validate_balance_type(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",
|
||||
"Payable",
|
||||
]:
|
||||
@ -120,7 +120,7 @@ class GLEntry(Document):
|
||||
frappe.throw(msg, title=_("Missing Cost Center"))
|
||||
|
||||
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():
|
||||
if (
|
||||
@ -188,7 +188,7 @@ class GLEntry(Document):
|
||||
def check_pl_account(self):
|
||||
if (
|
||||
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
|
||||
):
|
||||
frappe.throw(
|
||||
@ -281,7 +281,7 @@ class GLEntry(Document):
|
||||
|
||||
def validate_balance_type(account, adv_adj=False):
|
||||
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:
|
||||
balance = frappe.db.sql(
|
||||
"""select sum(debit) - sum(credit)
|
||||
|
@ -21,7 +21,7 @@ class ItemTaxTemplate(Document):
|
||||
check_list = []
|
||||
for d in self.get("taxes"):
|
||||
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 [
|
||||
"Tax",
|
||||
|
@ -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";
|
||||
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)) {
|
||||
|
@ -319,7 +319,7 @@ class JournalEntry(AccountsController):
|
||||
|
||||
def validate_party(self):
|
||||
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 not (d.party_type and d.party):
|
||||
frappe.throw(
|
||||
@ -382,7 +382,7 @@ class JournalEntry(AccountsController):
|
||||
def validate_against_jv(self):
|
||||
for d in self.get("accounts"):
|
||||
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:
|
||||
frappe.throw(
|
||||
_(
|
||||
@ -631,7 +631,7 @@ class JournalEntry(AccountsController):
|
||||
def validate_multi_currency(self):
|
||||
alternate_currency = []
|
||||
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
|
||||
)
|
||||
if account:
|
||||
@ -762,7 +762,7 @@ class JournalEntry(AccountsController):
|
||||
party_amount += d.debit_in_account_currency or d.credit_in_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_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
|
||||
|
||||
if account:
|
||||
account_details = frappe.db.get_value(
|
||||
account_details = frappe.get_cached_value(
|
||||
"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": ref_doc.get(args.get("party_type").lower()),
|
||||
"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")
|
||||
or get_account_currency(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,
|
||||
"balance": account_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)
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
@ -1349,7 +1349,7 @@ def 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
|
||||
)
|
||||
|
||||
|
@ -25,7 +25,7 @@ class ModeofPayment(Document):
|
||||
def validate_accounts(self):
|
||||
for entry in self.accounts:
|
||||
"""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(
|
||||
_("Account {0} does not match with Company {1} in Mode of Account: {2}").format(
|
||||
entry.default_account, entry.company, self.name
|
||||
|
@ -725,7 +725,7 @@ class PaymentEntry(AccountsController):
|
||||
|
||||
def validate_transaction_reference(self):
|
||||
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 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"
|
||||
)
|
||||
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"
|
||||
)
|
||||
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_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():
|
||||
frappe.msgprint(_("{0} is on hold till {1}").format(doc.name, doc.release_date))
|
||||
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",
|
||||
{"name": doc.payment_terms_template},
|
||||
doc.payment_terms_template,
|
||||
"allocate_payment_based_on_payment_terms",
|
||||
):
|
||||
|
||||
|
@ -11,7 +11,7 @@ class PaymentGatewayAccount(Document):
|
||||
self.name = self.payment_gateway + " - " + self.currency
|
||||
|
||||
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.set_as_default_if_not_set()
|
||||
|
@ -97,7 +97,7 @@ class PaymentLedgerEntry(Document):
|
||||
)
|
||||
|
||||
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():
|
||||
if (
|
||||
|
@ -53,7 +53,7 @@ class PaymentRequest(Document):
|
||||
|
||||
def validate_currency(self):
|
||||
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"
|
||||
):
|
||||
frappe.throw(_("Transaction currency must be same as Payment Gateway currency"))
|
||||
|
@ -43,7 +43,7 @@ class PeriodClosingVoucher(AccountsController):
|
||||
make_reverse_gl_entries(voucher_type="Period Closing Voucher", voucher_no=self.name)
|
||||
|
||||
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"]:
|
||||
frappe.throw(
|
||||
|
@ -5,6 +5,8 @@
|
||||
frappe.provide("erpnext.accounts");
|
||||
|
||||
erpnext.selling.POSInvoiceController = class POSInvoiceController extends erpnext.selling.SellingController {
|
||||
settings = {};
|
||||
|
||||
setup(doc) {
|
||||
this.setup_posting_date_time_check();
|
||||
super.setup(doc);
|
||||
@ -25,8 +27,13 @@ erpnext.selling.POSInvoiceController = class POSInvoiceController extends erpnex
|
||||
erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
|
||||
}
|
||||
|
||||
onload_post_render(frm) {
|
||||
this.pos_profile(frm);
|
||||
}
|
||||
|
||||
refresh(doc) {
|
||||
super.refresh();
|
||||
|
||||
if (doc.docstatus == 1 && !doc.is_return) {
|
||||
this.frm.add_custom_button(__('Return'), this.make_sales_return, __('Create'));
|
||||
this.frm.page.set_inner_btn_group_as_primary(__('Create'));
|
||||
@ -36,6 +43,18 @@ erpnext.selling.POSInvoiceController = class POSInvoiceController extends erpnex
|
||||
this.frm.return_print_format = "Sales Invoice Return";
|
||||
this.frm.set_value('consolidated_invoice', '');
|
||||
}
|
||||
|
||||
this.frm.set_query("customer", (function () {
|
||||
const customer_groups = this.settings?.customer_groups;
|
||||
|
||||
if (!customer_groups?.length) return {};
|
||||
|
||||
return {
|
||||
filters: {
|
||||
customer_group: ["in", customer_groups],
|
||||
}
|
||||
}
|
||||
}).bind(this));
|
||||
}
|
||||
|
||||
is_pos() {
|
||||
@ -88,6 +107,25 @@ erpnext.selling.POSInvoiceController = class POSInvoiceController extends erpnex
|
||||
});
|
||||
}
|
||||
|
||||
pos_profile(frm) {
|
||||
if (!frm.pos_profile || frm.pos_profile == '') {
|
||||
this.update_customer_groups_settings([]);
|
||||
return;
|
||||
}
|
||||
|
||||
frappe.call({
|
||||
method: "erpnext.selling.page.point_of_sale.point_of_sale.get_pos_profile_data",
|
||||
args: { "pos_profile": frm.pos_profile },
|
||||
callback: ({ message: profile }) => {
|
||||
this.update_customer_groups_settings(profile?.customer_groups);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
update_customer_groups_settings(customer_groups) {
|
||||
this.settings.customer_groups = customer_groups?.map((group) => group.name)
|
||||
}
|
||||
|
||||
amount(){
|
||||
this.write_off_outstanding_amount_automatically()
|
||||
}
|
||||
|
@ -335,7 +335,8 @@ class POSInvoice(SalesInvoice):
|
||||
if (
|
||||
self.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(
|
||||
_("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", 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"
|
||||
)
|
||||
selling_price_list = (
|
||||
@ -532,8 +533,8 @@ class POSInvoice(SalesInvoice):
|
||||
|
||||
if not self.debit_to:
|
||||
self.debit_to = get_party_account("Customer", self.customer, self.company)
|
||||
self.party_account_currency = frappe.db.get_value(
|
||||
"Account", self.debit_to, "account_currency", cache=True
|
||||
self.party_account_currency = frappe.get_cached_value(
|
||||
"Account", self.debit_to, "account_currency"
|
||||
)
|
||||
if not self.due_date and self.customer:
|
||||
self.due_date = get_due_date(self.posting_date, "Customer", self.customer, self.company)
|
||||
|
@ -81,7 +81,7 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
|
||||
}
|
||||
|
||||
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'));
|
||||
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() {
|
||||
me.make_payment_request()
|
||||
}, __('Create'));
|
||||
|
@ -25,6 +25,10 @@
|
||||
"apply_tds",
|
||||
"tax_withholding_category",
|
||||
"amended_from",
|
||||
"supplier_invoice_details",
|
||||
"bill_no",
|
||||
"column_break_15",
|
||||
"bill_date",
|
||||
"accounting_dimensions_section",
|
||||
"cost_center",
|
||||
"dimension_col_break",
|
||||
@ -65,6 +69,7 @@
|
||||
"tax_category",
|
||||
"column_break_49",
|
||||
"shipping_rule",
|
||||
"incoterm",
|
||||
"section_break_51",
|
||||
"taxes",
|
||||
"totals",
|
||||
@ -151,10 +156,6 @@
|
||||
"status",
|
||||
"column_break_177",
|
||||
"per_received",
|
||||
"supplier_invoice_details",
|
||||
"bill_no",
|
||||
"column_break_15",
|
||||
"bill_date",
|
||||
"accounting_details_section",
|
||||
"credit_to",
|
||||
"party_account_currency",
|
||||
@ -1534,13 +1535,19 @@
|
||||
"oldfieldtype": "Section Break",
|
||||
"options": "fa fa-file-text",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "incoterm",
|
||||
"fieldtype": "Link",
|
||||
"label": "Incoterm",
|
||||
"options": "Incoterm"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-file-text",
|
||||
"idx": 204,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-11-04 01:02:44.544878",
|
||||
"modified": "2022-11-25 12:44:29.935567",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice",
|
||||
|
@ -153,8 +153,8 @@ class PurchaseInvoice(BuyingController):
|
||||
def set_missing_values(self, for_validate=False):
|
||||
if not self.credit_to:
|
||||
self.credit_to = get_party_account("Supplier", self.supplier, self.company)
|
||||
self.party_account_currency = frappe.db.get_value(
|
||||
"Account", self.credit_to, "account_currency", cache=True
|
||||
self.party_account_currency = frappe.get_cached_value(
|
||||
"Account", self.credit_to, "account_currency"
|
||||
)
|
||||
if not self.due_date:
|
||||
self.due_date = get_due_date(
|
||||
@ -175,7 +175,7 @@ class PurchaseInvoice(BuyingController):
|
||||
if not self.credit_to:
|
||||
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
|
||||
)
|
||||
|
||||
@ -606,7 +606,7 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
def make_supplier_gl_entry(self, gl_entries):
|
||||
# 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 = (
|
||||
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)
|
||||
|
||||
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"
|
||||
)
|
||||
)
|
||||
@ -809,10 +809,7 @@ class PurchaseInvoice(BuyingController):
|
||||
else item.deferred_expense_account
|
||||
)
|
||||
|
||||
if not item.is_fixed_asset:
|
||||
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"))
|
||||
dummy, amount = self.get_amount_and_base_amount(item, None)
|
||||
|
||||
if provisional_accounting_for_non_stock_items:
|
||||
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)
|
||||
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 [
|
||||
"Asset Received But Not Billed",
|
||||
"Fixed Asset",
|
||||
|
@ -64,6 +64,7 @@
|
||||
"taxes_and_charges",
|
||||
"column_break_38",
|
||||
"shipping_rule",
|
||||
"incoterm",
|
||||
"column_break_55",
|
||||
"tax_category",
|
||||
"section_break_40",
|
||||
@ -2114,6 +2115,12 @@
|
||||
"label": "Repost Required",
|
||||
"no_copy": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "incoterm",
|
||||
"fieldtype": "Link",
|
||||
"label": "Incoterm",
|
||||
"options": "Incoterm"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-file-text",
|
||||
@ -2126,7 +2133,7 @@
|
||||
"link_fieldname": "consolidated_invoice"
|
||||
}
|
||||
],
|
||||
"modified": "2022-11-15 09:33:47.870616",
|
||||
"modified": "2022-11-17 17:17:10.883487",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice",
|
||||
|
@ -27,7 +27,7 @@ class SalesTaxesandChargesTemplate(Document):
|
||||
def set_missing_values(self):
|
||||
for data in self.taxes:
|
||||
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):
|
||||
|
@ -226,6 +226,42 @@ class TestTaxWithholdingCategory(unittest.TestCase):
|
||||
for d in reversed(invoices):
|
||||
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):
|
||||
frappe.db.set_value(
|
||||
"Supplier", "Test TDS Supplier5", "tax_withholding_category", "Test Service Category"
|
||||
@ -348,6 +384,39 @@ def create_purchase_invoice(**args):
|
||||
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):
|
||||
# return sales invoice doc object
|
||||
item = frappe.db.get_value("Item", {"item_name": "TCS Item"}, "name")
|
||||
|
@ -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(
|
||||
gl_map[0].company, gl_map[0].voucher_type, gl_map[0].voucher_no
|
||||
)
|
||||
round_off_account_exists = False
|
||||
round_off_gle = frappe._dict()
|
||||
for d in gl_map:
|
||||
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
|
||||
round_off_account_exists = False
|
||||
|
||||
if round_off_account_exists and abs(debit_credit_diff) < (1.0 / (10**precision)):
|
||||
gl_map.remove(round_off_gle)
|
||||
return
|
||||
if gl_map[0].voucher_type != "Period Closing Voucher":
|
||||
for d in gl_map:
|
||||
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:
|
||||
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)
|
||||
|
||||
if not round_off_account_exists:
|
||||
gl_map.append(round_off_gle)
|
||||
|
||||
|
@ -296,7 +296,7 @@ def get_default_price_list(party):
|
||||
return party.default_price_list
|
||||
|
||||
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):
|
||||
@ -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)
|
||||
if existing_gle_currency:
|
||||
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:
|
||||
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 generator():
|
||||
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)
|
||||
|
||||
@ -474,15 +474,15 @@ def validate_party_accounts(doc):
|
||||
else:
|
||||
companies.append(account.company)
|
||||
|
||||
party_account_currency = frappe.db.get_value(
|
||||
"Account", account.account, "account_currency", cache=True
|
||||
)
|
||||
party_account_currency = frappe.get_cached_value("Account", account.account, "account_currency")
|
||||
if frappe.db.get_default("Company"):
|
||||
company_default_currency = frappe.get_cached_value(
|
||||
"Company", frappe.db.get_default("Company"), "default_currency"
|
||||
)
|
||||
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)
|
||||
|
||||
@ -801,7 +801,7 @@ def get_dashboard_info(party_type, party, loyalty_program=None):
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
if party_account_currency == company_default_currency:
|
||||
|
@ -21,7 +21,7 @@ def execute(filters=None):
|
||||
if not filters.get("account"):
|
||||
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)
|
||||
|
||||
|
@ -180,7 +180,7 @@ def get_account_type_based_gl_data(company, start_date, end_date, account_type,
|
||||
filters = frappe._dict(filters or {})
|
||||
|
||||
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)
|
||||
""" % (
|
||||
frappe.db.escape(filters.finance_book),
|
||||
|
@ -641,7 +641,7 @@ def set_gl_entries_by_account(
|
||||
"rgt": root_rgt,
|
||||
"company": d.name,
|
||||
"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,
|
||||
)
|
||||
|
@ -220,8 +220,8 @@ class PartyLedgerSummaryReport(object):
|
||||
|
||||
if self.filters.party_type == "Customer":
|
||||
if self.filters.get("customer_group"):
|
||||
lft, rgt = frappe.db.get_value(
|
||||
"Customer Group", self.filters.get("customer_group"), ["lft", "rgt"]
|
||||
lft, rgt = frappe.get_cached_value(
|
||||
"Customer Group", self.filters["customer_group"], ["lft", "rgt"]
|
||||
)
|
||||
|
||||
conditions.append(
|
||||
|
@ -90,7 +90,7 @@ def set_gl_entries_by_account(dimension_list, filters, account, gl_entries_by_ac
|
||||
gl_filters["dimensions"] = set(dimension_list)
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
|
@ -440,7 +440,7 @@ def set_gl_entries_by_account(
|
||||
}
|
||||
|
||||
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():
|
||||
if value:
|
||||
|
@ -174,7 +174,7 @@ def get_gl_entries(filters, accounting_dimensions):
|
||||
order_by_statement = "order by account, posting_date, creation"
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
@ -286,9 +286,11 @@ def get_accounts_with_children(accounts):
|
||||
|
||||
all_accounts = []
|
||||
for d in accounts:
|
||||
if frappe.db.exists("Account", d):
|
||||
lft, rgt = frappe.db.get_value("Account", d, ["lft", "rgt"])
|
||||
children = frappe.get_all("Account", filters={"lft": [">=", lft], "rgt": ["<=", rgt]})
|
||||
account = frappe.get_cached_doc("Account", d)
|
||||
if account:
|
||||
children = frappe.get_all(
|
||||
"Account", filters={"lft": [">=", account.lft], "rgt": ["<=", account.rgt]}
|
||||
)
|
||||
all_accounts += [c.name for c in children]
|
||||
else:
|
||||
frappe.throw(_("Account: {0} does not exist").format(d))
|
||||
|
@ -38,7 +38,7 @@ def validate_filters(filters):
|
||||
if not 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
|
||||
)
|
||||
if not fiscal_year:
|
||||
@ -177,7 +177,7 @@ def get_rootwise_opening_balances(filters, report_type):
|
||||
"year_start_date": filters.year_start_date,
|
||||
"project": filters.project,
|
||||
"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:
|
||||
|
@ -975,7 +975,7 @@ def get_account_balances(accounts, company):
|
||||
def create_payment_gateway_account(gateway, payment_channel="Email"):
|
||||
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:
|
||||
return
|
||||
|
||||
|
@ -224,7 +224,10 @@ class TestAsset(AssetSetup):
|
||||
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"))
|
||||
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.assertTrue(asset.journal_entry_for_scrap)
|
||||
|
@ -54,6 +54,8 @@
|
||||
"column_break_26",
|
||||
"total",
|
||||
"net_total",
|
||||
"tax_withholding_net_total",
|
||||
"base_tax_withholding_net_total",
|
||||
"section_break_48",
|
||||
"pricing_rules",
|
||||
"raw_material_details",
|
||||
@ -65,6 +67,7 @@
|
||||
"tax_category",
|
||||
"column_break_50",
|
||||
"shipping_rule",
|
||||
"incoterm",
|
||||
"section_break_52",
|
||||
"taxes",
|
||||
"totals",
|
||||
@ -1220,6 +1223,26 @@
|
||||
"label": "Additional Info",
|
||||
"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",
|
||||
"fieldtype": "Column Break"
|
||||
@ -1227,13 +1250,19 @@
|
||||
{
|
||||
"fieldname": "column_break_103",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "incoterm",
|
||||
"fieldtype": "Link",
|
||||
"label": "Incoterm",
|
||||
"options": "Incoterm"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-file-text",
|
||||
"idx": 105,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-11-17 12:34:36.033363",
|
||||
"modified": "2022-11-17 17:28:07.729943",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order",
|
||||
|
@ -736,27 +736,29 @@ class TestPurchaseOrder(FrappeTestCase):
|
||||
def test_advance_paid_upon_payment_entry_cancellation(self):
|
||||
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.reference_no = "1"
|
||||
pe.reference_date = nowdate()
|
||||
pe.paid_from_account_currency = po_doc.currency
|
||||
pe.paid_to_account_currency = po_doc.currency
|
||||
pe.source_exchange_rate = 1
|
||||
pe = get_payment_entry("Purchase Order", po_doc.name)
|
||||
pe.mode_of_payment = "Cash"
|
||||
pe.paid_from = "Cash - _TC"
|
||||
pe.source_exchange_rate = 80
|
||||
pe.target_exchange_rate = 1
|
||||
pe.paid_amount = po_doc.grand_total
|
||||
pe.save(ignore_permissions=True)
|
||||
pe.submit()
|
||||
|
||||
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.cancel()
|
||||
|
||||
po_doc.reload()
|
||||
self.assertEqual(po_doc.advance_paid, 0)
|
||||
self.assertEqual(po_doc.party_account_currency, "USD")
|
||||
|
||||
def test_schedule_date(self):
|
||||
po = create_purchase_order(do_not_submit=True)
|
||||
|
@ -44,6 +44,7 @@
|
||||
"discount_amount",
|
||||
"base_rate_with_margin",
|
||||
"sec_break2",
|
||||
"apply_tds",
|
||||
"rate",
|
||||
"amount",
|
||||
"item_tax_template",
|
||||
@ -889,6 +890,12 @@
|
||||
{
|
||||
"fieldname": "column_break_54",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "apply_tds",
|
||||
"fieldtype": "Check",
|
||||
"label": "Apply TDS"
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
|
@ -28,6 +28,7 @@
|
||||
"sec_break_email_2",
|
||||
"message_for_supplier",
|
||||
"terms_section_break",
|
||||
"incoterm",
|
||||
"tc_name",
|
||||
"terms",
|
||||
"printing_settings",
|
||||
@ -271,13 +272,19 @@
|
||||
"fieldname": "schedule_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Required Date"
|
||||
},
|
||||
{
|
||||
"fieldname": "incoterm",
|
||||
"fieldtype": "Link",
|
||||
"label": "Incoterm",
|
||||
"options": "Incoterm"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-shopping-cart",
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-04-06 17:47:49.909000",
|
||||
"modified": "2022-11-17 17:26:33.770993",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Request for Quotation",
|
||||
@ -345,5 +352,6 @@
|
||||
"search_fields": "status, transaction_date",
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
@ -45,6 +45,7 @@
|
||||
"tax_category",
|
||||
"column_break_36",
|
||||
"shipping_rule",
|
||||
"incoterm",
|
||||
"section_break_38",
|
||||
"taxes",
|
||||
"totals",
|
||||
@ -823,6 +824,12 @@
|
||||
{
|
||||
"fieldname": "column_break_85",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "incoterm",
|
||||
"fieldtype": "Link",
|
||||
"label": "Incoterm",
|
||||
"options": "Incoterm"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-shopping-cart",
|
||||
@ -830,7 +837,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-09-27 18:20:09.462037",
|
||||
"modified": "2022-11-17 17:27:32.179686",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Quotation",
|
||||
|
@ -239,6 +239,14 @@ class AccountsController(TransactionBase):
|
||||
else:
|
||||
item.set(field_map.get(self.doctype), default_deferred_account)
|
||||
|
||||
def validate_auto_repeat_subscription_dates(self):
|
||||
if (
|
||||
self.get("from_date")
|
||||
and self.get("to_date")
|
||||
and getdate(self.from_date) > getdate(self.to_date)
|
||||
):
|
||||
frappe.throw(_("To Date cannot be before From Date"), title=_("Invalid Auto Repeat Date"))
|
||||
|
||||
def validate_deferred_start_and_end_date(self):
|
||||
for d in self.items:
|
||||
if d.get("enable_deferred_revenue") or d.get("enable_deferred_expense"):
|
||||
@ -1352,12 +1360,12 @@ class AccountsController(TransactionBase):
|
||||
party = self.customer if self.doctype == "Sales Order" else self.supplier
|
||||
advance = (
|
||||
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(
|
||||
(ple.against_voucher_type == self.doctype)
|
||||
& (ple.against_voucher_no == self.name)
|
||||
& (ple.party == party)
|
||||
& (ple.delinked == 0)
|
||||
& (ple.docstatus == 1)
|
||||
& (ple.company == self.company)
|
||||
)
|
||||
.run(as_dict=True)
|
||||
|
@ -41,6 +41,7 @@ class BuyingController(SubcontractingController):
|
||||
self.validate_from_warehouse()
|
||||
self.set_supplier_address()
|
||||
self.validate_asset_return()
|
||||
self.validate_auto_repeat_subscription_dates()
|
||||
|
||||
if self.doctype == "Purchase Invoice":
|
||||
self.validate_purchase_receipt_if_update_stock()
|
||||
|
@ -40,6 +40,7 @@ class SellingController(StockController):
|
||||
self.set_customer_address()
|
||||
self.validate_for_duplicate_items()
|
||||
self.validate_target_warehouse()
|
||||
self.validate_auto_repeat_subscription_dates()
|
||||
|
||||
def set_missing_values(self, for_validate=False):
|
||||
|
||||
@ -581,6 +582,7 @@ class SellingController(StockController):
|
||||
"customer_address": "address_display",
|
||||
"shipping_address_name": "shipping_address",
|
||||
"company_address": "company_address_display",
|
||||
"dispatch_address_name": "dispatch_address",
|
||||
}
|
||||
|
||||
for address_field, address_display_field in address_dict.items():
|
||||
|
@ -120,7 +120,7 @@ def link_open_tasks(ref_doctype, ref_docname, doc):
|
||||
todo_doc = frappe.get_doc("ToDo", todo.name)
|
||||
todo_doc.reference_type = doc.doctype
|
||||
todo_doc.reference_name = doc.name
|
||||
todo_doc.db_update()
|
||||
todo_doc.save()
|
||||
|
||||
|
||||
def link_open_events(ref_doctype, ref_docname, doc):
|
||||
|
@ -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
|
||||
}
|
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -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'
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
});
|
@ -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
|
||||
}
|
@ -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)
|
@ -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
|
@ -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 list(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
|
@ -175,6 +175,7 @@ website_route_rules = [
|
||||
},
|
||||
},
|
||||
{"from_route": "/project", "to_route": "Project"},
|
||||
{"from_route": "/tasks", "to_route": "Task"},
|
||||
]
|
||||
|
||||
standard_portal_menu_items = [
|
||||
@ -312,11 +313,9 @@ doc_events = {
|
||||
"erpnext.regional.create_transaction_log",
|
||||
"erpnext.regional.italy.utils.sales_invoice_on_submit",
|
||||
"erpnext.regional.saudi_arabia.utils.create_qr_code",
|
||||
"erpnext.erpnext_integrations.taxjar_integration.create_transaction",
|
||||
],
|
||||
"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",
|
||||
],
|
||||
"on_trash": "erpnext.regional.check_deletion_permission",
|
||||
@ -349,9 +348,6 @@ doc_events = {
|
||||
"Email Unsubscribe": {
|
||||
"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"]},
|
||||
"Integration Request": {
|
||||
"validate": "erpnext.accounts.doctype.payment_request.payment_request.validate_payment"
|
||||
|
@ -191,7 +191,9 @@ def get_total_pledged_security_value(loan):
|
||||
|
||||
for security, qty in pledged_securities.items():
|
||||
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
|
||||
|
||||
|
@ -33,6 +33,11 @@ frappe.ui.form.on('Job Card', {
|
||||
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) {
|
||||
let to_request = frm.doc.for_quantity > frm.doc.transferred_qty;
|
||||
let excess_transfer_allowed = frm.doc.__onload.job_card_excess_transfer;
|
||||
|
@ -57,6 +57,10 @@ class JobCard(Document):
|
||||
)
|
||||
self.set_onload("job_card_excess_transfer", excess_transfer)
|
||||
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):
|
||||
self.set_wip_warehouse()
|
||||
|
@ -47,7 +47,7 @@
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Warehouse",
|
||||
"label": "For Warehouse",
|
||||
"options": "Warehouse",
|
||||
"reqd": 1
|
||||
},
|
||||
@ -173,7 +173,7 @@
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-08-23 18:17:58.400462",
|
||||
"modified": "2022-11-26 14:59:25.879631",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Material Request Plan Item",
|
||||
@ -182,5 +182,6 @@
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
@ -3,13 +3,13 @@
|
||||
|
||||
frappe.ui.form.on('Production Plan', {
|
||||
|
||||
before_save: function(frm) {
|
||||
before_save(frm) {
|
||||
// preserve temporary names on production plan item to re-link sub-assembly items
|
||||
frm.doc.po_items.forEach(item => {
|
||||
item.temporary_name = item.name;
|
||||
});
|
||||
},
|
||||
setup: function(frm) {
|
||||
setup(frm) {
|
||||
frm.custom_make_buttons = {
|
||||
'Work Order': 'Work Order / Subcontract PO',
|
||||
'Material Request': 'Material Request',
|
||||
@ -70,7 +70,7 @@ frappe.ui.form.on('Production Plan', {
|
||||
}
|
||||
},
|
||||
|
||||
refresh: function(frm) {
|
||||
refresh(frm) {
|
||||
if (frm.doc.docstatus === 1) {
|
||||
frm.trigger("show_progress");
|
||||
|
||||
@ -158,7 +158,7 @@ frappe.ui.form.on('Production Plan', {
|
||||
set_field_options("projected_qty_formula", projected_qty_formula);
|
||||
},
|
||||
|
||||
close_open_production_plan: (frm, close=false) => {
|
||||
close_open_production_plan(frm, close=false) {
|
||||
frappe.call({
|
||||
method: "set_status",
|
||||
freeze: true,
|
||||
@ -170,7 +170,7 @@ frappe.ui.form.on('Production Plan', {
|
||||
});
|
||||
},
|
||||
|
||||
make_work_order: function(frm) {
|
||||
make_work_order(frm) {
|
||||
frappe.call({
|
||||
method: "make_work_order",
|
||||
freeze: true,
|
||||
@ -181,7 +181,7 @@ frappe.ui.form.on('Production Plan', {
|
||||
});
|
||||
},
|
||||
|
||||
make_material_request: function(frm) {
|
||||
make_material_request(frm) {
|
||||
|
||||
frappe.confirm(__("Do you want to submit the material request"),
|
||||
function() {
|
||||
@ -193,7 +193,7 @@ frappe.ui.form.on('Production Plan', {
|
||||
);
|
||||
},
|
||||
|
||||
create_material_request: function(frm, submit) {
|
||||
create_material_request(frm, submit) {
|
||||
frm.doc.submit_material_request = submit;
|
||||
|
||||
frappe.call({
|
||||
@ -206,7 +206,7 @@ frappe.ui.form.on('Production Plan', {
|
||||
});
|
||||
},
|
||||
|
||||
get_sales_orders: function(frm) {
|
||||
get_sales_orders(frm) {
|
||||
frappe.call({
|
||||
method: "get_open_sales_orders",
|
||||
doc: frm.doc,
|
||||
@ -216,7 +216,7 @@ frappe.ui.form.on('Production Plan', {
|
||||
});
|
||||
},
|
||||
|
||||
get_material_request: function(frm) {
|
||||
get_material_request(frm) {
|
||||
frappe.call({
|
||||
method: "get_pending_material_requests",
|
||||
doc: frm.doc,
|
||||
@ -226,7 +226,7 @@ frappe.ui.form.on('Production Plan', {
|
||||
});
|
||||
},
|
||||
|
||||
get_items: function (frm) {
|
||||
get_items(frm) {
|
||||
frm.clear_table('prod_plan_references');
|
||||
|
||||
frappe.call({
|
||||
@ -238,7 +238,7 @@ frappe.ui.form.on('Production Plan', {
|
||||
}
|
||||
});
|
||||
},
|
||||
combine_items: function (frm) {
|
||||
combine_items(frm) {
|
||||
frm.clear_table("prod_plan_references");
|
||||
|
||||
frappe.call({
|
||||
@ -254,14 +254,14 @@ frappe.ui.form.on('Production Plan', {
|
||||
});
|
||||
},
|
||||
|
||||
combine_sub_items: (frm) => {
|
||||
combine_sub_items(frm) {
|
||||
if (frm.doc.sub_assembly_items.length > 0) {
|
||||
frm.clear_table("sub_assembly_items");
|
||||
frm.trigger("get_sub_assembly_items");
|
||||
}
|
||||
},
|
||||
|
||||
get_sub_assembly_items: function(frm) {
|
||||
get_sub_assembly_items(frm) {
|
||||
frm.dirty();
|
||||
|
||||
frappe.call({
|
||||
@ -274,9 +274,25 @@ frappe.ui.form.on('Production Plan', {
|
||||
});
|
||||
},
|
||||
|
||||
get_items_for_mr: function(frm) {
|
||||
toggle_for_warehouse(frm) {
|
||||
frm.toggle_reqd("for_warehouse", true);
|
||||
},
|
||||
|
||||
get_items_for_mr(frm) {
|
||||
if (!frm.doc.for_warehouse) {
|
||||
frappe.throw(__("To make material requests, 'Make Material Request for Warehouse' field is mandatory"));
|
||||
frm.trigger("toggle_for_warehouse");
|
||||
frappe.throw(__("Select the Warehouse"));
|
||||
}
|
||||
|
||||
frm.events.get_items_for_material_requests(frm, [{
|
||||
warehouse: frm.doc.for_warehouse
|
||||
}]);
|
||||
},
|
||||
|
||||
transfer_materials(frm) {
|
||||
if (!frm.doc.for_warehouse) {
|
||||
frm.trigger("toggle_for_warehouse");
|
||||
frappe.throw(__("Select the Warehouse"));
|
||||
}
|
||||
|
||||
if (frm.doc.ignore_existing_ordered_qty) {
|
||||
@ -287,18 +303,10 @@ frappe.ui.form.on('Production Plan', {
|
||||
title: title,
|
||||
fields: [
|
||||
{
|
||||
'label': __('Target Warehouse'),
|
||||
'fieldtype': 'Link',
|
||||
'fieldname': 'target_warehouse',
|
||||
'read_only': true,
|
||||
'default': frm.doc.for_warehouse
|
||||
},
|
||||
{
|
||||
'label': __('Source Warehouses (Optional)'),
|
||||
'label': __('Transfer From Warehouses'),
|
||||
'fieldtype': 'Table MultiSelect',
|
||||
'fieldname': 'warehouses',
|
||||
'options': 'Production Plan Material Request Warehouse',
|
||||
'description': __('If source warehouse selected then system will create the material request with type Material Transfer from Source to Target warehouse. If not selected then will create the material request with type Purchase for the target warehouse.'),
|
||||
get_query: function () {
|
||||
return {
|
||||
filters: {
|
||||
@ -307,6 +315,13 @@ frappe.ui.form.on('Production Plan', {
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
'label': __('For Warehouse'),
|
||||
'fieldtype': 'Link',
|
||||
'fieldname': 'target_warehouse',
|
||||
'read_only': true,
|
||||
'default': frm.doc.for_warehouse
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
@ -320,8 +335,8 @@ frappe.ui.form.on('Production Plan', {
|
||||
}
|
||||
},
|
||||
|
||||
get_items_for_material_requests: function(frm, warehouses) {
|
||||
const set_fields = ['actual_qty', 'item_code','item_name', 'description', 'uom', 'from_warehouse',
|
||||
get_items_for_material_requests(frm, warehouses) {
|
||||
let set_fields = ['actual_qty', 'item_code','item_name', 'description', 'uom', 'from_warehouse',
|
||||
'min_order_qty', 'required_bom_qty', 'quantity', 'sales_order', 'warehouse', 'projected_qty', 'ordered_qty',
|
||||
'reserved_qty_for_production', 'material_request_type'];
|
||||
|
||||
@ -335,13 +350,13 @@ frappe.ui.form.on('Production Plan', {
|
||||
callback: function(r) {
|
||||
if(r.message) {
|
||||
frm.set_value('mr_items', []);
|
||||
$.each(r.message, function(i, d) {
|
||||
var item = frm.add_child('mr_items');
|
||||
for (let key in d) {
|
||||
if (d[key] && in_list(set_fields, key)) {
|
||||
item[key] = d[key];
|
||||
r.message.forEach(row => {
|
||||
let d = frm.add_child('mr_items');
|
||||
set_fields.forEach(field => {
|
||||
if (row[field]) {
|
||||
d[field] = row[field];
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
refresh_field('mr_items');
|
||||
@ -349,13 +364,7 @@ frappe.ui.form.on('Production Plan', {
|
||||
});
|
||||
},
|
||||
|
||||
for_warehouse: function(frm) {
|
||||
if (frm.doc.mr_items && frm.doc.for_warehouse) {
|
||||
frm.trigger("get_items_for_mr");
|
||||
}
|
||||
},
|
||||
|
||||
download_materials_required: function(frm) {
|
||||
download_materials_required(frm) {
|
||||
const fields = [{
|
||||
fieldname: 'warehouses',
|
||||
fieldtype: 'Table MultiSelect',
|
||||
@ -381,7 +390,7 @@ frappe.ui.form.on('Production Plan', {
|
||||
}, __('Select Warehouses to get Stock for Materials Planning'), __('Get Stock'));
|
||||
},
|
||||
|
||||
show_progress: function(frm) {
|
||||
show_progress(frm) {
|
||||
var bars = [];
|
||||
var message = '';
|
||||
var title = '';
|
||||
@ -416,7 +425,7 @@ frappe.ui.form.on('Production Plan', {
|
||||
});
|
||||
|
||||
frappe.ui.form.on("Production Plan Item", {
|
||||
item_code: function(frm, cdt, cdn) {
|
||||
item_code(frm, cdt, cdn) {
|
||||
const row = locals[cdt][cdn];
|
||||
if (row.item_code) {
|
||||
frappe.call({
|
||||
@ -435,7 +444,7 @@ frappe.ui.form.on("Production Plan Item", {
|
||||
});
|
||||
|
||||
frappe.ui.form.on("Material Request Plan Item", {
|
||||
warehouse: function(frm, cdt, cdn) {
|
||||
warehouse(frm, cdt, cdn) {
|
||||
const row = locals[cdt][cdn];
|
||||
if (row.warehouse && row.item_code && frm.doc.company) {
|
||||
frappe.call({
|
||||
|
@ -38,6 +38,8 @@
|
||||
"get_sub_assembly_items",
|
||||
"combine_sub_items",
|
||||
"sub_assembly_items",
|
||||
"download_materials_request_plan_section_section",
|
||||
"download_materials_required",
|
||||
"material_request_planning",
|
||||
"include_non_stock_items",
|
||||
"include_subcontracted_items",
|
||||
@ -45,8 +47,8 @@
|
||||
"ignore_existing_ordered_qty",
|
||||
"column_break_25",
|
||||
"for_warehouse",
|
||||
"download_materials_required",
|
||||
"get_items_for_mr",
|
||||
"transfer_materials",
|
||||
"section_break_27",
|
||||
"mr_items",
|
||||
"other_details",
|
||||
@ -206,7 +208,7 @@
|
||||
{
|
||||
"fieldname": "material_request_planning",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Material Requirement Planning"
|
||||
"label": "Material Request Planning"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
@ -235,12 +237,12 @@
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fieldname": "download_materials_required",
|
||||
"fieldtype": "Button",
|
||||
"label": "Download Required Materials"
|
||||
"label": "Download Materials Request Plan"
|
||||
},
|
||||
{
|
||||
"fieldname": "get_items_for_mr",
|
||||
"fieldtype": "Button",
|
||||
"label": "Get Raw Materials For Production"
|
||||
"label": "Get Raw Materials for Purchase"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_27",
|
||||
@ -304,7 +306,7 @@
|
||||
{
|
||||
"fieldname": "for_warehouse",
|
||||
"fieldtype": "Link",
|
||||
"label": "Make Material Request for Warehouse",
|
||||
"label": "Raw Materials Warehouse",
|
||||
"options": "Warehouse"
|
||||
},
|
||||
{
|
||||
@ -378,13 +380,24 @@
|
||||
"fieldname": "combine_sub_items",
|
||||
"fieldtype": "Check",
|
||||
"label": "Consolidate Sub Assembly Items"
|
||||
},
|
||||
{
|
||||
"fieldname": "transfer_materials",
|
||||
"fieldtype": "Button",
|
||||
"label": "Get Raw Materials for Transfer"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "download_materials_request_plan_section_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Download Materials Request Plan Section"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-calendar",
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-03-25 09:15:25.017664",
|
||||
"modified": "2022-11-26 14:51:08.774372",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Production Plan",
|
||||
|
@ -312,6 +312,9 @@ class ProductionPlan(Document):
|
||||
def add_items(self, items):
|
||||
refs = {}
|
||||
for data in items:
|
||||
if not data.pending_qty:
|
||||
continue
|
||||
|
||||
item_details = get_item_details(data.item_code)
|
||||
if self.combine_items:
|
||||
if item_details.bom_no in refs:
|
||||
@ -518,6 +521,9 @@ class ProductionPlan(Document):
|
||||
subcontracted_po.setdefault(row.supplier, []).append(row)
|
||||
continue
|
||||
|
||||
if row.type_of_manufacturing == "Material Request":
|
||||
continue
|
||||
|
||||
work_order_data = {
|
||||
"wip_warehouse": default_warehouses.get("wip_warehouse"),
|
||||
"fg_warehouse": default_warehouses.get("fg_warehouse"),
|
||||
@ -1158,6 +1164,7 @@ def get_bin_details(row, company, for_warehouse=None, all_warehouse=False):
|
||||
|
||||
subquery = frappe.qb.from_(wh).select(wh.name).where(wh.company == company)
|
||||
|
||||
warehouse = ""
|
||||
if not all_warehouse:
|
||||
warehouse = for_warehouse or row.get("source_warehouse") or row.get("default_warehouse")
|
||||
|
||||
@ -1223,6 +1230,21 @@ def get_items_for_material_requests(doc, warehouses=None, get_parent_warehouse_d
|
||||
doc["mr_items"] = []
|
||||
|
||||
po_items = doc.get("po_items") if doc.get("po_items") else doc.get("items")
|
||||
|
||||
if doc.get("sub_assembly_items"):
|
||||
for sa_row in doc.sub_assembly_items:
|
||||
sa_row = frappe._dict(sa_row)
|
||||
if sa_row.type_of_manufacturing == "Material Request":
|
||||
po_items.append(
|
||||
frappe._dict(
|
||||
{
|
||||
"item_code": sa_row.production_item,
|
||||
"required_qty": sa_row.qty,
|
||||
"include_exploded_items": 0,
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
# Check for empty table or empty rows
|
||||
if not po_items or not [row.get("item_code") for row in po_items if row.get("item_code")]:
|
||||
frappe.throw(
|
||||
|
@ -840,6 +840,34 @@ class TestProductionPlan(FrappeTestCase):
|
||||
self.assertEqual(row.uom, "Nos")
|
||||
self.assertEqual(row.qty, 1)
|
||||
|
||||
def test_material_request_for_sub_assembly_items(self):
|
||||
from erpnext.manufacturing.doctype.bom.test_bom import create_nested_bom
|
||||
|
||||
bom_tree = {
|
||||
"Fininshed Goods1 For MR": {
|
||||
"SubAssembly1 For MR": {"SubAssembly1-1 For MR": {"ChildPart1 For MR": {}}}
|
||||
}
|
||||
}
|
||||
|
||||
parent_bom = create_nested_bom(bom_tree, prefix="")
|
||||
plan = create_production_plan(
|
||||
item_code=parent_bom.item, planned_qty=10, ignore_existing_ordered_qty=1, do_not_submit=1
|
||||
)
|
||||
|
||||
plan.get_sub_assembly_items()
|
||||
|
||||
mr_items = []
|
||||
for row in plan.sub_assembly_items:
|
||||
mr_items.append(row.production_item)
|
||||
row.type_of_manufacturing = "Material Request"
|
||||
|
||||
plan.save()
|
||||
items = get_items_for_material_requests(plan.as_dict())
|
||||
|
||||
validate_mr_items = [d.get("item_code") for d in items]
|
||||
for item_code in mr_items:
|
||||
self.assertTrue(item_code in validate_mr_items)
|
||||
|
||||
|
||||
def create_production_plan(**args):
|
||||
"""
|
||||
|
@ -83,7 +83,7 @@
|
||||
"fieldname": "warehouse",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "For Warehouse",
|
||||
"label": "FG Warehouse",
|
||||
"options": "Warehouse"
|
||||
},
|
||||
{
|
||||
@ -216,7 +216,7 @@
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-03-24 04:54:09.940224",
|
||||
"modified": "2022-11-25 14:15:40.061514",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Production Plan Item",
|
||||
|
@ -169,7 +169,7 @@
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Manufacturing Type",
|
||||
"options": "In House\nSubcontract"
|
||||
"options": "In House\nSubcontract\nMaterial Request"
|
||||
},
|
||||
{
|
||||
"fieldname": "supplier",
|
||||
@ -188,7 +188,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-01-30 21:31:10.527559",
|
||||
"modified": "2022-11-28 13:50:15.116082",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Production Plan Sub Assembly Item",
|
||||
|
@ -54,11 +54,11 @@ frappe.query_reports["Job Card Summary"] = {
|
||||
options: ["", "Open", "Work In Progress", "Completed", "On Hold"]
|
||||
},
|
||||
{
|
||||
label: __("Sales Orders"),
|
||||
fieldname: "sales_order",
|
||||
label: __("Work Orders"),
|
||||
fieldname: "work_order",
|
||||
fieldtype: "MultiSelectList",
|
||||
get_data: function(txt) {
|
||||
return frappe.db.get_link_options('Sales Order', txt);
|
||||
return frappe.db.get_link_options('Work Order', txt);
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -36,10 +36,14 @@ def get_data(filters):
|
||||
"total_time_in_mins",
|
||||
]
|
||||
|
||||
for field in ["work_order", "workstation", "operation", "status", "company"]:
|
||||
for field in ["work_order", "production_item"]:
|
||||
if filters.get(field):
|
||||
query_filters[field] = ("in", filters.get(field))
|
||||
|
||||
for field in ["workstation", "operation", "status", "company"]:
|
||||
if filters.get(field):
|
||||
query_filters[field] = filters.get(field)
|
||||
|
||||
data = frappe.get_all("Job Card", fields=fields, filters=query_filters)
|
||||
|
||||
if not data:
|
||||
|
@ -39,10 +39,14 @@ def get_data(filters):
|
||||
"lead_time",
|
||||
]
|
||||
|
||||
for field in ["sales_order", "production_item", "status", "company"]:
|
||||
for field in ["sales_order", "production_item"]:
|
||||
if filters.get(field):
|
||||
query_filters[field] = ("in", filters.get(field))
|
||||
|
||||
for field in ["status", "company"]:
|
||||
if filters.get(field):
|
||||
query_filters[field] = filters.get(field)
|
||||
|
||||
query_filters["planned_start_date"] = (">=", filters.get("from_date"))
|
||||
query_filters["planned_end_date"] = ("<=", filters.get("to_date"))
|
||||
|
||||
|
@ -169,7 +169,6 @@ erpnext.patches.v13_0.delete_old_sales_reports
|
||||
execute:frappe.delete_doc_if_exists("DocType", "Bank Reconciliation")
|
||||
execute:frappe.reload_doc("regional", "doctype", "e_invoice_settings")
|
||||
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.v13_0.delete_report_requested_items_to_order
|
||||
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
|
||||
execute:frappe.reload_doc("erpnext_integrations", "doctype", "TaxJar Settings")
|
||||
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.create_gst_payment_entry_fields #27-11-2021
|
||||
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.reset_corrupt_defaults
|
||||
erpnext.patches.v13_0.create_accounting_dimensions_for_asset_repair
|
||||
erpnext.patches.v15_0.delete_taxjar_doctypes
|
||||
|
||||
[post_model_sync]
|
||||
execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings')
|
||||
@ -317,4 +316,5 @@ erpnext.patches.v14_0.fix_subcontracting_receipt_gl_entries
|
||||
erpnext.patches.v14_0.migrate_remarks_from_gl_to_payment_ledger
|
||||
erpnext.patches.v13_0.update_schedule_type_in_loans
|
||||
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
|
||||
|
@ -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()
|
@ -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,
|
||||
)
|
@ -0,0 +1,31 @@
|
||||
import frappe
|
||||
|
||||
from erpnext.setup.doctype.incoterm.incoterm import create_incoterms
|
||||
|
||||
|
||||
def execute():
|
||||
create_incoterms()
|
||||
migrate_shipments()
|
||||
|
||||
|
||||
def migrate_shipments():
|
||||
if not frappe.db.count("Shipment"):
|
||||
return
|
||||
|
||||
OLD_VALUES = [
|
||||
"EXW (Ex Works)",
|
||||
"FCA (Free Carrier)",
|
||||
"FOB (Free On Board)",
|
||||
"FAS (Free Alongside Ship)",
|
||||
"CPT (Carriage Paid To)",
|
||||
"CIP (Carriage and Insurance Paid to)",
|
||||
"CFR (Cost and Freight)",
|
||||
"DPU (Delivered At Place Unloaded)",
|
||||
"DAP (Delivered At Place)",
|
||||
"DDP (Delivered Duty Paid)",
|
||||
]
|
||||
shipment = frappe.qb.DocType("Shipment")
|
||||
for old_value in OLD_VALUES:
|
||||
frappe.qb.update(shipment).set(shipment.incoterm, old_value[:3]).where(
|
||||
shipment.incoterm == old_value
|
||||
).run()
|
@ -25,5 +25,21 @@ def execute():
|
||||
).where(
|
||||
purchase_invoice.docstatus == 1
|
||||
).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:
|
||||
pass
|
17
erpnext/patches/v15_0/delete_taxjar_doctypes.py
Normal file
17
erpnext/patches/v15_0/delete_taxjar_doctypes.py
Normal 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",
|
||||
)
|
@ -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) {
|
||||
|
||||
// }
|
||||
});
|
@ -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
|
||||
}
|
@ -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
|
@ -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
|
@ -2,9 +2,6 @@
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
@ -48,6 +48,7 @@
|
||||
"tax_category",
|
||||
"column_break_34",
|
||||
"shipping_rule",
|
||||
"incoterm",
|
||||
"section_break_36",
|
||||
"taxes",
|
||||
"section_break_39",
|
||||
@ -1052,13 +1053,19 @@
|
||||
{
|
||||
"fieldname": "column_break_108",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "incoterm",
|
||||
"fieldtype": "Link",
|
||||
"label": "Incoterm",
|
||||
"options": "Incoterm"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-shopping-cart",
|
||||
"idx": 82,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-10-11 13:06:33.479650",
|
||||
"modified": "2022-11-17 17:20:54.984348",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Quotation",
|
||||
|
@ -63,6 +63,7 @@
|
||||
"tax_category",
|
||||
"column_break_49",
|
||||
"shipping_rule",
|
||||
"incoterm",
|
||||
"section_break_40",
|
||||
"taxes",
|
||||
"section_break_43",
|
||||
@ -1623,13 +1624,19 @@
|
||||
{
|
||||
"fieldname": "column_break_152",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "incoterm",
|
||||
"fieldtype": "Link",
|
||||
"label": "Incoterm",
|
||||
"options": "Incoterm"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-file-text",
|
||||
"idx": 105,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-10-11 13:06:10.469796",
|
||||
"modified": "2022-11-17 17:22:00.413878",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Order",
|
||||
|
8
erpnext/setup/doctype/incoterm/incoterm.js
Normal file
8
erpnext/setup/doctype/incoterm/incoterm.js
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
// frappe.ui.form.on("Incoterm", {
|
||||
// refresh(frm) {
|
||||
|
||||
// },
|
||||
// });
|
168
erpnext/setup/doctype/incoterm/incoterm.json
Normal file
168
erpnext/setup/doctype/incoterm/incoterm.json
Normal file
@ -0,0 +1,168 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:code",
|
||||
"creation": "2022-11-17 15:17:34.717467",
|
||||
"default_view": "List",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"code",
|
||||
"title",
|
||||
"description"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "code",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Code",
|
||||
"length": 3,
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "title",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Title",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Long Text",
|
||||
"label": "Description"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"group": "Selling",
|
||||
"link_doctype": "Quotation",
|
||||
"link_fieldname": "incoterm"
|
||||
},
|
||||
{
|
||||
"group": "Selling",
|
||||
"link_doctype": "Sales Order",
|
||||
"link_fieldname": "incoterm"
|
||||
},
|
||||
{
|
||||
"group": "Buying",
|
||||
"link_doctype": "Request for Quotation",
|
||||
"link_fieldname": "incoterm"
|
||||
},
|
||||
{
|
||||
"group": "Buying",
|
||||
"link_doctype": "Supplier Quotation",
|
||||
"link_fieldname": "incoterm"
|
||||
},
|
||||
{
|
||||
"group": "Buying",
|
||||
"link_doctype": "Purchase Order",
|
||||
"link_fieldname": "incoterm"
|
||||
},
|
||||
{
|
||||
"group": "Stock",
|
||||
"link_doctype": "Delivery Note",
|
||||
"link_fieldname": "incoterm"
|
||||
},
|
||||
{
|
||||
"group": "Stock",
|
||||
"link_doctype": "Purchase Receipt",
|
||||
"link_fieldname": "incoterm"
|
||||
},
|
||||
{
|
||||
"group": "Stock",
|
||||
"link_doctype": "Shipment",
|
||||
"link_fieldname": "incoterm"
|
||||
},
|
||||
{
|
||||
"group": "Accounts",
|
||||
"link_doctype": "Sales Invoice",
|
||||
"link_fieldname": "incoterm"
|
||||
},
|
||||
{
|
||||
"group": "Accounts",
|
||||
"link_doctype": "Purchase Invoice",
|
||||
"link_fieldname": "incoterm"
|
||||
}
|
||||
],
|
||||
"modified": "2022-11-17 22:35:52.084553",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Incoterm",
|
||||
"naming_rule": "By fieldname",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Stock Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"read": 1,
|
||||
"role": "Purchase User"
|
||||
},
|
||||
{
|
||||
"read": 1,
|
||||
"role": "Sales User"
|
||||
},
|
||||
{
|
||||
"read": 1,
|
||||
"role": "Accounts User"
|
||||
},
|
||||
{
|
||||
"read": 1,
|
||||
"role": "Stock User"
|
||||
}
|
||||
],
|
||||
"show_title_field_in_link": 1,
|
||||
"sort_field": "name",
|
||||
"sort_order": "ASC",
|
||||
"states": [],
|
||||
"title_field": "title",
|
||||
"translated_doctype": 1
|
||||
}
|
24
erpnext/setup/doctype/incoterm/incoterm.py
Normal file
24
erpnext/setup/doctype/incoterm/incoterm.py
Normal file
@ -0,0 +1,24 @@
|
||||
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class Incoterm(Document):
|
||||
pass
|
||||
|
||||
|
||||
def create_incoterms():
|
||||
"""Create Incoterm records from incoterms.csv."""
|
||||
import os
|
||||
from csv import DictReader
|
||||
|
||||
with open(os.path.join(os.path.dirname(__file__), "incoterms.csv"), "r") as f:
|
||||
for incoterm in DictReader(f):
|
||||
if frappe.db.exists("Incoterm", incoterm["code"]):
|
||||
continue
|
||||
|
||||
doc = frappe.new_doc("Incoterm")
|
||||
doc.update(incoterm)
|
||||
doc.save()
|
12
erpnext/setup/doctype/incoterm/incoterms.csv
Normal file
12
erpnext/setup/doctype/incoterm/incoterms.csv
Normal file
@ -0,0 +1,12 @@
|
||||
code,title
|
||||
EXW,Ex Works
|
||||
FCA,Free Carrier
|
||||
FAS,Free Alongside Ship
|
||||
FOB,Free On Board
|
||||
CPT,Carriage Paid To
|
||||
CIP,Carriage and Insurance Paid to
|
||||
CFR,Cost and Freight
|
||||
CIF,"Cost, Insurance and Freight"
|
||||
DAP,Delivered At Place
|
||||
DPU,Delivered At Place Unloaded
|
||||
DDP,Delivered Duty Paid
|
|
9
erpnext/setup/doctype/incoterm/test_incoterm.py
Normal file
9
erpnext/setup/doctype/incoterm/test_incoterm.py
Normal file
@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.tests.utils import FrappeTestCase
|
||||
|
||||
|
||||
class TestIncoterm(FrappeTestCase):
|
||||
pass
|
@ -10,6 +10,7 @@ from frappe.utils import cint
|
||||
|
||||
from erpnext.accounts.doctype.cash_flow_mapper.default_cash_flow_mapper import DEFAULT_MAPPERS
|
||||
from erpnext.setup.default_energy_point_rules import get_default_energy_point_rules
|
||||
from erpnext.setup.doctype.incoterm.incoterm import create_incoterms
|
||||
|
||||
from .default_success_action import get_default_success_action
|
||||
|
||||
@ -25,6 +26,7 @@ def after_install():
|
||||
create_default_cash_flow_mapper_templates()
|
||||
create_default_success_action()
|
||||
create_default_energy_point_rules()
|
||||
create_incoterms()
|
||||
add_company_to_session_defaults()
|
||||
add_standard_navbar_items()
|
||||
add_app_name()
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -62,6 +62,7 @@
|
||||
"tax_category",
|
||||
"column_break_39",
|
||||
"shipping_rule",
|
||||
"incoterm",
|
||||
"section_break_41",
|
||||
"taxes",
|
||||
"section_break_44",
|
||||
@ -1381,13 +1382,19 @@
|
||||
{
|
||||
"fieldname": "column_break_18",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "incoterm",
|
||||
"fieldtype": "Link",
|
||||
"label": "Incoterm",
|
||||
"options": "Incoterm"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-truck",
|
||||
"idx": 146,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-10-11 13:06:58.655635",
|
||||
"modified": "2022-11-17 17:22:42.860790",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Delivery Note",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user