Merge pull request #40681 from barredterra/ruff

chore: switch to ruff for python formatting/linting
This commit is contained in:
Akhil Narang
2024-03-27 16:23:00 +05:30
committed by GitHub
581 changed files with 4309 additions and 6450 deletions

View File

@@ -35,3 +35,6 @@ eb9ee3f79b94e594fc6dfa4f6514580e125eee8c
# js formatting
ec74a5e56617bbd76ac402451468fd4668af543d
# ruff formatting
a308792ee7fda18a681e9181f4fd00b36385bc23

View File

@@ -1,7 +1,7 @@
import sys
import requests
from urllib.parse import urlparse
import requests
WEBSITE_REPOS = [
"erpnext_com",
@@ -36,11 +36,7 @@ def is_documentation_link(word: str) -> bool:
def contains_documentation_link(body: str) -> bool:
return any(
is_documentation_link(word)
for line in body.splitlines()
for word in line.split()
)
return any(is_documentation_link(word) for line in body.splitlines() for word in line.split())
def check_pull_request(number: str) -> "tuple[int, str]":
@@ -53,12 +49,7 @@ def check_pull_request(number: str) -> "tuple[int, str]":
head_sha = (payload.get("head") or {}).get("sha")
body = (payload.get("body") or "").lower()
if (
not title.startswith("feat")
or not head_sha
or "no-docs" in body
or "backport" in body
):
if not title.startswith("feat") or not head_sha or "no-docs" in body or "backport" in body:
return 0, "Skipping documentation checks... 🏃"
if contains_documentation_link(body):

View File

@@ -2,7 +2,9 @@ import re
import sys
errors_encounter = 0
pattern = re.compile(r"_\(([\"']{,3})(?P<message>((?!\1).)*)\1(\s*,\s*context\s*=\s*([\"'])(?P<py_context>((?!\5).)*)\5)*(\s*,(\s*?.*?\n*?)*(,\s*([\"'])(?P<js_context>((?!\11).)*)\11)*)*\)")
pattern = re.compile(
r"_\(([\"']{,3})(?P<message>((?!\1).)*)\1(\s*,\s*context\s*=\s*([\"'])(?P<py_context>((?!\5).)*)\5)*(\s*,(\s*?.*?\n*?)*(,\s*([\"'])(?P<js_context>((?!\11).)*)\11)*)*\)"
)
words_pattern = re.compile(r"_{1,2}\([\"'`]{1,3}.*?[a-zA-Z]")
start_pattern = re.compile(r"_{1,2}\([f\"'`]{1,3}")
f_string_pattern = re.compile(r"_\(f[\"']")
@@ -10,14 +12,14 @@ starts_with_f_pattern = re.compile(r"_\(f")
# skip first argument
files = sys.argv[1:]
files_to_scan = [_file for _file in files if _file.endswith(('.py', '.js'))]
files_to_scan = [_file for _file in files if _file.endswith((".py", ".js"))]
for _file in files_to_scan:
with open(_file, 'r') as f:
print(f'Checking: {_file}')
with open(_file) as f:
print(f"Checking: {_file}")
file_lines = f.readlines()
for line_number, line in enumerate(file_lines, 1):
if 'frappe-lint: disable-translate' in line:
if "frappe-lint: disable-translate" in line:
continue
start_matches = start_pattern.search(line)
@@ -28,7 +30,9 @@ for _file in files_to_scan:
has_f_string = f_string_pattern.search(line)
if has_f_string:
errors_encounter += 1
print(f'\nF-strings are not supported for translations at line number {line_number}\n{line.strip()[:100]}')
print(
f"\nF-strings are not supported for translations at line number {line_number}\n{line.strip()[:100]}"
)
continue
else:
continue
@@ -36,25 +40,29 @@ for _file in files_to_scan:
match = pattern.search(line)
error_found = False
if not match and line.endswith((',\n', '[\n')):
if not match and line.endswith((",\n", "[\n")):
# concat remaining text to validate multiline pattern
line = "".join(file_lines[line_number - 1:])
line = line[start_matches.start() + 1:]
line = "".join(file_lines[line_number - 1 :])
line = line[start_matches.start() + 1 :]
match = pattern.match(line)
if not match:
error_found = True
print(f'\nTranslation syntax error at line number {line_number}\n{line.strip()[:100]}')
print(f"\nTranslation syntax error at line number {line_number}\n{line.strip()[:100]}")
if not error_found and not words_pattern.search(line):
error_found = True
print(f'\nTranslation is useless because it has no words at line number {line_number}\n{line.strip()[:100]}')
print(
f"\nTranslation is useless because it has no words at line number {line_number}\n{line.strip()[:100]}"
)
if error_found:
errors_encounter += 1
if errors_encounter > 0:
print('\nVisit "https://frappeframework.com/docs/user/en/translations" to learn about valid translation strings.')
print(
'\nVisit "https://frappeframework.com/docs/user/en/translations" to learn about valid translation strings.'
)
sys.exit(1)
else:
print('\nGood To Go!')
print("\nGood To Go!")

View File

@@ -32,7 +32,7 @@ jobs:
steps:
- name: Clone
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Check for valid Python & Merge Conflicts
run: |
@@ -43,12 +43,12 @@ jobs:
fi
- name: Setup Python
uses: "actions/setup-python@v4"
uses: actions/setup-python@v5
with:
python-version: '3.10'
python-version: '3.11'
- name: Setup Node
uses: actions/setup-node@v2
uses: actions/setup-node@v4
with:
node-version: 18
check-latest: true
@@ -57,7 +57,7 @@ jobs:
run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts
- name: Cache pip
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/*requirements.txt', '**/pyproject.toml') }}
@@ -66,7 +66,7 @@ jobs:
${{ runner.os }}-
- name: Cache node modules
uses: actions/cache@v2
uses: actions/cache@v4
env:
cache-name: cache-node-modules
with:
@@ -81,7 +81,7 @@ jobs:
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v2
- uses: actions/cache@v4
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}

View File

@@ -54,12 +54,12 @@ jobs:
steps:
- name: Clone
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: '3.11'
python-version: '3.12'
- name: Check for valid Python & Merge Conflicts
run: |
@@ -70,7 +70,7 @@ jobs:
fi
- name: Setup Node
uses: actions/setup-node@v2
uses: actions/setup-node@v4
with:
node-version: 18
check-latest: true
@@ -79,7 +79,7 @@ jobs:
run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts
- name: Cache pip
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/*requirements.txt', '**/pyproject.toml') }}
@@ -88,7 +88,7 @@ jobs:
${{ runner.os }}-
- name: Cache node modules
uses: actions/cache@v2
uses: actions/cache@v4
env:
cache-name: cache-node-modules
with:
@@ -103,7 +103,7 @@ jobs:
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v2
- uses: actions/cache@v4
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
@@ -144,13 +144,13 @@ jobs:
if: ${{ github.event_name != 'pull_request' }}
steps:
- name: Clone
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Download artifacts
uses: actions/download-artifact@v3
- name: Upload coverage data
uses: codecov/codecov-action@v2
uses: codecov/codecov-action@v4
with:
name: MariaDB
token: ${{ secrets.CODECOV_TOKEN }}

View File

@@ -41,12 +41,12 @@ jobs:
steps:
- name: Clone
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: '3.10'
python-version: '3.12'
- name: Check for valid Python & Merge Conflicts
run: |
@@ -57,7 +57,7 @@ jobs:
fi
- name: Setup Node
uses: actions/setup-node@v2
uses: actions/setup-node@v4
with:
node-version: 18
check-latest: true
@@ -66,7 +66,7 @@ jobs:
run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts
- name: Cache pip
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/*requirements.txt', '**/pyproject.toml') }}
@@ -75,7 +75,7 @@ jobs:
${{ runner.os }}-
- name: Cache node modules
uses: actions/cache@v2
uses: actions/cache@v4
env:
cache-name: cache-node-modules
with:
@@ -90,7 +90,7 @@ jobs:
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v2
- uses: actions/cache@v4
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}

View File

@@ -55,28 +55,15 @@ repos:
erpnext/templates/includes/.*
)$
- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.2.0
hooks:
- id: flake8
additional_dependencies: [
'flake8-bugbear',
'flake8-tuple',
]
args: ['--config', '.github/helper/.flake8_strict']
exclude: ".*setup.py$"
- id: ruff
name: "Run ruff linter and apply fixes"
args: ["--fix"]
- repo: https://github.com/adityahase/black
rev: 9cb0a69f4d0030cdf687eddf314468b39ed54119
hooks:
- id: black
additional_dependencies: ['click==8.0.4']
- repo: https://github.com/PyCQA/isort
rev: 5.12.0
hooks:
- id: isort
exclude: ".*setup.py$"
- id: ruff-format
name: "Format Python code"
ci:

View File

@@ -37,9 +37,7 @@ def get_default_cost_center(company):
if not frappe.flags.company_cost_center:
frappe.flags.company_cost_center = {}
if company not in frappe.flags.company_cost_center:
frappe.flags.company_cost_center[company] = frappe.get_cached_value(
"Company", company, "cost_center"
)
frappe.flags.company_cost_center[company] = frappe.get_cached_value("Company", company, "cost_center")
return frappe.flags.company_cost_center[company]

View File

@@ -11,14 +11,14 @@ class ERPNextAddress(Address):
def validate(self):
self.validate_reference()
self.update_compnay_address()
super(ERPNextAddress, self).validate()
super().validate()
def link_address(self):
"""Link address based on owner"""
if self.is_your_company_address:
return
return super(ERPNextAddress, self).link_address()
return super().link_address()
def update_compnay_address(self):
for link in self.get("links"):
@@ -26,11 +26,11 @@ class ERPNextAddress(Address):
self.is_your_company_address = 1
def validate_reference(self):
if self.is_your_company_address and not [
row for row in self.links if row.link_doctype == "Company"
]:
if self.is_your_company_address and not [row for row in self.links if row.link_doctype == "Company"]:
frappe.throw(
_("Address needs to be linked to a Company. Please add a row for Company in the Links table."),
_(
"Address needs to be linked to a Company. Please add a row for Company in the Links table."
),
title=_("Company Not Linked"),
)

View File

@@ -37,7 +37,7 @@ def get(
filters = frappe.parse_json(filters) or frappe.parse_json(chart.filters_json)
account = filters.get("account")
company = filters.get("company")
filters.get("company")
if not account and chart_name:
frappe.throw(
@@ -83,7 +83,6 @@ def build_result(account, dates, gl_entries):
# get balances in debit
for entry in gl_entries:
# entry date is after the current pointer, so move the pointer forward
while getdate(entry.posting_date) > result[date_index][0]:
date_index += 1
@@ -133,8 +132,6 @@ def get_dates_from_timegrain(from_date, to_date, timegrain):
dates = [get_period_ending(from_date, timegrain)]
while getdate(dates[-1]) < getdate(to_date):
date = get_period_ending(
add_to_date(dates[-1], years=years, months=months, days=days), timegrain
)
date = get_period_ending(add_to_date(dates[-1], years=years, months=months, days=days), timegrain)
dates.append(date)
return dates

View File

@@ -24,14 +24,10 @@ from erpnext.accounts.utils import get_account_currency
def validate_service_stop_date(doc):
"""Validates service_stop_date for Purchase Invoice and Sales Invoice"""
enable_check = (
"enable_deferred_revenue" if doc.doctype == "Sales Invoice" else "enable_deferred_expense"
)
enable_check = "enable_deferred_revenue" if doc.doctype == "Sales Invoice" else "enable_deferred_expense"
old_stop_dates = {}
old_doc = frappe.db.get_all(
"{0} Item".format(doc.doctype), {"parent": doc.name}, ["name", "service_stop_date"]
)
old_doc = frappe.db.get_all(f"{doc.doctype} Item", {"parent": doc.name}, ["name", "service_stop_date"])
for d in old_doc:
old_stop_dates[d.name] = d.service_stop_date or ""
@@ -62,16 +58,14 @@ def build_conditions(process_type, account, company):
)
if account:
conditions += "AND %s='%s'" % (deferred_account, account)
conditions += f"AND {deferred_account}='{account}'"
elif company:
conditions += f"AND p.company = {frappe.db.escape(company)}"
return conditions
def convert_deferred_expense_to_expense(
deferred_process, start_date=None, end_date=None, conditions=""
):
def convert_deferred_expense_to_expense(deferred_process, start_date=None, end_date=None, conditions=""):
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
if not start_date:
@@ -81,16 +75,14 @@ def convert_deferred_expense_to_expense(
# check for the purchase invoice for which GL entries has to be done
invoices = frappe.db.sql_list(
"""
f"""
select distinct item.parent
from `tabPurchase Invoice Item` item, `tabPurchase Invoice` p
where item.service_start_date<=%s and item.service_end_date>=%s
and item.enable_deferred_expense = 1 and item.parent=p.name
and item.docstatus = 1 and ifnull(item.amount, 0) > 0
{0}
""".format(
conditions
),
{conditions}
""",
(end_date, start_date),
) # nosec
@@ -103,9 +95,7 @@ def convert_deferred_expense_to_expense(
send_mail(deferred_process)
def convert_deferred_revenue_to_income(
deferred_process, start_date=None, end_date=None, conditions=""
):
def convert_deferred_revenue_to_income(deferred_process, start_date=None, end_date=None, conditions=""):
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
if not start_date:
@@ -115,16 +105,14 @@ def convert_deferred_revenue_to_income(
# check for the sales invoice for which GL entries has to be done
invoices = frappe.db.sql_list(
"""
f"""
select distinct item.parent
from `tabSales Invoice Item` item, `tabSales Invoice` p
where item.service_start_date<=%s and item.service_end_date>=%s
and item.enable_deferred_revenue = 1 and item.parent=p.name
and item.docstatus = 1 and ifnull(item.amount, 0) > 0
{0}
""".format(
conditions
),
{conditions}
""",
(end_date, start_date),
) # nosec
@@ -243,9 +231,7 @@ def calculate_monthly_amount(
already_booked_amount, already_booked_amount_in_account_currency = get_already_booked_amount(
doc, item
)
base_amount = flt(
item.base_net_amount - already_booked_amount, item.precision("base_net_amount")
)
base_amount = flt(item.base_net_amount - already_booked_amount, item.precision("base_net_amount"))
if account_currency == doc.company_currency:
amount = base_amount
else:
@@ -265,17 +251,13 @@ def calculate_amount(doc, item, last_gl_entry, total_days, total_booking_days, a
if account_currency == doc.company_currency:
amount = base_amount
else:
amount = flt(
item.net_amount * total_booking_days / flt(total_days), item.precision("net_amount")
)
amount = flt(item.net_amount * total_booking_days / flt(total_days), item.precision("net_amount"))
else:
already_booked_amount, already_booked_amount_in_account_currency = get_already_booked_amount(
doc, item
)
base_amount = flt(
item.base_net_amount - already_booked_amount, item.precision("base_net_amount")
)
base_amount = flt(item.base_net_amount - already_booked_amount, item.precision("base_net_amount"))
if account_currency == doc.company_currency:
amount = base_amount
else:
@@ -296,26 +278,22 @@ def get_already_booked_amount(doc, item):
gl_entries_details = frappe.db.sql(
"""
select sum({0}) as total_credit, sum({1}) as total_credit_in_account_currency, voucher_detail_no
select sum({}) as total_credit, sum({}) as total_credit_in_account_currency, voucher_detail_no
from `tabGL Entry` where company=%s and account=%s and voucher_type=%s and voucher_no=%s and voucher_detail_no=%s
and is_cancelled = 0
group by voucher_detail_no
""".format(
total_credit_debit, total_credit_debit_currency
),
""".format(total_credit_debit, total_credit_debit_currency),
(doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name),
as_dict=True,
)
journal_entry_details = frappe.db.sql(
"""
SELECT sum(c.{0}) as total_credit, sum(c.{1}) as total_credit_in_account_currency, reference_detail_no
SELECT sum(c.{}) as total_credit, sum(c.{}) as total_credit_in_account_currency, reference_detail_no
FROM `tabJournal Entry` p , `tabJournal Entry Account` c WHERE p.name = c.parent and
p.company = %s and c.account=%s and c.reference_type=%s and c.reference_name=%s and c.reference_detail_no=%s
and p.docstatus < 2 group by reference_detail_no
""".format(
total_credit_debit, total_credit_debit_currency
),
""".format(total_credit_debit, total_credit_debit_currency),
(doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name),
as_dict=True,
)
@@ -337,9 +315,7 @@ def get_already_booked_amount(doc, item):
def book_deferred_income_or_expense(doc, deferred_process, posting_date=None):
enable_check = (
"enable_deferred_revenue" if doc.doctype == "Sales Invoice" else "enable_deferred_expense"
)
enable_check = "enable_deferred_revenue" if doc.doctype == "Sales Invoice" else "enable_deferred_expense"
accounts_frozen_upto = frappe.db.get_single_value("Accounts Settings", "acc_frozen_upto")
@@ -440,9 +416,7 @@ def book_deferred_income_or_expense(doc, deferred_process, posting_date=None):
via_journal_entry = cint(
frappe.db.get_singles_value("Accounts Settings", "book_deferred_entries_via_journal_entry")
)
submit_journal_entry = cint(
frappe.db.get_singles_value("Accounts Settings", "submit_journal_entries")
)
submit_journal_entry = cint(frappe.db.get_singles_value("Accounts Settings", "submit_journal_entries"))
book_deferred_entries_based_on = frappe.db.get_singles_value(
"Accounts Settings", "book_deferred_entries_based_on"
)
@@ -462,9 +436,7 @@ def process_deferred_accounting(posting_date=None):
posting_date = today()
if not cint(
frappe.db.get_singles_value(
"Accounts Settings", "automatically_process_deferred_accounting_entry"
)
frappe.db.get_singles_value("Accounts Settings", "automatically_process_deferred_accounting_entry")
):
return
@@ -587,16 +559,13 @@ def book_revenue_via_journal_entry(
deferred_process=None,
submit="No",
):
if amount == 0:
return
journal_entry = frappe.new_doc("Journal Entry")
journal_entry.posting_date = posting_date
journal_entry.company = doc.company
journal_entry.voucher_type = (
"Deferred Revenue" if doc.doctype == "Sales Invoice" else "Deferred Expense"
)
journal_entry.voucher_type = "Deferred Revenue" if doc.doctype == "Sales Invoice" else "Deferred Expense"
journal_entry.process_deferred_accounting = deferred_process
debit_entry = {
@@ -645,7 +614,6 @@ def book_revenue_via_journal_entry(
def get_deferred_booking_accounts(doctype, voucher_detail_no, dr_or_cr):
if doctype == "Sales Invoice":
credit_account, debit_account = frappe.db.get_value(
"Sales Invoice Item",

View File

@@ -88,12 +88,10 @@ class Account(NestedSet):
if frappe.local.flags.ignore_update_nsm:
return
else:
super(Account, self).on_update()
super().on_update()
def onload(self):
frozen_accounts_modifier = frappe.db.get_single_value(
"Accounts Settings", "frozen_accounts_modifier"
)
frozen_accounts_modifier = frappe.db.get_single_value("Accounts Settings", "frozen_accounts_modifier")
if not frozen_accounts_modifier or frozen_accounts_modifier in frappe.get_roles():
self.set_onload("can_freeze_account", True)
@@ -218,9 +216,7 @@ class Account(NestedSet):
def validate_root_company_and_sync_account_to_children(self):
# ignore validation while creating new compnay or while syncing to child companies
if (
frappe.local.flags.ignore_root_company_validation or self.flags.ignore_root_company_validation
):
if frappe.local.flags.ignore_root_company_validation or self.flags.ignore_root_company_validation:
return
ancestors = get_root_company(self.company)
if ancestors:
@@ -418,7 +414,7 @@ class Account(NestedSet):
if self.check_gle_exists():
throw(_("Account with existing transaction can not be deleted"))
super(Account, self).on_trash(True)
super().on_trash(True)
@frappe.whitelist()
@@ -426,9 +422,8 @@ class Account(NestedSet):
def get_parent_account(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql(
"""select name from tabAccount
where is_group = 1 and docstatus != 2 and company = %s
and %s like %s order by name limit %s offset %s"""
% ("%s", searchfield, "%s", "%s", "%s"),
where is_group = 1 and docstatus != 2 and company = {}
and {} like {} order by name limit {} offset {}""".format("%s", searchfield, "%s", "%s", "%s"),
(filters["company"], "%%%s%%" % txt, page_len, start),
as_list=1,
)
@@ -594,7 +589,5 @@ def sync_update_account_number_in_child(
if old_acc_number:
filters["account_number"] = old_acc_number
for d in frappe.db.get_values(
"Account", filters=filters, fieldname=["company", "name"], as_dict=True
):
for d in frappe.db.get_values("Account", filters=filters, fieldname=["company", "name"], as_dict=True):
update_account_number(d["name"], account_name, account_number, from_descendant=True)

View File

@@ -31,7 +31,6 @@ def create_charts(
"tax_rate",
"account_currency",
]:
account_number = cstr(child.get("account_number")).strip()
account_name, account_name_in_db = add_suffix_if_duplicate(
account_name, account_number, accounts
@@ -39,7 +38,9 @@ def create_charts(
is_group = identify_is_group(child)
report_type = (
"Balance Sheet" if root_type in ["Asset", "Liability", "Equity"] else "Profit and Loss"
"Balance Sheet"
if root_type in ["Asset", "Liability", "Equity"]
else "Profit and Loss"
)
account = frappe.get_doc(
@@ -141,7 +142,7 @@ def get_chart(chart_template, existing_company=None):
for fname in os.listdir(path):
fname = frappe.as_unicode(fname)
if fname.endswith(".json"):
with open(os.path.join(path, fname), "r") as f:
with open(os.path.join(path, fname)) as f:
chart = f.read()
if chart and json.loads(chart).get("name") == chart_template:
return json.loads(chart).get("tree")
@@ -173,7 +174,7 @@ def get_charts_for_country(country, with_standard=False):
for fname in os.listdir(path):
fname = frappe.as_unicode(fname)
if (fname.startswith(country_code) or fname.startswith(country)) and fname.endswith(".json"):
with open(os.path.join(path, fname), "r") as f:
with open(os.path.join(path, fname)) as f:
_get_chart_name(f.read())
# if more than one charts, returned then add the standard
@@ -249,7 +250,13 @@ def validate_bank_account(coa, bank_account):
def _get_account_names(account_master):
for account_name, child in account_master.items():
if account_name not in ["account_number", "account_type", "root_type", "is_group", "tax_rate"]:
if account_name not in [
"account_number",
"account_type",
"root_type",
"is_group",
"tax_rate",
]:
accounts.append(account_name)
_get_account_names(child)

View File

@@ -261,28 +261,20 @@ class TestAccount(unittest.TestCase):
acc.insert()
self.assertTrue(
frappe.db.exists(
"Account", {"account_name": "Test Group Account", "company": "_Test Company 4"}
)
frappe.db.exists("Account", {"account_name": "Test Group Account", "company": "_Test Company 4"})
)
self.assertTrue(
frappe.db.exists(
"Account", {"account_name": "Test Group Account", "company": "_Test Company 5"}
)
frappe.db.exists("Account", {"account_name": "Test Group Account", "company": "_Test Company 5"})
)
# Try renaming child company account
acc_tc_5 = frappe.db.get_value(
"Account", {"account_name": "Test Group Account", "company": "_Test Company 5"}
)
self.assertRaises(
frappe.ValidationError, update_account_number, acc_tc_5, "Test Modified Account"
)
self.assertRaises(frappe.ValidationError, update_account_number, acc_tc_5, "Test Modified Account")
# Rename child company account with allow_account_creation_against_child_company enabled
frappe.db.set_value(
"Company", "_Test Company 5", "allow_account_creation_against_child_company", 1
)
frappe.db.set_value("Company", "_Test Company 5", "allow_account_creation_against_child_company", 1)
update_account_number(acc_tc_5, "Test Modified Account")
self.assertTrue(
@@ -291,9 +283,7 @@ class TestAccount(unittest.TestCase):
)
)
frappe.db.set_value(
"Company", "_Test Company 5", "allow_account_creation_against_child_company", 0
)
frappe.db.set_value("Company", "_Test Company 5", "allow_account_creation_against_child_company", 0)
to_delete = [
"Test Group Account - _TC3",
@@ -318,9 +308,7 @@ class TestAccount(unittest.TestCase):
self.assertEqual(acc.account_currency, "INR")
# Make a JV against this account
make_journal_entry(
"Test Currency Account - _TC", "Miscellaneous Expenses - _TC", 100, submit=True
)
make_journal_entry("Test Currency Account - _TC", "Miscellaneous Expenses - _TC", 100, submit=True)
acc.account_currency = "USD"
self.assertRaises(frappe.ValidationError, acc.save)

View File

@@ -40,16 +40,12 @@ class AccountClosingBalance(Document):
def make_closing_entries(closing_entries, voucher_name, company, closing_date):
accounting_dimensions = get_accounting_dimensions()
previous_closing_entries = get_previous_closing_entries(
company, closing_date, accounting_dimensions
)
previous_closing_entries = get_previous_closing_entries(company, closing_date, accounting_dimensions)
combined_entries = closing_entries + previous_closing_entries
merged_entries = aggregate_with_last_account_closing_balance(
combined_entries, accounting_dimensions
)
merged_entries = aggregate_with_last_account_closing_balance(combined_entries, accounting_dimensions)
for key, value in merged_entries.items():
for _key, value in merged_entries.items():
cle = frappe.new_doc("Account Closing Balance")
cle.update(value)
cle.update(value["dimensions"])

View File

@@ -40,7 +40,8 @@ class AccountingDimension(Document):
self.set_fieldname_and_label()
def validate(self):
if self.document_type in core_doctypes_list + (
if self.document_type in (
*core_doctypes_list,
"Accounting Dimension",
"Project",
"Cost Center",
@@ -48,13 +49,10 @@ class AccountingDimension(Document):
"Company",
"Account",
):
msg = _("Not allowed to create accounting dimension for {0}").format(self.document_type)
frappe.throw(msg)
exists = frappe.db.get_value(
"Accounting Dimension", {"document_type": self.document_type}, ["name"]
)
exists = frappe.db.get_value("Accounting Dimension", {"document_type": self.document_type}, ["name"])
if exists and self.is_new():
frappe.throw(_("Document Type already used as a dimension"))
@@ -113,7 +111,6 @@ def make_dimension_in_accounting_doctypes(doc, doclist=None):
repostable_doctypes = get_allowed_types_from_settings()
for doctype in doclist:
if (doc_count + 1) % 2 == 0:
insert_after_field = "dimension_col_break"
else:
@@ -148,7 +145,7 @@ def add_dimension_to_budget_doctype(df, doc):
df.update(
{
"insert_after": "cost_center",
"depends_on": "eval:doc.budget_against == '{0}'".format(doc.document_type),
"depends_on": f"eval:doc.budget_against == '{doc.document_type}'",
}
)
@@ -182,19 +179,17 @@ def delete_accounting_dimension(doc):
frappe.db.sql(
"""
DELETE FROM `tabCustom Field`
WHERE fieldname = %s
AND dt IN (%s)"""
% ("%s", ", ".join(["%s"] * len(doclist))), # nosec
tuple([doc.fieldname] + doclist),
WHERE fieldname = {}
AND dt IN ({})""".format("%s", ", ".join(["%s"] * len(doclist))), # nosec
tuple([doc.fieldname, *doclist]),
)
frappe.db.sql(
"""
DELETE FROM `tabProperty Setter`
WHERE field_name = %s
AND doc_type IN (%s)"""
% ("%s", ", ".join(["%s"] * len(doclist))), # nosec
tuple([doc.fieldname] + doclist),
WHERE field_name = {}
AND doc_type IN ({})""".format("%s", ", ".join(["%s"] * len(doclist))), # nosec
tuple([doc.fieldname, *doclist]),
)
budget_against_property = frappe.get_doc("Property Setter", "Budget-budget_against-options")
@@ -243,7 +238,6 @@ def get_doctypes_with_dimensions():
def get_accounting_dimensions(as_list=True, filters=None):
if not filters:
filters = {"disabled": 0}
@@ -274,7 +268,6 @@ def get_checks_for_pl_and_bs_accounts():
def get_dimension_with_children(doctype, dimensions):
if isinstance(dimensions, str):
dimensions = [dimensions]
@@ -282,9 +275,7 @@ def get_dimension_with_children(doctype, dimensions):
for dimension in dimensions:
lft, rgt = frappe.db.get_value(doctype, dimension, ["lft", "rgt"])
children = frappe.get_all(
doctype, filters={"lft": [">=", lft], "rgt": ["<=", rgt]}, order_by="lft"
)
children = frappe.get_all(doctype, filters={"lft": [">=", lft], "rgt": ["<=", rgt]}, order_by="lft")
all_dimensions += [c.name for c in children]
return all_dimensions
@@ -292,14 +283,10 @@ def get_dimension_with_children(doctype, dimensions):
@frappe.whitelist()
def get_dimensions(with_cost_center_and_project=False):
c = frappe.qb.DocType("Accounting Dimension Detail")
p = frappe.qb.DocType("Accounting Dimension")
dimension_filters = (
frappe.qb.from_(p)
.select(p.label, p.fieldname, p.document_type)
.where(p.disabled == 0)
.run(as_dict=1)
frappe.qb.from_(p).select(p.label, p.fieldname, p.document_type).where(p.disabled == 0).run(as_dict=1)
)
default_dimensions = (
frappe.qb.from_(c)

View File

@@ -57,9 +57,7 @@ class TestAccountingDimensionFilter(unittest.TestCase):
def create_accounting_dimension_filter():
if not frappe.db.get_value(
"Accounting Dimension Filter", {"accounting_dimension": "Cost Center"}
):
if not frappe.db.get_value("Accounting Dimension Filter", {"accounting_dimension": "Cost Center"}):
frappe.get_doc(
{
"doctype": "Accounting Dimension Filter",

View File

@@ -84,7 +84,10 @@ class AccountingPeriod(Document):
for doctype_for_closing in self.get_doctypes_for_closing():
self.append(
"closed_documents",
{"document_type": doctype_for_closing.document_type, "closed": doctype_for_closing.closed},
{
"document_type": doctype_for_closing.document_type,
"closed": doctype_for_closing.closed,
},
)

View File

@@ -34,9 +34,7 @@ class TestAccountingPeriod(unittest.TestCase):
ap1 = create_accounting_period(period_name="Test Accounting Period 2")
ap1.save()
doc = create_sales_invoice(
do_not_save=1, cost_center="_Test Company - _TC", warehouse="Stores - _TC"
)
doc = create_sales_invoice(do_not_save=1, cost_center="_Test Company - _TC", warehouse="Stores - _TC")
self.assertRaises(ClosedAccountingPeriod, doc.save)
def tearDown(self):

View File

@@ -37,11 +37,11 @@ class TestBankAccount(unittest.TestCase):
try:
bank_account.validate_iban()
except ValidationError:
msg = "BankAccount.validate_iban() failed for valid IBAN {}".format(iban)
msg = f"BankAccount.validate_iban() failed for valid IBAN {iban}"
self.fail(msg=msg)
for not_iban in invalid_ibans:
bank_account.iban = not_iban
msg = "BankAccount.validate_iban() accepted invalid IBAN {}".format(not_iban)
msg = f"BankAccount.validate_iban() accepted invalid IBAN {not_iban}"
with self.assertRaises(ValidationError, msg=msg):
bank_account.validate_iban()

View File

@@ -127,7 +127,7 @@ def get_payment_entries_for_bank_clearance(
condition = "and (clearance_date IS NULL or clearance_date='0000-00-00')"
journal_entries = frappe.db.sql(
"""
f"""
select
"Journal Entry" as payment_document, t1.name as payment_entry,
t1.cheque_no as cheque_number, t1.cheque_date,
@@ -141,9 +141,7 @@ def get_payment_entries_for_bank_clearance(
and ifnull(t1.is_opening, 'No') = 'No' {condition}
group by t2.account, t1.name
order by t1.posting_date ASC, t1.name DESC
""".format(
condition=condition
),
""",
{"account": account, "from": from_date, "to": to_date},
as_dict=1,
)
@@ -152,7 +150,7 @@ def get_payment_entries_for_bank_clearance(
condition += "and bank_account = %(bank_account)s"
payment_entries = frappe.db.sql(
"""
f"""
select
"Payment Entry" as payment_document, name as payment_entry,
reference_no as cheque_number, reference_date as cheque_date,
@@ -167,9 +165,7 @@ def get_payment_entries_for_bank_clearance(
{condition}
order by
posting_date ASC, name DESC
""".format(
condition=condition
),
""",
{
"account": account,
"from": from_date,
@@ -239,10 +235,7 @@ def get_payment_entries_for_bank_clearance(
).run(as_dict=True)
entries = (
list(payment_entries)
+ list(journal_entries)
+ list(pos_sales_invoices)
+ list(pos_purchase_invoices)
list(payment_entries) + list(journal_entries) + list(pos_sales_invoices) + list(pos_purchase_invoices)
)
return entries

View File

@@ -68,9 +68,7 @@ class TestBankClearance(unittest.TestCase):
)
loan.submit()
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=getdate())
repayment_entry = create_repayment_entry(
loan.name, "_Test Customer", getdate(), loan.loan_amount
)
repayment_entry = create_repayment_entry(loan.name, "_Test Customer", getdate(), loan.loan_amount)
repayment_entry.save()
repayment_entry.submit()

View File

@@ -81,9 +81,7 @@ def get_bank_transactions(bank_account, from_date=None, to_date=None):
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")
filters = frappe._dict(
{"account": account, "report_date": till_date, "include_pos_transactions": 1}
)
filters = frappe._dict({"account": account, "report_date": till_date, "include_pos_transactions": 1})
data = get_entries(filters)
balance_as_per_system = get_balance_on(filters["account"], filters["report_date"])
@@ -96,10 +94,7 @@ def get_account_balance(bank_account, till_date):
amounts_not_reflected_in_system = get_amounts_not_reflected_in_system(filters)
bank_bal = (
flt(balance_as_per_system)
- flt(total_debit)
+ flt(total_credit)
+ amounts_not_reflected_in_system
flt(balance_as_per_system) - flt(total_debit) + flt(total_credit) + amounts_not_reflected_in_system
)
return bank_bal
@@ -538,9 +533,7 @@ def check_matching(
for query in queries:
matching_vouchers.extend(query.run(as_dict=True))
return (
sorted(matching_vouchers, key=lambda x: x["rank"], reverse=True) if matching_vouchers else []
)
return sorted(matching_vouchers, key=lambda x: x["rank"], reverse=True) if matching_vouchers else []
def get_queries(
@@ -654,17 +647,13 @@ def get_bt_matching_query(exact_match, transaction):
amount_rank = frappe.qb.terms.Case().when(amount_equality, 1).else_(0)
amount_condition = amount_equality if exact_match else getattr(bt, field) > 0.0
ref_rank = (
frappe.qb.terms.Case().when(bt.reference_number == transaction.reference_number, 1).else_(0)
)
ref_rank = frappe.qb.terms.Case().when(bt.reference_number == transaction.reference_number, 1).else_(0)
unallocated_rank = (
frappe.qb.terms.Case().when(bt.unallocated_amount == transaction.unallocated_amount, 1).else_(0)
)
party_condition = (
(bt.party_type == transaction.party_type)
& (bt.party == transaction.party)
& bt.party.isnotnull()
(bt.party_type == transaction.party_type) & (bt.party == transaction.party) & bt.party.isnotnull()
)
party_rank = frappe.qb.terms.Case().when(party_condition, 1).else_(0)
@@ -716,9 +705,7 @@ def get_pe_matching_query(
amount_condition = amount_equality if exact_match else pe.paid_amount > 0.0
party_condition = (
(pe.party_type == transaction.party_type)
& (pe.party == transaction.party)
& pe.party.isnotnull()
(pe.party_type == transaction.party_type) & (pe.party == transaction.party) & pe.party.isnotnull()
)
party_rank = frappe.qb.terms.Case().when(party_condition, 1).else_(0)
@@ -749,7 +736,7 @@ def get_pe_matching_query(
.orderby(pe.reference_date if cint(filter_by_reference_date) else pe.posting_date)
)
if frappe.flags.auto_reconcile_vouchers == True:
if frappe.flags.auto_reconcile_vouchers is True:
query = query.where(ref_condition)
return query
@@ -810,7 +797,7 @@ def get_je_matching_query(
.orderby(je.cheque_date if cint(filter_by_reference_date) else je.posting_date)
)
if frappe.flags.auto_reconcile_vouchers == True:
if frappe.flags.auto_reconcile_vouchers is True:
query = query.where(ref_condition)
return query

View File

@@ -1,12 +1,11 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe import qb
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import add_days, flt, getdate, today
from frappe.tests.utils import FrappeTestCase
from frappe.utils import add_days, today
from erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool import (
auto_reconcile_vouchers,
@@ -22,7 +21,7 @@ class TestBankReconciliationTool(AccountsTestMixin, FrappeTestCase):
self.create_customer()
self.clear_old_entries()
bank_dt = qb.DocType("Bank")
q = qb.from_(bank_dt).delete().where(bank_dt.name == "HDFC").run()
qb.from_(bank_dt).delete().where(bank_dt.name == "HDFC").run()
self.create_bank_account()
def tearDown(self):

View File

@@ -45,7 +45,7 @@ class BankStatementImport(DataImport):
# end: auto-generated types
def __init__(self, *args, **kwargs):
super(BankStatementImport, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
def validate(self):
doc_before_save = self.get_doc_before_save()
@@ -54,7 +54,6 @@ class BankStatementImport(DataImport):
or (doc_before_save and doc_before_save.import_file != self.import_file)
or (doc_before_save and doc_before_save.google_sheets_url != self.google_sheets_url)
):
template_options_dict = {}
column_to_field_map = {}
bank = frappe.get_doc("Bank", self.bank)
@@ -69,7 +68,6 @@ class BankStatementImport(DataImport):
self.validate_google_sheets_url()
def start_import(self):
preview = frappe.get_doc("Bank Statement Import", self.name).get_preview_from_template(
self.import_file, self.google_sheets_url
)
@@ -126,7 +124,7 @@ def download_errored_template(data_import_name):
def parse_data_from_template(raw_data):
data = []
for i, row in enumerate(raw_data):
for _i, row in enumerate(raw_data):
if all(v in INVALID_VALUES for v in row):
# empty row
continue
@@ -136,9 +134,7 @@ def parse_data_from_template(raw_data):
return data
def start_import(
data_import, bank_account, import_file_path, google_sheets_url, bank, template_options
):
def start_import(data_import, bank_account, import_file_path, google_sheets_url, bank, template_options):
"""This method runs in background job"""
update_mapping_db(bank, template_options)

View File

@@ -1,5 +1,3 @@
from typing import Tuple, Union
import frappe
from frappe.utils import flt
from rapidfuzz import fuzz, process
@@ -19,7 +17,7 @@ class AutoMatchParty:
def get(self, key):
return self.__dict__.get(key, None)
def match(self) -> Union[Tuple, None]:
def match(self) -> tuple | None:
result = None
result = AutoMatchbyAccountIBAN(
bank_party_account_number=self.bank_party_account_number,
@@ -50,7 +48,7 @@ class AutoMatchbyAccountIBAN:
result = self.match_account_in_party()
return result
def match_account_in_party(self) -> Union[Tuple, None]:
def match_account_in_party(self) -> tuple | None:
"""Check if there is a IBAN/Account No. match in Customer/Supplier/Employee"""
result = None
parties = get_parties_in_order(self.deposit)
@@ -97,7 +95,7 @@ class AutoMatchbyPartyNameDescription:
def get(self, key):
return self.__dict__.get(key, None)
def match(self) -> Union[Tuple, None]:
def match(self) -> tuple | None:
# fuzzy search by customer/supplier & employee
if not (self.bank_party_name or self.description):
return None
@@ -105,7 +103,7 @@ class AutoMatchbyPartyNameDescription:
result = self.match_party_name_desc_in_party()
return result
def match_party_name_desc_in_party(self) -> Union[Tuple, None]:
def match_party_name_desc_in_party(self) -> tuple | None:
"""Fuzzy search party name and/or description against parties in the system"""
result = None
parties = get_parties_in_order(self.deposit)
@@ -130,7 +128,7 @@ class AutoMatchbyPartyNameDescription:
return result
def fuzzy_search_and_return_result(self, party, names, field) -> Union[Tuple, None]:
def fuzzy_search_and_return_result(self, party, names, field) -> tuple | None:
skip = False
result = process.extract(
query=self.get(field),
@@ -147,7 +145,7 @@ class AutoMatchbyPartyNameDescription:
party_name,
), skip
def process_fuzzy_result(self, result: Union[list, None]):
def process_fuzzy_result(self, result: list | None):
"""
If there are multiple valid close matches return None as result may be faulty.
Return the result only if one accurate match stands out.

View File

@@ -64,7 +64,9 @@ class BankTransaction(Document):
_(
"Transaction currency: {0} cannot be different from Bank Account({1}) currency: {2}"
).format(
frappe.bold(self.currency), frappe.bold(self.bank_account), frappe.bold(account_currency)
frappe.bold(self.currency),
frappe.bold(self.bank_account),
frappe.bold(account_currency),
)
)
@@ -180,7 +182,7 @@ class BankTransaction(Document):
frappe.throw(_("Voucher {0} is over-allocated by {1}").format(unallocated_amount))
for payment_entry in to_remove:
self.remove(to_remove)
self.remove(payment_entry)
@frappe.whitelist()
def remove_payment_entries(self):
@@ -235,9 +237,7 @@ def get_clearance_details(transaction, payment_entry):
"""
gl_bank_account = frappe.db.get_value("Bank Account", transaction.bank_account, "account")
gles = get_related_bank_gl_entries(payment_entry.payment_document, payment_entry.payment_entry)
bt_allocations = get_total_allocated_amount(
payment_entry.payment_document, payment_entry.payment_entry
)
bt_allocations = get_total_allocated_amount(payment_entry.payment_document, payment_entry.payment_entry)
unallocated_amount = min(
transaction.unallocated_amount,
@@ -332,7 +332,6 @@ def get_total_allocated_amount(doctype, docname):
def get_paid_amount(payment_entry, currency, gl_bank_account):
if payment_entry.payment_document in ["Payment Entry", "Sales Invoice", "Purchase Invoice"]:
paid_amount_field = "paid_amount"
if payment_entry.payment_document == "Payment Entry":
doc = frappe.get_doc("Payment Entry", payment_entry.payment_entry)
@@ -371,9 +370,7 @@ def get_paid_amount(payment_entry, currency, gl_bank_account):
)
elif payment_entry.payment_document == "Loan Repayment":
return frappe.db.get_value(
payment_entry.payment_document, payment_entry.payment_entry, "amount_paid"
)
return frappe.db.get_value(payment_entry.payment_document, payment_entry.payment_entry, "amount_paid")
elif payment_entry.payment_document == "Bank Transaction":
dep, wth = frappe.db.get_value(
@@ -383,9 +380,7 @@ def get_paid_amount(payment_entry, currency, gl_bank_account):
else:
frappe.throw(
"Please reconcile {0}: {1} manually".format(
payment_entry.payment_document, payment_entry.payment_entry
)
f"Please reconcile {payment_entry.payment_document}: {payment_entry.payment_entry} manually"
)

View File

@@ -18,12 +18,12 @@ def upload_bank_statement():
fcontent = frappe.local.uploaded_file
fname = frappe.local.uploaded_filename
if frappe.safe_encode(fname).lower().endswith("csv".encode("utf-8")):
if frappe.safe_encode(fname).lower().endswith(b"csv"):
from frappe.utils.csvutils import read_csv_content
rows = read_csv_content(fcontent, False)
elif frappe.safe_encode(fname).lower().endswith("xlsx".encode("utf-8")):
elif frappe.safe_encode(fname).lower().endswith(b"xlsx"):
from frappe.utils.xlsxutils import read_xlsx_file_from_attached_file
rows = read_xlsx_file_from_attached_file(fcontent=fcontent)

View File

@@ -436,9 +436,7 @@ def add_vouchers(gl_account="_Test Bank - _TC"):
mode_of_payment = frappe.get_doc({"doctype": "Mode of Payment", "name": "Cash"})
if not frappe.db.get_value(
"Mode of Payment Account", {"company": "_Test Company", "parent": "Cash"}
):
if not frappe.db.get_value("Mode of Payment Account", {"company": "_Test Company", "parent": "Cash"}):
mode_of_payment.append("accounts", {"company": "_Test Company", "default_account": gl_account})
mode_of_payment.save()

View File

@@ -70,10 +70,11 @@ class Budget(Document):
select
b.name, ba.account from `tabBudget` b, `tabBudget Account` ba
where
ba.parent = b.name and b.docstatus < 2 and b.company = %s and %s=%s and
b.fiscal_year=%s and b.name != %s and ba.account in (%s) """
% ("%s", budget_against_field, "%s", "%s", "%s", ",".join(["%s"] * len(accounts))),
(self.company, budget_against, self.fiscal_year, self.name) + tuple(accounts),
ba.parent = b.name and b.docstatus < 2 and b.company = {} and {}={} and
b.fiscal_year={} and b.name != {} and ba.account in ({}) """.format(
"%s", budget_against_field, "%s", "%s", "%s", ",".join(["%s"] * len(accounts))
),
(self.company, budget_against, self.fiscal_year, self.name, *tuple(accounts)),
as_dict=1,
)
@@ -96,12 +97,14 @@ class Budget(Document):
if account_details.is_group:
frappe.throw(_("Budget cannot be assigned against Group Account {0}").format(d.account))
elif account_details.company != self.company:
frappe.throw(_("Account {0} does not belongs to company {1}").format(d.account, self.company))
frappe.throw(
_("Account {0} does not belongs to company {1}").format(d.account, self.company)
)
elif account_details.report_type != "Profit and Loss":
frappe.throw(
_("Budget cannot be assigned against {0}, as it's not an Income or Expense account").format(
d.account
)
_(
"Budget cannot be assigned against {0}, as it's not an Income or Expense account"
).format(d.account)
)
if d.account in account_list:
@@ -148,9 +151,7 @@ def validate_expense_against_budget(args, expense_amount=0):
"Company", args.get("company"), "exception_budget_approver_role"
)
if not frappe.get_cached_value(
"Budget", {"fiscal_year": args.fiscal_year, "company": args.company}
): # nosec
if not frappe.get_cached_value("Budget", {"fiscal_year": args.fiscal_year, "company": args.company}): # nosec
return
if not args.account:
@@ -181,30 +182,24 @@ def validate_expense_against_budget(args, expense_amount=0):
and args.account
and (frappe.get_cached_value("Account", args.account, "root_type") == "Expense")
):
doctype = dimension.get("document_type")
if frappe.get_cached_value("DocType", doctype, "is_tree"):
lft, rgt = frappe.get_cached_value(doctype, args.get(budget_against), ["lft", "rgt"])
condition = """and exists(select name from `tab%s`
where lft<=%s and rgt>=%s and name=b.%s)""" % (
doctype,
lft,
rgt,
budget_against,
) # nosec
condition = f"""and exists(select name from `tab{doctype}`
where lft<={lft} and rgt>={rgt} and name=b.{budget_against})""" # nosec
args.is_tree = True
else:
condition = "and b.%s=%s" % (budget_against, frappe.db.escape(args.get(budget_against)))
condition = f"and b.{budget_against}={frappe.db.escape(args.get(budget_against))}"
args.is_tree = False
args.budget_against_field = budget_against
args.budget_against_doctype = doctype
budget_records = frappe.db.sql(
"""
f"""
select
b.{budget_against_field} as budget_against, ba.budget_amount, b.monthly_distribution,
b.{budget_against} as budget_against, ba.budget_amount, b.monthly_distribution,
ifnull(b.applicable_on_material_request, 0) as for_material_request,
ifnull(applicable_on_purchase_order, 0) as for_purchase_order,
ifnull(applicable_on_booking_actual_expenses,0) as for_actual_expenses,
@@ -217,9 +212,7 @@ def validate_expense_against_budget(args, expense_amount=0):
b.name=ba.parent and b.fiscal_year=%s
and ba.account=%s and b.docstatus=1
{condition}
""".format(
condition=condition, budget_against_field=budget_against
),
""",
(args.fiscal_year, args.account),
as_dict=True,
) # nosec
@@ -247,7 +240,12 @@ def validate_budget_records(args, budget_records, expense_amount):
args["month_end_date"] = get_last_day(args.posting_date)
compare_expense_with_budget(
args, budget_amount, _("Accumulated Monthly"), monthly_action, budget.budget_against, amount
args,
budget_amount,
_("Accumulated Monthly"),
monthly_action,
budget.budget_against,
amount,
)
@@ -275,9 +273,8 @@ def compare_expense_with_budget(args, budget_amount, action_for, action, budget_
frappe.bold(fmt_money(diff, currency=currency)),
)
if (
frappe.flags.exception_approver_role
and frappe.flags.exception_approver_role in frappe.get_roles(frappe.session.user)
if frappe.flags.exception_approver_role and frappe.flags.exception_approver_role in frappe.get_roles(
frappe.session.user
):
action = "Warn"
@@ -323,10 +320,8 @@ def get_requested_amount(args, budget):
data = frappe.db.sql(
""" select ifnull((sum(child.stock_qty - child.ordered_qty) * rate), 0) as amount
from `tabMaterial Request Item` child, `tabMaterial Request` parent where parent.name = child.parent and
child.item_code = %s and parent.docstatus = 1 and child.stock_qty > child.ordered_qty and {0} and
parent.material_request_type = 'Purchase' and parent.status != 'Stopped'""".format(
condition
),
child.item_code = %s and parent.docstatus = 1 and child.stock_qty > child.ordered_qty and {} and
parent.material_request_type = 'Purchase' and parent.status != 'Stopped'""".format(condition),
item_code,
as_list=1,
)
@@ -339,12 +334,10 @@ def get_ordered_amount(args, budget):
condition = get_other_condition(args, budget, "Purchase Order")
data = frappe.db.sql(
""" select ifnull(sum(child.amount - child.billed_amt), 0) as amount
f""" select ifnull(sum(child.amount - child.billed_amt), 0) as amount
from `tabPurchase Order Item` child, `tabPurchase Order` parent where
parent.name = child.parent and child.item_code = %s and parent.docstatus = 1 and child.amount > child.billed_amt
and parent.status != 'Closed' and {0}""".format(
condition
),
and parent.status != 'Closed' and {condition}""",
item_code,
as_list=1,
)
@@ -357,7 +350,7 @@ def get_other_condition(args, budget, for_doc):
budget_against_field = args.get("budget_against_field")
if budget_against_field and args.get(budget_against_field):
condition += " and child.%s = '%s'" % (budget_against_field, args.get(budget_against_field))
condition += f" and child.{budget_against_field} = '{args.get(budget_against_field)}'"
if args.get("fiscal_year"):
date_field = "schedule_date" if for_doc == "Material Request" else "transaction_date"
@@ -365,12 +358,8 @@ def get_other_condition(args, budget, for_doc):
"Fiscal Year", args.get("fiscal_year"), ["year_start_date", "year_end_date"]
)
condition += """ and parent.%s
between '%s' and '%s' """ % (
date_field,
start_date,
end_date,
)
condition += f""" and parent.{date_field}
between '{start_date}' and '{end_date}' """
return condition
@@ -389,21 +378,17 @@ def get_actual_expense(args):
args.update(lft_rgt)
condition2 = """and exists(select name from `tab{doctype}`
condition2 = f"""and exists(select name from `tab{args.budget_against_doctype}`
where lft>=%(lft)s and rgt<=%(rgt)s
and name=gle.{budget_against_field})""".format(
doctype=args.budget_against_doctype, budget_against_field=budget_against_field # nosec
)
and name=gle.{budget_against_field})"""
else:
condition2 = """and exists(select name from `tab{doctype}`
where name=gle.{budget_against} and
gle.{budget_against} = %({budget_against})s)""".format(
doctype=args.budget_against_doctype, budget_against=budget_against_field
)
condition2 = f"""and exists(select name from `tab{args.budget_against_doctype}`
where name=gle.{budget_against_field} and
gle.{budget_against_field} = %({budget_against_field})s)"""
amount = flt(
frappe.db.sql(
"""
f"""
select sum(gle.debit) - sum(gle.credit)
from `tabGL Entry` gle
where
@@ -414,9 +399,7 @@ def get_actual_expense(args):
and gle.company=%(company)s
and gle.docstatus=1
{condition2}
""".format(
condition1=condition1, condition2=condition2
),
""",
(args),
)[0][0]
) # nosec

View File

@@ -41,9 +41,7 @@ class TestBudget(unittest.TestCase):
budget = make_budget(budget_against="Cost Center")
frappe.db.set_value(
"Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop"
)
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
jv = make_journal_entry(
"_Test Account Cost for Goods Sold - _TC",
@@ -63,9 +61,7 @@ class TestBudget(unittest.TestCase):
budget = make_budget(budget_against="Cost Center")
frappe.db.set_value(
"Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop"
)
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
jv = make_journal_entry(
"_Test Account Cost for Goods Sold - _TC",
@@ -97,9 +93,7 @@ class TestBudget(unittest.TestCase):
)
fiscal_year = get_fiscal_year(nowdate())[0]
frappe.db.set_value(
"Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop"
)
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
frappe.db.set_value("Budget", budget.name, "fiscal_year", fiscal_year)
mr = frappe.get_doc(
@@ -138,9 +132,7 @@ class TestBudget(unittest.TestCase):
)
fiscal_year = get_fiscal_year(nowdate())[0]
frappe.db.set_value(
"Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop"
)
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
frappe.db.set_value("Budget", budget.name, "fiscal_year", fiscal_year)
po = create_purchase_order(transaction_date=nowdate(), do_not_submit=True)
@@ -158,9 +150,7 @@ class TestBudget(unittest.TestCase):
budget = make_budget(budget_against="Project")
frappe.db.set_value(
"Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop"
)
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
project = frappe.get_value("Project", {"project_name": "_Test Project"})
@@ -223,7 +213,7 @@ class TestBudget(unittest.TestCase):
if month > 9:
month = 9
for i in range(month + 1):
for _i in range(month + 1):
jv = make_journal_entry(
"_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC",
@@ -237,9 +227,7 @@ class TestBudget(unittest.TestCase):
frappe.db.get_value("GL Entry", {"voucher_type": "Journal Entry", "voucher_no": jv.name})
)
frappe.db.set_value(
"Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop"
)
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
self.assertRaises(BudgetError, jv.cancel)
@@ -255,7 +243,7 @@ class TestBudget(unittest.TestCase):
month = 9
project = frappe.get_value("Project", {"project_name": "_Test Project"})
for i in range(month + 1):
for _i in range(month + 1):
jv = make_journal_entry(
"_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC",
@@ -270,9 +258,7 @@ class TestBudget(unittest.TestCase):
frappe.db.get_value("GL Entry", {"voucher_type": "Journal Entry", "voucher_no": jv.name})
)
frappe.db.set_value(
"Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop"
)
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
self.assertRaises(BudgetError, jv.cancel)
@@ -284,9 +270,7 @@ class TestBudget(unittest.TestCase):
set_total_expense_zero(nowdate(), "cost_center", "_Test Cost Center 2 - _TC")
budget = make_budget(budget_against="Cost Center", cost_center="_Test Company - _TC")
frappe.db.set_value(
"Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop"
)
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
jv = make_journal_entry(
"_Test Account Cost for Goods Sold - _TC",
@@ -316,9 +300,7 @@ class TestBudget(unittest.TestCase):
).insert(ignore_permissions=True)
budget = make_budget(budget_against="Cost Center", cost_center=cost_center)
frappe.db.set_value(
"Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop"
)
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
jv = make_journal_entry(
"_Test Account Cost for Goods Sold - _TC",
@@ -423,13 +405,11 @@ def make_budget(**args):
fiscal_year = get_fiscal_year(nowdate())[0]
if budget_against == "Project":
project_name = "{0}%".format("_Test Project/" + fiscal_year)
project_name = "{}%".format("_Test Project/" + fiscal_year)
budget_list = frappe.get_all("Budget", fields=["name"], filters={"name": ("like", project_name)})
else:
cost_center_name = "{0}%".format(cost_center or "_Test Cost Center - _TC/" + fiscal_year)
budget_list = frappe.get_all(
"Budget", fields=["name"], filters={"name": ("like", cost_center_name)}
)
cost_center_name = "{}%".format(cost_center or "_Test Cost Center - _TC/" + fiscal_year)
budget_list = frappe.get_all("Budget", fields=["name"], filters={"name": ("like", cost_center_name)})
for d in budget_list:
frappe.db.sql("delete from `tabBudget` where name = %(name)s", d)
frappe.db.sql("delete from `tabBudget Account` where parent = %(name)s", d)
@@ -451,24 +431,18 @@ def make_budget(**args):
budget.action_if_annual_budget_exceeded = "Stop"
budget.action_if_accumulated_monthly_budget_exceeded = "Ignore"
budget.budget_against = budget_against
budget.append(
"accounts", {"account": "_Test Account Cost for Goods Sold - _TC", "budget_amount": 200000}
)
budget.append("accounts", {"account": "_Test Account Cost for Goods Sold - _TC", "budget_amount": 200000})
if args.applicable_on_material_request:
budget.applicable_on_material_request = 1
budget.action_if_annual_budget_exceeded_on_mr = (
args.action_if_annual_budget_exceeded_on_mr or "Warn"
)
budget.action_if_annual_budget_exceeded_on_mr = args.action_if_annual_budget_exceeded_on_mr or "Warn"
budget.action_if_accumulated_monthly_budget_exceeded_on_mr = (
args.action_if_accumulated_monthly_budget_exceeded_on_mr or "Warn"
)
if args.applicable_on_purchase_order:
budget.applicable_on_purchase_order = 1
budget.action_if_annual_budget_exceeded_on_po = (
args.action_if_annual_budget_exceeded_on_po or "Warn"
)
budget.action_if_annual_budget_exceeded_on_po = args.action_if_annual_budget_exceeded_on_po or "Warn"
budget.action_if_accumulated_monthly_budget_exceeded_on_po = (
args.action_if_accumulated_monthly_budget_exceeded_on_po or "Warn"
)

View File

@@ -38,9 +38,7 @@ class ChartofAccountsImporter(Document):
def validate(self):
if self.import_file:
get_coa(
"Chart of Accounts Importer", "All Accounts", file_name=self.import_file, for_validate=1
)
get_coa("Chart of Accounts Importer", "All Accounts", file_name=self.import_file, for_validate=1)
def validate_columns(data):
@@ -116,7 +114,7 @@ def generate_data_from_csv(file_doc, as_dict=False):
file_path = file_doc.get_full_path()
data = []
with open(file_path, "r") as in_file:
with open(file_path) as in_file:
csv_reader = list(csv.reader(in_file))
headers = csv_reader[0]
del csv_reader[0] # delete top row and headers row
@@ -215,10 +213,10 @@ def build_forest(data):
for row in data:
account_name, parent_account, account_number, parent_account_number = row[0:4]
if account_number:
account_name = "{} - {}".format(account_number, account_name)
account_name = f"{account_number} - {account_name}"
if parent_account_number:
parent_account_number = cstr(parent_account_number).strip()
parent_account = "{} - {}".format(parent_account_number, parent_account)
parent_account = f"{parent_account_number} - {parent_account}"
if parent_account == account_name == child:
return [parent_account]
@@ -230,7 +228,7 @@ def build_forest(data):
frappe.bold(parent_account)
)
)
return [child] + parent_account_list
return [child, *parent_account_list]
charts_map, paths = {}, []
@@ -250,12 +248,12 @@ def build_forest(data):
) = i
if not account_name:
error_messages.append("Row {0}: Please enter Account Name".format(line_no))
error_messages.append(f"Row {line_no}: Please enter Account Name")
name = account_name
if account_number:
account_number = cstr(account_number).strip()
account_name = "{} - {}".format(account_number, account_name)
account_name = f"{account_number} - {account_name}"
charts_map[account_name] = {}
charts_map[account_name]["account_name"] = name
@@ -352,9 +350,9 @@ def get_template(template_type, company):
def get_sample_template(writer, company):
currency = frappe.db.get_value("Company", company, "default_currency")
with open(os.path.join(os.path.dirname(__file__), "coa_sample_template.csv"), "r") as f:
with open(os.path.join(os.path.dirname(__file__), "coa_sample_template.csv")) as f:
for row in f:
row = row.strip().split(",") + [currency]
row = [*row.strip().split(","), currency]
writer.writerow(row)
return writer
@@ -463,7 +461,7 @@ def unset_existing_data(company):
"Purchase Taxes and Charges Template",
]:
frappe.db.sql(
'''delete from `tab{0}` where `company`="%s"'''.format(doctype) % (company) # nosec
f'''delete from `tab{doctype}` where `company`="%s"''' % (company) # nosec
)

View File

@@ -66,71 +66,71 @@ def create_or_update_cheque_print_format(template_name):
cheque_print.html = """
<style>
.print-format {
.print-format {{
padding: 0px;
}
@media screen {
.print-format {
}}
@media screen {{
.print-format {{
padding: 0in;
}
}
}}
}}
</style>
<div style="position: relative; top:%(starting_position_from_top_edge)scm">
<div style="width:%(cheque_width)scm;height:%(cheque_height)scm;">
<span style="top:%(acc_pay_dist_from_top_edge)scm; left:%(acc_pay_dist_from_left_edge)scm;
<div style="position: relative; top:{starting_position_from_top_edge}cm">
<div style="width:{cheque_width}cm;height:{cheque_height}cm;">
<span style="top:{acc_pay_dist_from_top_edge}cm; left:{acc_pay_dist_from_left_edge}cm;
border-bottom: solid 1px;border-top:solid 1px; width:2cm;text-align: center; position: absolute;">
%(message_to_show)s
{message_to_show}
</span>
<span style="top:%(date_dist_from_top_edge)scm; left:%(date_dist_from_left_edge)scm;
<span style="top:{date_dist_from_top_edge}cm; left:{date_dist_from_left_edge}cm;
position: absolute;">
{{ frappe.utils.formatdate(doc.reference_date) or '' }}
{{{{ frappe.utils.formatdate(doc.reference_date) or '' }}}}
</span>
<span style="top:%(acc_no_dist_from_top_edge)scm;left:%(acc_no_dist_from_left_edge)scm;
<span style="top:{acc_no_dist_from_top_edge}cm;left:{acc_no_dist_from_left_edge}cm;
position: absolute; min-width: 6cm;">
{{ doc.account_no or '' }}
{{{{ doc.account_no or '' }}}}
</span>
<span style="top:%(payer_name_from_top_edge)scm;left: %(payer_name_from_left_edge)scm;
<span style="top:{payer_name_from_top_edge}cm;left: {payer_name_from_left_edge}cm;
position: absolute; min-width: 6cm;">
{{doc.party_name}}
{{{{doc.party_name}}}}
</span>
<span style="top:%(amt_in_words_from_top_edge)scm; left:%(amt_in_words_from_left_edge)scm;
position: absolute; display: block; width: %(amt_in_word_width)scm;
line-height:%(amt_in_words_line_spacing)scm; word-wrap: break-word;">
{{frappe.utils.money_in_words(doc.base_paid_amount or doc.base_received_amount)}}
<span style="top:{amt_in_words_from_top_edge}cm; left:{amt_in_words_from_left_edge}cm;
position: absolute; display: block; width: {amt_in_word_width}cm;
line-height:{amt_in_words_line_spacing}cm; word-wrap: break-word;">
{{{{frappe.utils.money_in_words(doc.base_paid_amount or doc.base_received_amount)}}}}
</span>
<span style="top:%(amt_in_figures_from_top_edge)scm;left: %(amt_in_figures_from_left_edge)scm;
<span style="top:{amt_in_figures_from_top_edge}cm;left: {amt_in_figures_from_left_edge}cm;
position: absolute; min-width: 4cm;">
{{doc.get_formatted("base_paid_amount") or doc.get_formatted("base_received_amount")}}
{{{{doc.get_formatted("base_paid_amount") or doc.get_formatted("base_received_amount")}}}}
</span>
<span style="top:%(signatory_from_top_edge)scm;left: %(signatory_from_left_edge)scm;
<span style="top:{signatory_from_top_edge}cm;left: {signatory_from_left_edge}cm;
position: absolute; min-width: 6cm;">
{{doc.company}}
{{{{doc.company}}}}
</span>
</div>
</div>""" % {
"starting_position_from_top_edge": doc.starting_position_from_top_edge
</div>""".format(
starting_position_from_top_edge=doc.starting_position_from_top_edge
if doc.cheque_size == "A4"
else 0.0,
"cheque_width": doc.cheque_width,
"cheque_height": doc.cheque_height,
"acc_pay_dist_from_top_edge": doc.acc_pay_dist_from_top_edge,
"acc_pay_dist_from_left_edge": doc.acc_pay_dist_from_left_edge,
"message_to_show": doc.message_to_show if doc.message_to_show else _("Account Pay Only"),
"date_dist_from_top_edge": doc.date_dist_from_top_edge,
"date_dist_from_left_edge": doc.date_dist_from_left_edge,
"acc_no_dist_from_top_edge": doc.acc_no_dist_from_top_edge,
"acc_no_dist_from_left_edge": doc.acc_no_dist_from_left_edge,
"payer_name_from_top_edge": doc.payer_name_from_top_edge,
"payer_name_from_left_edge": doc.payer_name_from_left_edge,
"amt_in_words_from_top_edge": doc.amt_in_words_from_top_edge,
"amt_in_words_from_left_edge": doc.amt_in_words_from_left_edge,
"amt_in_word_width": doc.amt_in_word_width,
"amt_in_words_line_spacing": doc.amt_in_words_line_spacing,
"amt_in_figures_from_top_edge": doc.amt_in_figures_from_top_edge,
"amt_in_figures_from_left_edge": doc.amt_in_figures_from_left_edge,
"signatory_from_top_edge": doc.signatory_from_top_edge,
"signatory_from_left_edge": doc.signatory_from_left_edge,
}
cheque_width=doc.cheque_width,
cheque_height=doc.cheque_height,
acc_pay_dist_from_top_edge=doc.acc_pay_dist_from_top_edge,
acc_pay_dist_from_left_edge=doc.acc_pay_dist_from_left_edge,
message_to_show=doc.message_to_show if doc.message_to_show else _("Account Pay Only"),
date_dist_from_top_edge=doc.date_dist_from_top_edge,
date_dist_from_left_edge=doc.date_dist_from_left_edge,
acc_no_dist_from_top_edge=doc.acc_no_dist_from_top_edge,
acc_no_dist_from_left_edge=doc.acc_no_dist_from_left_edge,
payer_name_from_top_edge=doc.payer_name_from_top_edge,
payer_name_from_left_edge=doc.payer_name_from_left_edge,
amt_in_words_from_top_edge=doc.amt_in_words_from_top_edge,
amt_in_words_from_left_edge=doc.amt_in_words_from_left_edge,
amt_in_word_width=doc.amt_in_word_width,
amt_in_words_line_spacing=doc.amt_in_words_line_spacing,
amt_in_figures_from_top_edge=doc.amt_in_figures_from_top_edge,
amt_in_figures_from_left_edge=doc.amt_in_figures_from_left_edge,
signatory_from_top_edge=doc.signatory_from_top_edge,
signatory_from_left_edge=doc.signatory_from_left_edge,
)
cheque_print.save(ignore_permissions=True)

View File

@@ -34,9 +34,7 @@ class CostCenter(NestedSet):
def autoname(self):
from erpnext.accounts.utils import get_autoname_with_number
self.name = get_autoname_with_number(
self.cost_center_number, self.cost_center_name, self.company
)
self.name = get_autoname_with_number(self.cost_center_number, self.cost_center_name, self.company)
def validate(self):
self.validate_mandatory()
@@ -109,14 +107,14 @@ class CostCenter(NestedSet):
new_cost_center = get_name_with_abbr(newdn, self.company)
# Validate properties before merging
super(CostCenter, self).before_rename(olddn, new_cost_center, merge, "is_group")
super().before_rename(olddn, new_cost_center, merge, "is_group")
if not merge:
new_cost_center = get_name_with_number(new_cost_center, self.cost_center_number)
return new_cost_center
def after_rename(self, olddn, newdn, merge=False):
super(CostCenter, self).after_rename(olddn, newdn, merge)
super().after_rename(olddn, newdn, merge)
if not merge:
new_cost_center = frappe.db.get_value(

View File

@@ -10,7 +10,6 @@ test_records = frappe.get_test_records("Cost Center")
class TestCostCenter(unittest.TestCase):
def test_cost_center_creation_against_child_node(self):
if not frappe.db.get_value("Cost Center", {"name": "_Test Cost Center 2 - _TC"}):
frappe.get_doc(test_records[1]).insert()

View File

@@ -48,7 +48,7 @@ class CostCenterAllocation(Document):
# end: auto-generated types
def __init__(self, *args, **kwargs):
super(CostCenterAllocation, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self._skip_from_date_validation = False
def validate(self):
@@ -63,9 +63,7 @@ class CostCenterAllocation(Document):
total_percentage = sum([d.percentage for d in self.get("allocation_percentages", [])])
if total_percentage != 100:
frappe.throw(
_("Total percentage against cost centers should be 100"), WrongPercentageAllocation
)
frappe.throw(_("Total percentage against cost centers should be 100"), WrongPercentageAllocation)
def validate_from_date_based_on_existing_gle(self):
# Check if GLE exists against the main cost center

View File

@@ -43,7 +43,6 @@ class CurrencyExchangeSettings(Document):
def set_parameters_and_result(self):
if self.service_provider == "exchangerate.host":
if not self.access_key:
frappe.throw(
_("Access Key is required for Service Provider: {0}").format(
@@ -78,9 +77,7 @@ class CurrencyExchangeSettings(Document):
transaction_date=nowdate(), to_currency="INR", from_currency="USD"
)
api_url = self.api_endpoint.format(
transaction_date=nowdate(), to_currency="INR", from_currency="USD"
)
api_url = self.api_endpoint.format(transaction_date=nowdate(), to_currency="INR", from_currency="USD")
try:
response = requests.get(api_url, params=params)
@@ -100,14 +97,14 @@ class CurrencyExchangeSettings(Document):
]
except Exception:
frappe.throw(_("Invalid result key. Response:") + " " + response.text)
if not isinstance(value, (int, float)):
if not isinstance(value, int | float):
frappe.throw(_("Returned exchange rate is neither integer not float."))
self.url = response.url
@frappe.whitelist()
def get_api_endpoint(service_provider: str = None, use_http: bool = False):
def get_api_endpoint(service_provider: str | None = None, use_http: bool = False):
if service_provider and service_provider in ["exchangerate.host", "frankfurter.app"]:
if service_provider == "exchangerate.host":
api = "api.exchangerate.host/convert"

View File

@@ -109,9 +109,7 @@ class TestDunning(FrappeTestCase):
def create_dunning(overdue_days, dunning_type_name=None):
posting_date = add_days(today(), -1 * overdue_days)
sales_invoice = create_sales_invoice_against_cost_center(
posting_date=posting_date, qty=1, rate=100
)
sales_invoice = create_sales_invoice_against_cost_center(posting_date=posting_date, qty=1, rate=100)
dunning = create_dunning_from_sales_invoice(sales_invoice.name)
if dunning_type_name:

View File

@@ -268,7 +268,6 @@ class ExchangeRateRevaluation(Document):
# Handle Accounts with '0' balance in Account/Base Currency
for d in [x for x in account_details if x.zero_balance]:
if d.balance != 0:
current_exchange_rate = new_exchange_rate = 0
@@ -281,7 +280,8 @@ class ExchangeRateRevaluation(Document):
new_balance_in_account_currency = 0
current_exchange_rate = (
calculate_exchange_rate_using_last_gle(company, d.account, d.party_type, d.party) or 0.0
calculate_exchange_rate_using_last_gle(company, d.account, d.party_type, d.party)
or 0.0
)
gain_loss = new_balance_in_account_currency - (
@@ -335,9 +335,7 @@ class ExchangeRateRevaluation(Document):
revaluation_jv = self.make_jv_for_revaluation()
if revaluation_jv:
frappe.msgprint(
f"Revaluation Journal: {get_link_to_form('Journal Entry', revaluation_jv.name)}"
)
frappe.msgprint(f"Revaluation Journal: {get_link_to_form('Journal Entry', revaluation_jv.name)}")
return {
"revaluation_jv": revaluation_jv.name if revaluation_jv else None,
@@ -394,7 +392,8 @@ class ExchangeRateRevaluation(Document):
journal_account.update(
{
dr_or_cr: flt(
abs(d.get("balance_in_account_currency")), d.precision("balance_in_account_currency")
abs(d.get("balance_in_account_currency")),
d.precision("balance_in_account_currency"),
),
reverse_dr_or_cr: 0,
"debit": 0,
@@ -520,7 +519,9 @@ class ExchangeRateRevaluation(Document):
abs(d.get("balance_in_account_currency")), d.precision("balance_in_account_currency")
),
"cost_center": erpnext.get_default_cost_center(self.company),
"exchange_rate": flt(d.get("current_exchange_rate"), d.precision("current_exchange_rate")),
"exchange_rate": flt(
d.get("current_exchange_rate"), d.precision("current_exchange_rate")
),
"reference_type": "Exchange Rate Revaluation",
"reference_name": self.name,
}
@@ -598,7 +599,7 @@ def calculate_exchange_rate_using_last_gle(company, account, party_type, party):
@frappe.whitelist()
def get_account_details(
company, posting_date, account, party_type=None, party=None, rounding_loss_allowance: float = None
company, posting_date, account, party_type=None, party=None, rounding_loss_allowance: float | None = None
):
if not (company and posting_date):
frappe.throw(_("Company and Posting Date is mandatory"))
@@ -611,7 +612,7 @@ def get_account_details(
frappe.throw(_("Party Type and Party is mandatory for {0} account").format(account_type))
account_details = {}
company_currency = erpnext.get_company_currency(company)
erpnext.get_company_currency(company)
account_details = {
"account_currency": account_currency,
@@ -625,9 +626,7 @@ def get_account_details(
rounding_loss_allowance=rounding_loss_allowance,
)
if account_balance and (
account_balance[0].balance or account_balance[0].balance_in_account_currency
):
if account_balance and (account_balance[0].balance or account_balance[0].balance_in_account_currency):
if account_with_new_balance := ExchangeRateRevaluation.calculate_new_account_balance(
company, posting_date, account_balance
):

View File

@@ -1,21 +1,14 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe import qb
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import add_days, flt, today
from erpnext import get_default_cost_center
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.accounts.party import get_party_account
from erpnext.accounts.test.accounts_mixin import AccountsTestMixin
from erpnext.stock.doctype.item.test_item import create_item
class TestExchangeRateRevaluation(AccountsTestMixin, FrappeTestCase):
@@ -73,9 +66,7 @@ class TestExchangeRateRevaluation(AccountsTestMixin, FrappeTestCase):
err.extend("accounts", accounts)
row = err.accounts[0]
row.new_exchange_rate = 85
row.new_balance_in_base_currency = flt(
row.new_exchange_rate * flt(row.balance_in_account_currency)
)
row.new_balance_in_base_currency = flt(row.new_exchange_rate * flt(row.balance_in_account_currency))
row.gain_loss = row.new_balance_in_base_currency - flt(row.balance_in_base_currency)
err.set_total_gain_loss()
err = err.save().submit()
@@ -127,9 +118,9 @@ class TestExchangeRateRevaluation(AccountsTestMixin, FrappeTestCase):
pe.save().submit()
# Cancel the auto created gain/loss JE to simulate balance only in base currency
je = frappe.db.get_all(
"Journal Entry Account", filters={"reference_name": si.name}, pluck="parent"
)[0]
je = frappe.db.get_all("Journal Entry Account", filters={"reference_name": si.name}, pluck="parent")[
0
]
frappe.get_doc("Journal Entry", je).cancel()
err = frappe.new_doc("Exchange Rate Revaluation")
@@ -235,9 +226,9 @@ class TestExchangeRateRevaluation(AccountsTestMixin, FrappeTestCase):
self.assertEqual(flt(acc.debit, precision), 0.0)
self.assertEqual(flt(acc.credit, precision), 0.0)
row = [x for x in je.accounts if x.account == self.debtors_usd][0]
row = next(x for x in je.accounts if x.account == self.debtors_usd)
self.assertEqual(flt(row.credit_in_account_currency, precision), 5.0) # in USD
row = [x for x in je.accounts if x.account != self.debtors_usd][0]
row = next(x for x in je.accounts if x.account != self.debtors_usd)
self.assertEqual(flt(row.debit_in_account_currency, precision), 421.06) # in INR
# total_debit and total_credit will be 0.0, as JV is posting only to account currency fields
@@ -294,5 +285,5 @@ class TestExchangeRateRevaluation(AccountsTestMixin, FrappeTestCase):
"new_balance_in_account_currency": 100.0,
}
for key, val in expected_data.items():
for key, _val in expected_data.items():
self.assertEqual(expected_data.get(key), account_details.get(key))

View File

@@ -108,9 +108,9 @@ class FiscalYear(Document):
if overlap:
frappe.throw(
_("Year start date or end date is overlapping with {0}. To avoid please set company").format(
existing.name
),
_(
"Year start date or end date is overlapping with {0}. To avoid please set company"
).format(existing.name),
frappe.NameError,
)
@@ -126,9 +126,9 @@ def check_duplicate_fiscal_year(doc):
not frappe.flags.in_test
):
frappe.throw(
_("Fiscal Year Start Date and Fiscal Year End Date are already set in Fiscal Year {0}").format(
fiscal_year
)
_(
"Fiscal Year Start Date and Fiscal Year End Date are already set in Fiscal Year {0}"
).format(fiscal_year)
)

View File

@@ -105,13 +105,18 @@ class GLEntry(Document):
]:
# Update outstanding amt on against voucher
if (
self.against_voucher_type in ["Journal Entry", "Sales Invoice", "Purchase Invoice", "Fees"]
self.against_voucher_type
in ["Journal Entry", "Sales Invoice", "Purchase Invoice", "Fees"]
and self.against_voucher
and self.flags.update_outstanding == "Yes"
and not frappe.flags.is_reverse_depr_entry
):
update_outstanding_amt(
self.account, self.party_type, self.party, self.against_voucher_type, self.against_voucher
self.account,
self.party_type,
self.party,
self.against_voucher_type,
self.against_voucher,
)
def check_mandatory(self):
@@ -180,9 +185,9 @@ class GLEntry(Document):
):
if not self.get(dimension.fieldname):
frappe.throw(
_("Accounting Dimension <b>{0}</b> is required for 'Profit and Loss' account {1}.").format(
dimension.label, self.account
)
_(
"Accounting Dimension <b>{0}</b> is required for 'Profit and Loss' account {1}."
).format(dimension.label, self.account)
)
if (
@@ -193,9 +198,9 @@ class GLEntry(Document):
):
if not self.get(dimension.fieldname):
frappe.throw(
_("Accounting Dimension <b>{0}</b> is required for 'Balance Sheet' account {1}.").format(
dimension.label, self.account
)
_(
"Accounting Dimension <b>{0}</b> is required for 'Balance Sheet' account {1}."
).format(dimension.label, self.account)
)
def check_pl_account(self):
@@ -243,9 +248,7 @@ class GLEntry(Document):
if not self.cost_center:
return
is_group, company = frappe.get_cached_value(
"Cost Center", self.cost_center, ["is_group", "company"]
)
is_group, company = frappe.get_cached_value("Cost Center", self.cost_center, ["is_group", "company"])
if company != self.company:
frappe.throw(
@@ -314,7 +317,7 @@ def update_outstanding_amt(
account, party_type, party, against_voucher_type, against_voucher, on_cancel=False
):
if party_type and party:
party_condition = " and party_type={0} and party={1}".format(
party_condition = " and party_type={} and party={}".format(
frappe.db.escape(party_type), frappe.db.escape(party)
)
else:
@@ -322,23 +325,19 @@ def update_outstanding_amt(
if against_voucher_type == "Sales Invoice":
party_account = frappe.get_cached_value(against_voucher_type, against_voucher, "debit_to")
account_condition = "and account in ({0}, {1})".format(
frappe.db.escape(account), frappe.db.escape(party_account)
)
account_condition = f"and account in ({frappe.db.escape(account)}, {frappe.db.escape(party_account)})"
else:
account_condition = " and account = {0}".format(frappe.db.escape(account))
account_condition = f" and account = {frappe.db.escape(account)}"
# get final outstanding amt
bal = flt(
frappe.db.sql(
"""
f"""
select sum(debit_in_account_currency) - sum(credit_in_account_currency)
from `tabGL Entry`
where against_voucher_type=%s and against_voucher=%s
and voucher_type != 'Invoice Discounting'
{0} {1}""".format(
party_condition, account_condition
),
{party_condition} {account_condition}""",
(against_voucher_type, against_voucher),
)[0][0]
or 0.0
@@ -349,12 +348,10 @@ def update_outstanding_amt(
elif against_voucher_type == "Journal Entry":
against_voucher_amount = flt(
frappe.db.sql(
"""
f"""
select sum(debit_in_account_currency) - sum(credit_in_account_currency)
from `tabGL Entry` where voucher_type = 'Journal Entry' and voucher_no = %s
and account = %s and (against_voucher is null or against_voucher='') {0}""".format(
party_condition
),
and account = %s and (against_voucher is null or against_voucher='') {party_condition}""",
(against_voucher, account),
)[0][0]
)
@@ -373,7 +370,9 @@ def update_outstanding_amt(
# Validation : Outstanding can not be negative for JV
if bal < 0 and not on_cancel:
frappe.throw(
_("Outstanding for {0} cannot be less than zero ({1})").format(against_voucher, fmt_money(bal))
_("Outstanding for {0} cannot be less than zero ({1})").format(
against_voucher, fmt_money(bal)
)
)
if against_voucher_type in ["Sales Invoice", "Purchase Invoice", "Fees"]:
@@ -446,7 +445,7 @@ def rename_temporarily_named_docs(doctype):
set_name_from_naming_options(frappe.get_meta(doctype).autoname, doc)
newname = doc.name
frappe.db.sql(
"UPDATE `tab{}` SET name = %s, to_rename = 0 where name = %s".format(doctype),
f"UPDATE `tab{doctype}` SET name = %s, to_rename = 0 where name = %s",
(newname, oldname),
auto_commit=True,
)

View File

@@ -14,9 +14,7 @@ from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journ
class TestGLEntry(unittest.TestCase):
def test_round_off_entry(self):
frappe.db.set_value("Company", "_Test Company", "round_off_account", "_Test Write Off - _TC")
frappe.db.set_value(
"Company", "_Test Company", "round_off_cost_center", "_Test Cost Center - _TC"
)
frappe.db.set_value("Company", "_Test Company", "round_off_cost_center", "_Test Cost Center - _TC")
jv = make_journal_entry(
"_Test Account Cost for Goods Sold - _TC",
@@ -73,7 +71,9 @@ class TestGLEntry(unittest.TestCase):
)
self.assertTrue(all(entry.to_rename == 0 for entry in new_gl_entries))
self.assertTrue(all(new.name != old.name for new, old in zip(gl_entries, new_gl_entries)))
self.assertTrue(
all(new.name != old.name for new, old in zip(gl_entries, new_gl_entries, strict=False))
)
new_naming_series_current_value = frappe.db.sql(
"SELECT current from tabSeries where name = %s", naming_series

View File

@@ -83,9 +83,7 @@ class InvoiceDiscounting(AccountsController):
frappe.throw(
_(
"Row({0}): Outstanding Amount cannot be greater than actual Outstanding Amount {1} in {2}"
).format(
record.idx, frappe.bold(actual_outstanding), frappe.bold(record.sales_invoice)
)
).format(record.idx, frappe.bold(actual_outstanding), frappe.bold(record.sales_invoice))
)
def calculate_total_amount(self):
@@ -105,7 +103,9 @@ class InvoiceDiscounting(AccountsController):
self.status = status
self.db_set("status", status)
for d in self.invoices:
frappe.get_doc("Sales Invoice", d.sales_invoice).set_status(update=True, update_modified=False)
frappe.get_doc("Sales Invoice", d.sales_invoice).set_status(
update=True, update_modified=False
)
else:
self.status = "Draft"
if self.docstatus == 1:

View File

@@ -75,8 +75,8 @@ class TestInvoiceDiscounting(unittest.TestCase):
gle = get_gl_entries("Invoice Discounting", inv_disc.name)
expected_gle = {inv.debit_to: [0.0, 200], self.ar_credit: [200, 0.0]}
for i, gle in enumerate(gle):
self.assertEqual([gle.debit, gle.credit], expected_gle.get(gle.account))
for _i, gle_value in enumerate(gle):
self.assertEqual([gle_value.debit, gle_value.credit], expected_gle.get(gle_value.account))
def test_loan_on_submit(self):
inv = create_sales_invoice(rate=300)
@@ -92,9 +92,7 @@ class TestInvoiceDiscounting(unittest.TestCase):
period=60,
)
self.assertEqual(inv_disc.status, "Sanctioned")
self.assertEqual(
inv_disc.loan_end_date, add_days(inv_disc.loan_start_date, inv_disc.loan_period)
)
self.assertEqual(inv_disc.loan_end_date, add_days(inv_disc.loan_start_date, inv_disc.loan_period))
def test_on_disbursed(self):
inv = create_sales_invoice(rate=500)
@@ -262,13 +260,9 @@ class TestInvoiceDiscounting(unittest.TestCase):
je_on_payment.submit()
self.assertEqual(je_on_payment.accounts[0].account, self.ar_discounted)
self.assertEqual(
je_on_payment.accounts[0].credit_in_account_currency, flt(inv.outstanding_amount)
)
self.assertEqual(je_on_payment.accounts[0].credit_in_account_currency, flt(inv.outstanding_amount))
self.assertEqual(je_on_payment.accounts[1].account, self.bank_account)
self.assertEqual(
je_on_payment.accounts[1].debit_in_account_currency, flt(inv.outstanding_amount)
)
self.assertEqual(je_on_payment.accounts[1].debit_in_account_currency, flt(inv.outstanding_amount))
inv.reload()
self.assertEqual(inv.outstanding_amount, 0)
@@ -304,13 +298,9 @@ class TestInvoiceDiscounting(unittest.TestCase):
je_on_payment.submit()
self.assertEqual(je_on_payment.accounts[0].account, self.ar_unpaid)
self.assertEqual(
je_on_payment.accounts[0].credit_in_account_currency, flt(inv.outstanding_amount)
)
self.assertEqual(je_on_payment.accounts[0].credit_in_account_currency, flt(inv.outstanding_amount))
self.assertEqual(je_on_payment.accounts[1].account, self.bank_account)
self.assertEqual(
je_on_payment.accounts[1].debit_in_account_currency, flt(inv.outstanding_amount)
)
self.assertEqual(je_on_payment.accounts[1].debit_in_account_currency, flt(inv.outstanding_amount))
inv.reload()
self.assertEqual(inv.outstanding_amount, 0)

View File

@@ -32,7 +32,7 @@ class ItemTaxTemplate(Document):
def autoname(self):
if self.company and self.title:
abbr = frappe.get_cached_value("Company", self.company, "abbr")
self.name = "{0} - {1}".format(self.title, abbr)
self.name = f"{self.title} - {abbr}"
def validate_tax_accounts(self):
"""Check whether Tax Rate is not entered twice for same Tax Type"""

View File

@@ -112,7 +112,7 @@ class JournalEntry(AccountsController):
# end: auto-generated types
def __init__(self, *args, **kwargs):
super(JournalEntry, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
def validate(self):
if self.voucher_type == "Opening Entry":
@@ -191,7 +191,7 @@ class JournalEntry(AccountsController):
def on_cancel(self):
# References for this Journal are removed on the `on_cancel` event in accounts_controller
super(JournalEntry, self).on_cancel()
super().on_cancel()
self.ignore_linked_doctypes = (
"GL Entry",
"Stock Ledger Entry",
@@ -216,9 +216,9 @@ class JournalEntry(AccountsController):
def update_advance_paid(self):
advance_paid = frappe._dict()
advance_payment_doctypes = frappe.get_hooks(
"advance_payment_receivable_doctypes"
) + frappe.get_hooks("advance_payment_payable_doctypes")
advance_payment_doctypes = frappe.get_hooks("advance_payment_receivable_doctypes") + frappe.get_hooks(
"advance_payment_payable_doctypes"
)
for d in self.get("accounts"):
if d.is_advance:
if d.reference_type in advance_payment_doctypes:
@@ -229,10 +229,7 @@ class JournalEntry(AccountsController):
frappe.get_doc(voucher_type, voucher_no).set_total_advance_paid()
def validate_inter_company_accounts(self):
if (
self.voucher_type == "Inter Company Journal Entry"
and self.inter_company_journal_entry_reference
):
if self.voucher_type == "Inter Company Journal Entry" and self.inter_company_journal_entry_reference:
doc = frappe.get_doc("Journal Entry", self.inter_company_journal_entry_reference)
account_currency = frappe.get_cached_value("Company", self.company, "default_currency")
previous_account_currency = frappe.get_cached_value("Company", doc.company, "default_currency")
@@ -378,10 +375,7 @@ class JournalEntry(AccountsController):
asset.set_status()
def update_inter_company_jv(self):
if (
self.voucher_type == "Inter Company Journal Entry"
and self.inter_company_journal_entry_reference
):
if self.voucher_type == "Inter Company Journal Entry" and self.inter_company_journal_entry_reference:
frappe.db.set_value(
"Journal Entry",
self.inter_company_journal_entry_reference,
@@ -409,17 +403,25 @@ class JournalEntry(AccountsController):
if d.account == inv_disc_doc.short_term_loan and d.reference_name == inv_disc:
if self.docstatus == 1:
if d.credit > 0:
_validate_invoice_discounting_status(inv_disc, inv_disc_doc.status, "Sanctioned", d.idx)
_validate_invoice_discounting_status(
inv_disc, inv_disc_doc.status, "Sanctioned", d.idx
)
status = "Disbursed"
elif d.debit > 0:
_validate_invoice_discounting_status(inv_disc, inv_disc_doc.status, "Disbursed", d.idx)
_validate_invoice_discounting_status(
inv_disc, inv_disc_doc.status, "Disbursed", d.idx
)
status = "Settled"
else:
if d.credit > 0:
_validate_invoice_discounting_status(inv_disc, inv_disc_doc.status, "Disbursed", d.idx)
_validate_invoice_discounting_status(
inv_disc, inv_disc_doc.status, "Disbursed", d.idx
)
status = "Sanctioned"
elif d.debit > 0:
_validate_invoice_discounting_status(inv_disc, inv_disc_doc.status, "Settled", d.idx)
_validate_invoice_discounting_status(
inv_disc, inv_disc_doc.status, "Settled", d.idx
)
status = "Disbursed"
break
if status:
@@ -488,10 +490,7 @@ class JournalEntry(AccountsController):
)
def unlink_inter_company_jv(self):
if (
self.voucher_type == "Inter Company Journal Entry"
and self.inter_company_journal_entry_reference
):
if self.voucher_type == "Inter Company Journal Entry" and self.inter_company_journal_entry_reference:
frappe.db.set_value(
"Journal Entry",
self.inter_company_journal_entry_reference,
@@ -513,9 +512,9 @@ class JournalEntry(AccountsController):
if account_type in ["Receivable", "Payable"]:
if not (d.party_type and d.party):
frappe.throw(
_("Row {0}: Party Type and Party is required for Receivable / Payable account {1}").format(
d.idx, d.account
)
_(
"Row {0}: Party Type and Party is required for Receivable / Payable account {1}"
).format(d.idx, d.account)
)
elif (
d.party_type
@@ -580,16 +579,18 @@ class JournalEntry(AccountsController):
def system_generated_gain_loss(self):
return (
self.voucher_type == "Exchange Gain Or Loss"
and self.multi_currency
and self.is_system_generated
self.voucher_type == "Exchange Gain Or Loss" and self.multi_currency and self.is_system_generated
)
def validate_against_jv(self):
for d in self.get("accounts"):
if d.reference_type == "Journal Entry":
account_root_type = frappe.get_cached_value("Account", d.account, "root_type")
if account_root_type == "Asset" and flt(d.debit) > 0 and not self.system_generated_gain_loss():
if (
account_root_type == "Asset"
and flt(d.debit) > 0
and not self.system_generated_gain_loss()
):
frappe.throw(
_(
"Row #{0}: For {1}, you can select reference document only if account gets credited"
@@ -671,7 +672,9 @@ class JournalEntry(AccountsController):
if d.reference_type == "Purchase Order" and flt(d.credit) > 0:
frappe.throw(
_("Row {0}: Credit entry can not be linked with a {1}").format(d.idx, d.reference_type)
_("Row {0}: Credit entry can not be linked with a {1}").format(
d.idx, d.reference_type
)
)
# set totals
@@ -693,7 +696,10 @@ class JournalEntry(AccountsController):
# check if party and account match
if d.reference_type in ("Sales Invoice", "Purchase Invoice"):
if self.voucher_type in ("Deferred Revenue", "Deferred Expense") and d.reference_detail_no:
if (
self.voucher_type in ("Deferred Revenue", "Deferred Expense")
and d.reference_detail_no
):
debit_or_credit = "Debit" if d.debit else "Credit"
party_account = get_deferred_booking_accounts(
d.reference_type, d.reference_detail_no, debit_or_credit
@@ -702,7 +708,8 @@ class JournalEntry(AccountsController):
else:
if d.reference_type == "Sales Invoice":
party_account = (
get_party_account_based_on_invoice_discounting(d.reference_name) or against_voucher[1]
get_party_account_based_on_invoice_discounting(d.reference_name)
or against_voucher[1]
)
else:
party_account = against_voucher[1]
@@ -826,7 +833,9 @@ class JournalEntry(AccountsController):
if not (self.voucher_type == "Exchange Gain Or Loss" and self.multi_currency):
if self.difference:
frappe.throw(
_("Total Debit must be equal to Total Credit. The difference is {0}").format(self.difference)
_("Total Debit must be equal to Total Credit. The difference is {0}").format(
self.difference
)
)
def set_total_debit_credit(self):
@@ -890,7 +899,6 @@ class JournalEntry(AccountsController):
and self.posting_date
)
):
ignore_exchange_rate = False
if self.get("flags") and self.flags.get("ignore_exchange_rate"):
ignore_exchange_rate = True
@@ -1136,27 +1144,21 @@ class JournalEntry(AccountsController):
self.validate_total_debit_and_credit()
def get_values(self):
cond = (
" and outstanding_amount <= {0}".format(self.write_off_amount)
if flt(self.write_off_amount) > 0
else ""
)
cond = f" and outstanding_amount <= {self.write_off_amount}" if flt(self.write_off_amount) > 0 else ""
if self.write_off_based_on == "Accounts Receivable":
return frappe.db.sql(
"""select name, debit_to as account, customer as party, outstanding_amount
from `tabSales Invoice` where docstatus = 1 and company = %s
and outstanding_amount > 0 %s"""
% ("%s", cond),
from `tabSales Invoice` where docstatus = 1 and company = {}
and outstanding_amount > 0 {}""".format("%s", cond),
self.company,
as_dict=True,
)
elif self.write_off_based_on == "Accounts Payable":
return frappe.db.sql(
"""select name, credit_to as account, supplier as party, outstanding_amount
from `tabPurchase Invoice` where docstatus = 1 and company = %s
and outstanding_amount > 0 %s"""
% ("%s", cond),
from `tabPurchase Invoice` where docstatus = 1 and company = {}
and outstanding_amount > 0 {}""".format("%s", cond),
self.company,
as_dict=True,
)
@@ -1267,7 +1269,7 @@ def get_payment_entry_against_order(
"amount_field_bank": amount_field_bank,
"amount": amount,
"debit_in_account_currency": debit_in_account_currency,
"remarks": "Advance Payment received against {0} {1}".format(dt, dn),
"remarks": f"Advance Payment received against {dt} {dn}",
"is_advance": "Yes",
"bank_account": bank_account,
"journal_entry": journal_entry,
@@ -1306,7 +1308,7 @@ def get_payment_entry_against_invoice(
"amount_field_bank": amount_field_bank,
"amount": amount if amount else abs(ref_doc.outstanding_amount),
"debit_in_account_currency": debit_in_account_currency,
"remarks": "Payment received against {0} {1}. {2}".format(dt, dn, ref_doc.remarks),
"remarks": f"Payment received against {dt} {dn}. {ref_doc.remarks}",
"is_advance": "No",
"bank_account": bank_account,
"journal_entry": journal_entry,
@@ -1332,9 +1334,7 @@ def get_payment_entry(ref_doc, args):
)
je = frappe.new_doc("Journal Entry")
je.update(
{"voucher_type": "Bank Entry", "company": ref_doc.company, "remark": args.get("remarks")}
)
je.update({"voucher_type": "Bank Entry", "company": ref_doc.company, "remark": args.get("remarks")})
party_row = je.append(
"accounts",
@@ -1357,9 +1357,7 @@ def get_payment_entry(ref_doc, args):
bank_row = je.append("accounts")
# Make it bank_details
bank_account = get_default_bank_cash_account(
ref_doc.company, "Bank", account=args.get("bank_account")
)
bank_account = get_default_bank_cash_account(ref_doc.company, "Bank", account=args.get("bank_account"))
if bank_account:
bank_row.update(bank_account)
# Modified to include the posting date for which the exchange rate is required.
@@ -1399,7 +1397,7 @@ def get_against_jv(doctype, txt, searchfield, start, page_len, filters):
return []
return frappe.db.sql(
"""
f"""
SELECT jv.name, jv.posting_date, jv.user_remark
FROM `tabJournal Entry` jv, `tabJournal Entry Account` jv_detail
WHERE jv_detail.parent = jv.name
@@ -1410,16 +1408,14 @@ def get_against_jv(doctype, txt, searchfield, start, page_len, filters):
OR jv_detail.reference_type = ''
)
AND jv.docstatus = 1
AND jv.`{0}` LIKE %(txt)s
AND jv.`{searchfield}` LIKE %(txt)s
ORDER BY jv.name DESC
LIMIT %(limit)s offset %(offset)s
""".format(
searchfield
),
""",
dict(
account=filters.get("account"),
party=cstr(filters.get("party")),
txt="%{0}%".format(txt),
txt=f"%{txt}%",
offset=start,
limit=page_len,
),
@@ -1441,19 +1437,15 @@ def get_outstanding(args):
condition = " and party=%(party)s" if args.get("party") else ""
against_jv_amount = frappe.db.sql(
"""
f"""
select sum(debit_in_account_currency) - sum(credit_in_account_currency)
from `tabJournal Entry Account` where parent=%(docname)s and account=%(account)s {0}
and (reference_type is null or reference_type = '')""".format(
condition
),
from `tabJournal Entry Account` where parent=%(docname)s and account=%(account)s {condition}
and (reference_type is null or reference_type = '')""",
args,
)
against_jv_amount = flt(against_jv_amount[0][0]) if against_jv_amount else 0
amount_field = (
"credit_in_account_currency" if against_jv_amount > 0 else "debit_in_account_currency"
)
amount_field = "credit_in_account_currency" if against_jv_amount > 0 else "debit_in_account_currency"
return {amount_field: abs(against_jv_amount)}
elif args.get("doctype") in ("Sales Invoice", "Purchase Invoice"):
party_type = "Customer" if args.get("doctype") == "Sales Invoice" else "Supplier"
@@ -1466,9 +1458,7 @@ def get_outstanding(args):
due_date = invoice.get("due_date")
exchange_rate = (
invoice.conversion_rate if (args.get("account_currency") != company_currency) else 1
)
exchange_rate = invoice.conversion_rate if (args.get("account_currency") != company_currency) else 1
if args["doctype"] == "Sales Invoice":
amount_field = (
@@ -1506,9 +1496,7 @@ def get_party_account_and_currency(company, party_type, party):
@frappe.whitelist()
def get_account_details_and_party_type(
account, date, company, debit=None, credit=None, exchange_rate=None
):
def get_account_details_and_party_type(account, date, company, debit=None, credit=None, exchange_rate=None):
"""Returns dict of account details and party type to be set in Journal Entry on selection of account."""
if not frappe.has_permission("Account"):
frappe.msgprint(_("No Permission"), raise_exception=1)

View File

@@ -69,10 +69,8 @@ class TestJournalEntry(unittest.TestCase):
self.assertTrue(
frappe.db.sql(
"""select name from `tabJournal Entry Account`
where reference_type = %s and reference_name = %s and {0}=400""".format(
dr_or_cr
),
f"""select name from `tabJournal Entry Account`
where reference_type = %s and reference_name = %s and {dr_or_cr}=400""",
(submitted_voucher.doctype, submitted_voucher.name),
)
)
@@ -84,9 +82,8 @@ class TestJournalEntry(unittest.TestCase):
def advance_paid_testcase(self, base_jv, test_voucher, dr_or_cr):
# Test advance paid field
advance_paid = frappe.db.sql(
"""select advance_paid from `tab%s`
where name=%s"""
% (test_voucher.doctype, "%s"),
"""select advance_paid from `tab{}`
where name={}""".format(test_voucher.doctype, "%s"),
(test_voucher.name),
)
payment_against_order = base_jv.get("accounts")[0].get(dr_or_cr)
@@ -159,9 +156,7 @@ class TestJournalEntry(unittest.TestCase):
jv.cancel()
def test_multi_currency(self):
jv = make_journal_entry(
"_Test Bank USD - _TC", "_Test Bank - _TC", 100, exchange_rate=50, save=False
)
jv = make_journal_entry("_Test Bank USD - _TC", "_Test Bank - _TC", 100, exchange_rate=50, save=False)
jv.get("accounts")[1].credit_in_account_currency = 5000
jv.submit()
@@ -477,9 +472,7 @@ class TestJournalEntry(unittest.TestCase):
query = query.select(gl[field])
query = query.where(
(gl.voucher_type == "Journal Entry")
& (gl.voucher_no == self.voucher_no)
& (gl.is_cancelled == 0)
(gl.voucher_type == "Journal Entry") & (gl.voucher_no == self.voucher_no) & (gl.is_cancelled == 0)
).orderby(gl.account)
gl_entries = query.run(as_dict=True)

View File

@@ -83,7 +83,10 @@ class TestLedgerMerge(unittest.TestCase):
"account": "Indirect Income - _TC",
"merge_accounts": [
{"account": "Indirect Test Income - _TC", "account_name": "Indirect Test Income"},
{"account": "Administrative Test Income - _TC", "account_name": "Administrative Test Income"},
{
"account": "Administrative Test Income - _TC",
"account_name": "Administrative Test Income",
},
],
}
).insert(ignore_permissions=True)

View File

@@ -52,13 +52,11 @@ def get_loyalty_details(
condition += " and expiry_date>='%s' " % expiry_date
loyalty_point_details = frappe.db.sql(
"""select sum(loyalty_points) as loyalty_points,
f"""select sum(loyalty_points) as loyalty_points,
sum(purchase_amount) as total_spent from `tabLoyalty Point Entry`
where customer=%s and loyalty_program=%s and posting_date <= %s
{condition}
group by customer""".format(
condition=condition
),
group by customer""",
(customer, loyalty_program, expiry_date),
as_dict=1,
)
@@ -79,9 +77,7 @@ def get_loyalty_program_details_with_points(
include_expired_entry=False,
current_transaction_amount=0,
):
lp_details = get_loyalty_program_details(
customer, loyalty_program, company=company, silent=silent
)
lp_details = get_loyalty_program_details(customer, loyalty_program, company=company, silent=silent)
loyalty_program = frappe.get_doc("Loyalty Program", loyalty_program)
lp_details.update(
get_loyalty_details(customer, loyalty_program.name, expiry_date, company, include_expired_entry)

View File

@@ -19,9 +19,7 @@ class TestLoyaltyProgram(unittest.TestCase):
create_records()
def test_loyalty_points_earned_single_tier(self):
frappe.db.set_value(
"Customer", "Test Loyalty Customer", "loyalty_program", "Test Single Loyalty"
)
frappe.db.set_value("Customer", "Test Loyalty Customer", "loyalty_program", "Test Single Loyalty")
# create a new sales invoice
si_original = create_sales_invoice_record()
si_original.insert()
@@ -69,9 +67,7 @@ class TestLoyaltyProgram(unittest.TestCase):
d.cancel()
def test_loyalty_points_earned_multiple_tier(self):
frappe.db.set_value(
"Customer", "Test Loyalty Customer", "loyalty_program", "Test Multiple Loyalty"
)
frappe.db.set_value("Customer", "Test Loyalty Customer", "loyalty_program", "Test Multiple Loyalty")
# assign multiple tier program to the customer
customer = frappe.get_doc("Customer", {"customer_name": "Test Loyalty Customer"})
customer.loyalty_program = frappe.get_doc(
@@ -128,9 +124,7 @@ class TestLoyaltyProgram(unittest.TestCase):
def test_cancel_sales_invoice(self):
"""cancelling the sales invoice should cancel the earned points"""
frappe.db.set_value(
"Customer", "Test Loyalty Customer", "loyalty_program", "Test Single Loyalty"
)
frappe.db.set_value("Customer", "Test Loyalty Customer", "loyalty_program", "Test Single Loyalty")
# create a new sales invoice
si = create_sales_invoice_record()
si.insert()
@@ -148,9 +142,7 @@ class TestLoyaltyProgram(unittest.TestCase):
self.assertEqual(True, (lpe is None))
def test_sales_invoice_return(self):
frappe.db.set_value(
"Customer", "Test Loyalty Customer", "loyalty_program", "Test Single Loyalty"
)
frappe.db.set_value("Customer", "Test Loyalty Customer", "loyalty_program", "Test Single Loyalty")
# create a new sales invoice
si_original = create_sales_invoice_record(2)
si_original.conversion_rate = flt(1)
@@ -346,9 +338,7 @@ def create_records():
).insert()
# create item price
if not frappe.db.exists(
"Item Price", {"price_list": "Standard Selling", "item_code": "Loyal Item"}
):
if not frappe.db.exists("Item Price", {"price_list": "Standard Selling", "item_code": "Loyal Item"}):
frappe.get_doc(
{
"doctype": "Item Price",

View File

@@ -54,9 +54,7 @@ class MonthlyDistribution(Document):
total = sum(flt(d.percentage_allocation) for d in self.get("percentages"))
if flt(total, 2) != 100.0:
frappe.throw(
_("Percentage Allocation should be equal to 100%") + " ({0}%)".format(str(flt(total, 2)))
)
frappe.throw(_("Percentage Allocation should be equal to 100%") + f" ({flt(total, 2)!s}%)")
def get_periodwise_distribution_data(distribution_id, period_list, periodicity):

View File

@@ -83,9 +83,7 @@ class TestOpeningInvoiceCreationTool(FrappeTestCase):
company = "_Test Opening Invoice Company"
party_1, party_2 = make_customer("Customer A"), make_customer("Customer B")
old_default_receivable_account = frappe.db.get_value(
"Company", company, "default_receivable_account"
)
old_default_receivable_account = frappe.db.get_value("Company", company, "default_receivable_account")
frappe.db.set_value("Company", company, "default_receivable_account", "")
if not frappe.db.exists("Cost Center", "_Test Opening Invoice Company - _TOIC"):
@@ -121,9 +119,7 @@ class TestOpeningInvoiceCreationTool(FrappeTestCase):
self.assertTrue(error_log)
# teardown
frappe.db.set_value(
"Company", company, "default_receivable_account", old_default_receivable_account
)
frappe.db.set_value("Company", company, "default_receivable_account", old_default_receivable_account)
def test_renaming_of_invoice_using_invoice_number_field(self):
company = "_Test Opening Invoice Company"
@@ -169,7 +165,7 @@ def get_opening_invoice_creation_dict(**args):
{
"qty": 1.0,
"outstanding_amount": 300,
"party": args.get("party_1") or "_Test {0}".format(party),
"party": args.get("party_1") or f"_Test {party}",
"item_name": "Opening Item",
"due_date": "2016-09-10",
"posting_date": "2016-09-05",
@@ -179,7 +175,7 @@ def get_opening_invoice_creation_dict(**args):
{
"qty": 2.0,
"outstanding_amount": 250,
"party": args.get("party_2") or "_Test {0} 1".format(party),
"party": args.get("party_2") or f"_Test {party} 1",
"item_name": "Opening Item",
"due_date": "2016-09-10",
"posting_date": "2016-09-05",

View File

@@ -38,7 +38,10 @@ class PartyLink(Document):
if existing_party_link:
frappe.throw(
_("{} {} is already linked with {} {}").format(
self.primary_role, bold(self.primary_party), self.secondary_role, bold(self.secondary_party)
self.primary_role,
bold(self.primary_party),
self.secondary_role,
bold(self.secondary_party),
)
)

View File

@@ -134,7 +134,7 @@ class PaymentEntry(AccountsController):
# end: auto-generated types
def __init__(self, *args, **kwargs):
super(PaymentEntry, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
if not self.is_new():
self.setup_party_account_field()
@@ -247,7 +247,7 @@ class PaymentEntry(AccountsController):
"Unreconcile Payment",
"Unreconcile Payment Entries",
)
super(PaymentEntry, self).on_cancel()
super().on_cancel()
self.make_gl_entries(cancel=1)
self.update_outstanding_amounts()
self.update_advance_paid()
@@ -357,9 +357,7 @@ class PaymentEntry(AccountsController):
# If term based allocation is enabled, throw
if (
d.payment_term is None or d.payment_term == ""
) and self.term_based_allocation_enabled_for_reference(
d.reference_doctype, d.reference_name
):
) and self.term_based_allocation_enabled_for_reference(d.reference_doctype, d.reference_name):
frappe.throw(
_(
"{0} has Payment Term based allocation enabled. Select a Payment Term for Row #{1} in Payment References section"
@@ -371,7 +369,9 @@ class PaymentEntry(AccountsController):
# The reference has already been fully paid
if not latest:
frappe.throw(
_("{0} {1} has already been fully paid.").format(_(d.reference_doctype), d.reference_name)
_("{0} {1} has already been fully paid.").format(
_(d.reference_doctype), d.reference_name
)
)
# The reference has already been partly paid
elif (
@@ -395,14 +395,14 @@ class PaymentEntry(AccountsController):
and latest.payment_term_outstanding
and (flt(d.allocated_amount) > flt(latest.payment_term_outstanding))
)
and self.term_based_allocation_enabled_for_reference(d.reference_doctype, d.reference_name)
and self.term_based_allocation_enabled_for_reference(
d.reference_doctype, d.reference_name
)
):
frappe.throw(
_(
"Row #{0}: Allocated amount:{1} is greater than outstanding amount:{2} for Payment Term {3}"
).format(
d.idx, d.allocated_amount, latest.payment_term_outstanding, d.payment_term
)
).format(d.idx, d.allocated_amount, latest.payment_term_outstanding, d.payment_term)
)
if (flt(d.allocated_amount)) > 0 and flt(d.allocated_amount) > flt(latest.outstanding_amount):
@@ -445,7 +445,9 @@ class PaymentEntry(AccountsController):
if self.party:
if not self.contact_person:
set_contact_details(self, party=frappe._dict({"name": self.party}), party_type=self.party_type)
set_contact_details(
self, party=frappe._dict({"name": self.party}), party_type=self.party_type
)
else:
complete_contact_details(self)
if not self.party_balance:
@@ -527,7 +529,9 @@ class PaymentEntry(AccountsController):
else:
if ref_doc:
if self.paid_from_account_currency == ref_doc.currency:
self.source_exchange_rate = ref_doc.get("exchange_rate") or ref_doc.get("conversion_rate")
self.source_exchange_rate = ref_doc.get("exchange_rate") or ref_doc.get(
"conversion_rate"
)
if not self.source_exchange_rate:
self.source_exchange_rate = get_exchange_rate(
@@ -564,7 +568,7 @@ class PaymentEntry(AccountsController):
if d.reference_doctype not in valid_reference_doctypes:
frappe.throw(
_("Reference Doctype must be one of {0}").format(
comma_or((_(d) for d in valid_reference_doctypes))
comma_or(_(d) for d in valid_reference_doctypes)
)
)
@@ -587,7 +591,8 @@ class PaymentEntry(AccountsController):
if d.reference_doctype in frappe.get_hooks("invoice_doctypes"):
if self.party_type == "Customer":
ref_party_account = (
get_party_account_based_on_invoice_discounting(d.reference_name) or ref_doc.debit_to
get_party_account_based_on_invoice_discounting(d.reference_name)
or ref_doc.debit_to
)
elif self.party_type == "Supplier":
ref_party_account = ref_doc.credit_to
@@ -600,7 +605,10 @@ class PaymentEntry(AccountsController):
):
frappe.throw(
_("{0} {1} is associated with {2}, but Party Account is {3}").format(
_(d.reference_doctype), d.reference_name, ref_party_account, self.party_account
_(d.reference_doctype),
d.reference_name,
ref_party_account,
self.party_account,
)
)
@@ -611,7 +619,9 @@ class PaymentEntry(AccountsController):
)
if ref_doc.docstatus != 1:
frappe.throw(_("{0} {1} must be submitted").format(_(d.reference_doctype), d.reference_name))
frappe.throw(
_("{0} {1} must be submitted").format(_(d.reference_doctype), d.reference_name)
)
def get_valid_reference_doctypes(self):
if self.party_type == "Customer":
@@ -782,9 +792,7 @@ class PaymentEntry(AccountsController):
if not (is_single_currency and reference_is_multi_currency):
return allocated_amount
allocated_amount = flt(
allocated_amount / ref_exchange_rate, self.precision("total_allocated_amount")
)
allocated_amount = flt(allocated_amount / ref_exchange_rate, self.precision("total_allocated_amount"))
return allocated_amount
@@ -847,7 +855,6 @@ class PaymentEntry(AccountsController):
accounts = []
for d in self.taxes:
if d.account_head == tax_withholding_details.get("account_head"):
# Preserve user updated included in paid amount
if d.included_in_paid_amount:
tax_withholding_details.update({"included_in_paid_amount": d.included_in_paid_amount})
@@ -953,9 +960,9 @@ class PaymentEntry(AccountsController):
def calculate_base_allocated_amount_for_reference(self, d) -> float:
base_allocated_amount = 0
advance_payment_doctypes = frappe.get_hooks(
"advance_payment_receivable_doctypes"
) + frappe.get_hooks("advance_payment_payable_doctypes")
advance_payment_doctypes = frappe.get_hooks("advance_payment_receivable_doctypes") + frappe.get_hooks(
"advance_payment_payable_doctypes"
)
if d.reference_doctype in advance_payment_doctypes:
# When referencing Sales/Purchase Order, use the source/target exchange rate depending on payment type.
# This is so there are no Exchange Gain/Loss generated for such doctypes
@@ -970,7 +977,6 @@ class PaymentEntry(AccountsController):
flt(d.allocated_amount) * flt(exchange_rate), self.precision("base_paid_amount")
)
else:
# Use source/target exchange rate, so no difference amount is calculated.
# then update exchange gain/loss amount in reference table
# if there is an exchange gain/loss amount in reference table, submit a JE for that
@@ -1108,7 +1114,6 @@ class PaymentEntry(AccountsController):
)
]
else:
remarks = [
_("Amount {0} {1} {2} {3}").format(
_(self.party_account_currency),
@@ -1128,14 +1133,19 @@ class PaymentEntry(AccountsController):
if d.allocated_amount:
remarks.append(
_("Amount {0} {1} against {2} {3}").format(
_(self.party_account_currency), d.allocated_amount, d.reference_doctype, d.reference_name
_(self.party_account_currency),
d.allocated_amount,
d.reference_doctype,
d.reference_name,
)
)
for d in self.get("deductions"):
if d.amount:
remarks.append(
_("Amount {0} {1} deducted against {2}").format(_(self.company_currency), d.amount, d.account)
_("Amount {0} {1} deducted against {2}").format(
_(self.company_currency), d.amount, d.account
)
)
self.set("remarks", "\n".join(remarks))
@@ -1209,21 +1219,31 @@ class PaymentEntry(AccountsController):
dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
cost_center = self.cost_center
if d.reference_doctype == "Sales Invoice" and not cost_center:
cost_center = frappe.db.get_value(d.reference_doctype, d.reference_name, "cost_center")
cost_center = frappe.db.get_value(
d.reference_doctype, d.reference_name, "cost_center"
)
gle = party_gl_dict.copy()
allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference(d)
allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference(
d
)
reverse_dr_or_cr = 0
if d.reference_doctype in ["Sales Invoice", "Purchase Invoice"]:
is_return = frappe.db.get_value(d.reference_doctype, d.reference_name, "is_return")
payable_party_types = get_party_types_from_account_type("Payable")
receivable_party_types = get_party_types_from_account_type("Receivable")
if is_return and self.party_type in receivable_party_types and (self.payment_type == "Pay"):
if (
is_return
and self.party_type in receivable_party_types
and (self.payment_type == "Pay")
):
reverse_dr_or_cr = 1
elif (
is_return and self.party_type in payable_party_types and (self.payment_type == "Receive")
is_return
and self.party_type in payable_party_types
and (self.payment_type == "Receive")
):
reverse_dr_or_cr = 1
@@ -1306,9 +1326,7 @@ class PaymentEntry(AccountsController):
if getdate(posting_date) < getdate(self.posting_date):
posting_date = self.posting_date
dr_or_cr = (
"credit" if invoice.reference_doctype in ["Sales Invoice", "Payment Entry"] else "debit"
)
dr_or_cr = "credit" if invoice.reference_doctype in ["Sales Invoice", "Payment Entry"] else "debit"
args_dict["account"] = invoice.account
args_dict[dr_or_cr] = invoice.allocated_amount
args_dict[dr_or_cr + "_in_account_currency"] = invoice.allocated_amount
@@ -1694,7 +1712,8 @@ def get_outstanding_reference_documents(args, validate=False):
return []
elif supplier_status["hold_type"] == "Payments":
if (
not supplier_status["release_date"] or getdate(nowdate()) <= supplier_status["release_date"]
not supplier_status["release_date"]
or getdate(nowdate()) <= supplier_status["release_date"]
):
return []
@@ -1704,7 +1723,7 @@ def get_outstanding_reference_documents(args, validate=False):
# Get positive outstanding sales /purchase invoices
condition = ""
if args.get("voucher_type") and args.get("voucher_no"):
condition = " and voucher_type={0} and voucher_no={1}".format(
condition = " and voucher_type={} and voucher_no={}".format(
frappe.db.escape(args["voucher_type"]), frappe.db.escape(args["voucher_no"])
)
common_filter.append(ple.voucher_type == args["voucher_type"])
@@ -1719,7 +1738,7 @@ def get_outstanding_reference_documents(args, validate=False):
active_dimensions = get_dimensions()[0]
for dim in active_dimensions:
if args.get(dim.fieldname):
condition += " and {0}='{1}'".format(dim.fieldname, args.get(dim.fieldname))
condition += f" and {dim.fieldname}='{args.get(dim.fieldname)}'"
accounting_dimensions_filter.append(ple[dim.fieldname] == args.get(dim.fieldname))
date_fields_dict = {
@@ -1729,21 +1748,21 @@ def get_outstanding_reference_documents(args, validate=False):
for fieldname, date_fields in date_fields_dict.items():
if args.get(date_fields[0]) and args.get(date_fields[1]):
condition += " and {0} between '{1}' and '{2}'".format(
condition += " and {} between '{}' and '{}'".format(
fieldname, args.get(date_fields[0]), args.get(date_fields[1])
)
posting_and_due_date.append(ple[fieldname][args.get(date_fields[0]) : args.get(date_fields[1])])
elif args.get(date_fields[0]):
# if only from date is supplied
condition += " and {0} >= '{1}'".format(fieldname, args.get(date_fields[0]))
condition += f" and {fieldname} >= '{args.get(date_fields[0])}'"
posting_and_due_date.append(ple[fieldname].gte(args.get(date_fields[0])))
elif args.get(date_fields[1]):
# if only to date is supplied
condition += " and {0} <= '{1}'".format(fieldname, args.get(date_fields[1]))
condition += f" and {fieldname} <= '{args.get(date_fields[1])}'"
posting_and_due_date.append(ple[fieldname].lte(args.get(date_fields[1])))
if args.get("company"):
condition += " and company = {0}".format(frappe.db.escape(args.get("company")))
condition += " and company = {}".format(frappe.db.escape(args.get("company")))
common_filter.append(ple.company == args.get("company"))
outstanding_invoices = []
@@ -1859,12 +1878,10 @@ def split_invoices_based_on_payment_terms(outstanding_invoices, company) -> list
return outstanding_invoices_after_split
def get_currency_data(outstanding_invoices: list, company: str = None) -> dict:
def get_currency_data(outstanding_invoices: list, company: str | None = None) -> dict:
"""Get currency and conversion data for a list of invoices."""
exc_rates = frappe._dict()
company_currency = (
frappe.db.get_value("Company", company, "default_currency") if company else None
)
company_currency = frappe.db.get_value("Company", company, "default_currency") if company else None
for doctype in ["Sales Invoice", "Purchase Invoice"]:
invoices = [x.voucher_no for x in outstanding_invoices if x.voucher_type == doctype]
@@ -1959,7 +1976,7 @@ def get_orders_to_be_billed(
active_dimensions = get_dimensions()[0]
for dim in active_dimensions:
if filters.get(dim.fieldname):
condition += " and {0}='{1}'".format(dim.fieldname, filters.get(dim.fieldname))
condition += f" and {dim.fieldname}='{filters.get(dim.fieldname)}'"
if party_account_currency == company_currency:
grand_total_field = "base_grand_total"
@@ -2109,18 +2126,14 @@ def get_account_details(account, date, cost_center=None):
frappe.has_permission("Payment Entry", throw=True)
# to check if the passed account is accessible under reference doctype Payment Entry
account_list = frappe.get_list(
"Account", {"name": account}, reference_doctype="Payment Entry", limit=1
)
account_list = frappe.get_list("Account", {"name": account}, reference_doctype="Payment Entry", limit=1)
# There might be some user permissions which will allow account under certain doctypes
# except for Payment Entry, only in such case we should throw permission error
if not account_list:
frappe.throw(_("Account: {0} is not permitted under Payment Entry").format(account))
account_balance = get_balance_on(
account, date, cost_center=cost_center, ignore_account_permission=True
)
account_balance = get_balance_on(account, date, cost_center=cost_center, ignore_account_permission=True)
return frappe._dict(
{
@@ -2167,9 +2180,7 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
total_amount = outstanding_amount = exchange_rate = account = None
ref_doc = frappe.get_doc(reference_doctype, reference_name)
company_currency = ref_doc.get("company_currency") or erpnext.get_company_currency(
ref_doc.company
)
company_currency = ref_doc.get("company_currency") or erpnext.get_company_currency(ref_doc.company)
if reference_doctype == "Dunning":
total_amount = outstanding_amount = ref_doc.get("dunning_amount")
@@ -2178,9 +2189,7 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
elif reference_doctype == "Journal Entry" and ref_doc.docstatus == 1:
total_amount = ref_doc.get("total_amount")
if ref_doc.multi_currency:
exchange_rate = get_exchange_rate(
party_account_currency, company_currency, ref_doc.posting_date
)
exchange_rate = get_exchange_rate(party_account_currency, company_currency, ref_doc.posting_date)
else:
exchange_rate = 1
outstanding_amount = get_outstanding_on_journal_entry(reference_name)
@@ -2250,9 +2259,7 @@ def get_payment_entry(
):
doc = frappe.get_doc(dt, dn)
over_billing_allowance = frappe.db.get_single_value("Accounts Settings", "over_billing_allowance")
if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) >= (
100.0 + over_billing_allowance
):
if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) >= (100.0 + over_billing_allowance):
frappe.throw(_("Can only make payment against unbilled {0}").format(_(dt)))
if not party_type:
@@ -2305,9 +2312,7 @@ def get_payment_entry(
pe.paid_from_account_currency = (
party_account_currency if payment_type == "Receive" else bank.account_currency
)
pe.paid_to_account_currency = (
party_account_currency if payment_type == "Pay" else bank.account_currency
)
pe.paid_to_account_currency = party_account_currency if payment_type == "Pay" else bank.account_currency
pe.paid_amount = paid_amount
pe.received_amount = received_amount
pe.letter_head = doc.get("letter_head")
@@ -2336,7 +2341,6 @@ def get_payment_entry(
doc.payment_terms_template,
"allocate_payment_based_on_payment_terms",
):
for reference in get_reference_as_per_payment_terms(
doc.payment_schedule, dt, dn, doc, grand_total, outstanding_amount, party_account_currency
):
@@ -2524,9 +2528,7 @@ def set_paid_amount_and_received_amount(
return paid_amount, received_amount
def apply_early_payment_discount(
paid_amount, received_amount, doc, party_account_currency, reference_date
):
def apply_early_payment_discount(paid_amount, received_amount, doc, party_account_currency, reference_date):
total_discount = 0
valid_discounts = []
eligible_for_payments = ["Sales Order", "Sales Invoice", "Purchase Order", "Purchase Invoice"]
@@ -2536,7 +2538,6 @@ def apply_early_payment_discount(
if doc.doctype in eligible_for_payments and has_payment_schedule:
for term in doc.payment_schedule:
if not term.discounted_amount and term.discount and reference_date <= term.discount_date:
if term.discount_type == "Percentage":
grand_total = doc.get("grand_total") if is_multi_currency else doc.get("base_grand_total")
discount_amount = flt(grand_total) * (term.discount / 100)
@@ -2565,9 +2566,7 @@ def apply_early_payment_discount(
return paid_amount, received_amount, total_discount, valid_discounts
def set_pending_discount_loss(
pe, doc, discount_amount, base_total_discount_loss, party_account_currency
):
def set_pending_discount_loss(pe, doc, discount_amount, base_total_discount_loss, party_account_currency):
# If multi-currency, get base discount amount to adjust with base currency deductions/losses
if party_account_currency != doc.company_currency:
discount_amount = discount_amount * doc.get("conversion_rate", 1)
@@ -2587,7 +2586,8 @@ def set_pending_discount_loss(
pe.set_gain_or_loss(
account_details={
"account": frappe.get_cached_value("Company", pe.company, account_type),
"cost_center": pe.cost_center or frappe.get_cached_value("Company", pe.company, "cost_center"),
"cost_center": pe.cost_center
or frappe.get_cached_value("Company", pe.company, "cost_center"),
"amount": discount_amount * positive_negative,
}
)
@@ -2610,9 +2610,7 @@ def split_early_payment_discount_loss(pe, doc, valid_discounts) -> float:
def get_total_discount_percent(doc, valid_discounts) -> float:
"""Get total percentage and amount discount applied as a percentage."""
total_discount_percent = (
sum(
discount.get("discount") for discount in valid_discounts if discount.get("type") == "Percentage"
)
sum(discount.get("discount") for discount in valid_discounts if discount.get("type") == "Percentage")
or 0.0
)
@@ -2655,9 +2653,7 @@ def add_tax_discount_loss(pe, doc, total_discount_percentage) -> float:
# The same account head could be used more than once
for tax in doc.get("taxes", []):
base_tax_loss = tax.get("base_tax_amount_after_discount_amount") * (
total_discount_percentage / 100
)
base_tax_loss = tax.get("base_tax_amount_after_discount_amount") * (total_discount_percentage / 100)
account = tax.get("account_head")
if not tax_discount_loss.get(account):
@@ -2674,7 +2670,8 @@ def add_tax_discount_loss(pe, doc, total_discount_percentage) -> float:
"deductions",
{
"account": account,
"cost_center": pe.cost_center or frappe.get_cached_value("Company", pe.company, "cost_center"),
"cost_center": pe.cost_center
or frappe.get_cached_value("Company", pe.company, "cost_center"),
"amount": flt(loss, precision),
},
)
@@ -2697,7 +2694,8 @@ def get_reference_as_per_payment_terms(
if not is_multi_currency_acc:
# If accounting is done in company currency for multi-currency transaction
payment_term_outstanding = flt(
payment_term_outstanding * doc.get("conversion_rate"), payment_term.precision("payment_amount")
payment_term_outstanding * doc.get("conversion_rate"),
payment_term.precision("payment_amount"),
)
if payment_term_outstanding:
@@ -2725,7 +2723,7 @@ def get_paid_amount(dt, dn, party_type, party, account, due_date):
dr_or_cr = "debit_in_account_currency - credit_in_account_currency"
paid_amount = frappe.db.sql(
"""
f"""
select ifnull(sum({dr_or_cr}), 0) as paid_amount
from `tabGL Entry`
where against_voucher_type = %s
@@ -2735,9 +2733,7 @@ def get_paid_amount(dt, dn, party_type, party, account, due_date):
and account = %s
and due_date = %s
and {dr_or_cr} > 0
""".format(
dr_or_cr=dr_or_cr
),
""",
(dt, dn, party_type, party, account, due_date),
)

View File

@@ -1,7 +1,6 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe import qb
@@ -10,7 +9,6 @@ from frappe.utils import add_days, flt, nowdate
from erpnext.accounts.doctype.account.test_account import create_account
from erpnext.accounts.doctype.payment_entry.payment_entry import (
InvalidPaymentEntry,
get_outstanding_reference_documents,
get_payment_entry,
get_reference_details,
@@ -162,7 +160,7 @@ class TestPaymentEntry(FrappeTestCase):
supplier.on_hold = 0
supplier.save()
except:
except Exception:
pass
else:
raise Exception
@@ -469,9 +467,7 @@ class TestPaymentEntry(FrappeTestCase):
si.save()
si.submit()
pe = get_payment_entry(
"Sales Invoice", si.name, bank_account="_Test Bank - _TC", bank_amount=4700
)
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC", bank_amount=4700)
pe.reference_no = si.name
pe.reference_date = nowdate()
@@ -638,9 +634,7 @@ class TestPaymentEntry(FrappeTestCase):
pe.set_exchange_rate()
pe.set_amounts()
self.assertEqual(
pe.source_exchange_rate, 65.1, "{0} is not equal to {1}".format(pe.source_exchange_rate, 65.1)
)
self.assertEqual(pe.source_exchange_rate, 65.1, f"{pe.source_exchange_rate} is not equal to {65.1}")
def test_internal_transfer_usd_to_inr(self):
pe = frappe.new_doc("Payment Entry")
@@ -896,9 +890,7 @@ class TestPaymentEntry(FrappeTestCase):
cost_center = "_Test Cost Center for BS Account - _TC"
create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
pi = make_purchase_invoice_against_cost_center(
cost_center=cost_center, credit_to="Creditors - _TC"
)
pi = make_purchase_invoice_against_cost_center(cost_center=cost_center, credit_to="Creditors - _TC")
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
self.assertEqual(pe.cost_center, pi.cost_center)
@@ -939,9 +931,7 @@ class TestPaymentEntry(FrappeTestCase):
si = create_sales_invoice_against_cost_center(cost_center=cost_center, debit_to="Debtors - _TC")
account_balance = get_balance_on(account="_Test Bank - _TC", cost_center=si.cost_center)
party_balance = get_balance_on(
party_type="Customer", party=si.customer, cost_center=si.cost_center
)
party_balance = get_balance_on(party_type="Customer", party=si.customer, cost_center=si.cost_center)
party_account_balance = get_balance_on(si.debit_to, cost_center=si.cost_center)
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC")
@@ -1203,7 +1193,7 @@ class TestPaymentEntry(FrappeTestCase):
Overallocation validation shouldn't fire for Template without "Allocate Payment based on Payment Terms" enabled
"""
customer = create_customer()
create_customer()
create_payment_terms_template()
template = frappe.get_doc("Payment Terms Template", "Test Receivable Template")
@@ -1262,9 +1252,7 @@ class TestPaymentEntry(FrappeTestCase):
create_payment_terms_template()
# SI has an earlier due date and SI2 has a later due date
si = create_sales_invoice(
qty=1, rate=100, customer=customer, posting_date=add_days(nowdate(), -4)
)
si = create_sales_invoice(qty=1, rate=100, customer=customer, posting_date=add_days(nowdate(), -4))
si2 = create_sales_invoice(do_not_save=1, qty=1, rate=100, customer=customer)
si2.payment_terms_template = "Test Receivable Template"
si2.submit()
@@ -1363,8 +1351,6 @@ class TestPaymentEntry(FrappeTestCase):
self.check_gl_entries()
def test_ledger_entries_for_advance_as_liability(self):
from erpnext.accounts.doctype.account.test_account import create_account
company = "_Test Company"
advance_account = create_account(
@@ -1466,7 +1452,7 @@ class TestPaymentEntry(FrappeTestCase):
self.check_pl_entries()
# Unreconcile
unrecon = (
(
frappe.get_doc(
{
"doctype": "Unreconcile Payment",
@@ -1554,8 +1540,6 @@ class TestPaymentEntry(FrappeTestCase):
self.assertEqual(len(pr.payments), 0)
def test_advance_reverse_payment_reconciliation(self):
from erpnext.accounts.doctype.account.test_account import create_account
company = "_Test Company"
customer = create_customer(frappe.generate_hash(length=10), "INR")
advance_account = create_account(
@@ -1645,14 +1629,16 @@ class TestPaymentEntry(FrappeTestCase):
self.check_pl_entries()
# Unreconcile
unrecon = (
(
frappe.get_doc(
{
"doctype": "Unreconcile Payment",
"company": company,
"voucher_type": pe.doctype,
"voucher_no": pe.name,
"allocations": [{"reference_doctype": reverse_pe.doctype, "reference_name": reverse_pe.name}],
"allocations": [
{"reference_doctype": reverse_pe.doctype, "reference_name": reverse_pe.name}
],
}
)
.save()
@@ -1703,12 +1689,11 @@ def create_payment_entry(**args):
def create_payment_terms_template():
create_payment_term("Basic Amount Receivable")
create_payment_term("Tax Receivable")
if not frappe.db.exists("Payment Terms Template", "Test Receivable Template"):
payment_term_template = frappe.get_doc(
frappe.get_doc(
{
"doctype": "Payment Terms Template",
"template_name": "Test Receivable Template",

View File

@@ -137,9 +137,9 @@ class PaymentLedgerEntry(Document):
):
if not self.get(dimension.fieldname):
frappe.throw(
_("Accounting Dimension <b>{0}</b> is required for 'Profit and Loss' account {1}.").format(
dimension.label, self.account
)
_(
"Accounting Dimension <b>{0}</b> is required for 'Profit and Loss' account {1}."
).format(dimension.label, self.account)
)
if (
@@ -150,9 +150,9 @@ class PaymentLedgerEntry(Document):
):
if not self.get(dimension.fieldname):
frappe.throw(
_("Accounting Dimension <b>{0}</b> is required for 'Balance Sheet' account {1}.").format(
dimension.label, self.account
)
_(
"Accounting Dimension <b>{0}</b> is required for 'Balance Sheet' account {1}."
).format(dimension.label, self.account)
)
def validate(self):

View File

@@ -84,11 +84,14 @@ class TestPaymentLedgerEntry(FrappeTestCase):
self.customer = customer.name
def create_sales_invoice(
self, qty=1, rate=100, posting_date=nowdate(), do_not_save=False, do_not_submit=False
self, qty=1, rate=100, posting_date=None, do_not_save=False, do_not_submit=False
):
"""
Helper function to populate default values in sales invoice
"""
if posting_date is None:
posting_date = nowdate()
sinv = create_sales_invoice(
qty=qty,
rate=rate,
@@ -112,10 +115,12 @@ class TestPaymentLedgerEntry(FrappeTestCase):
)
return sinv
def create_payment_entry(self, amount=100, posting_date=nowdate()):
def create_payment_entry(self, amount=100, posting_date=None):
"""
Helper function to populate default values in payment entry
"""
if posting_date is None:
posting_date = nowdate()
payment = create_payment_entry(
company=self.company,
payment_type="Receive",
@@ -128,9 +133,10 @@ class TestPaymentLedgerEntry(FrappeTestCase):
payment.posting_date = posting_date
return payment
def create_sales_order(
self, qty=1, rate=100, posting_date=nowdate(), do_not_save=False, do_not_submit=False
):
def create_sales_order(self, qty=1, rate=100, posting_date=None, do_not_save=False, do_not_submit=False):
if posting_date is None:
posting_date = nowdate()
so = make_sales_order(
company=self.company,
transaction_date=posting_date,
@@ -159,9 +165,7 @@ class TestPaymentLedgerEntry(FrappeTestCase):
for doctype in doctype_list:
qb.from_(qb.DocType(doctype)).delete().where(qb.DocType(doctype).company == self.company).run()
def create_journal_entry(
self, acc1=None, acc2=None, amount=0, posting_date=None, cost_center=None
):
def create_journal_entry(self, acc1=None, acc2=None, amount=0, posting_date=None, cost_center=None):
je = frappe.new_doc("Journal Entry")
je.posting_date = posting_date or nowdate()
je.company = self.company
@@ -319,9 +323,7 @@ class TestPaymentLedgerEntry(FrappeTestCase):
ple.amount,
ple.delinked,
)
.where(
(ple.against_voucher_type == cr_note1.doctype) & (ple.against_voucher_no == cr_note1.name)
)
.where((ple.against_voucher_type == cr_note1.doctype) & (ple.against_voucher_no == cr_note1.name))
.orderby(ple.creation)
.run(as_dict=True)
)
@@ -362,9 +364,7 @@ class TestPaymentLedgerEntry(FrappeTestCase):
)
cr_note2.is_return = 1
cr_note2 = cr_note2.save().submit()
je1 = self.create_journal_entry(
self.debit_to, self.debit_to, amount, posting_date=transaction_date
)
je1 = self.create_journal_entry(self.debit_to, self.debit_to, amount, posting_date=transaction_date)
je1.get("accounts")[0].party_type = je1.get("accounts")[1].party_type = "Customer"
je1.get("accounts")[0].party = je1.get("accounts")[1].party = self.customer
je1.get("accounts")[0].reference_type = cr_note2.doctype
@@ -419,9 +419,7 @@ class TestPaymentLedgerEntry(FrappeTestCase):
ple.amount,
ple.delinked,
)
.where(
(ple.against_voucher_type == cr_note2.doctype) & (ple.against_voucher_no == cr_note2.name)
)
.where((ple.against_voucher_type == cr_note2.doctype) & (ple.against_voucher_no == cr_note2.name))
.orderby(ple.creation)
.run(as_dict=True)
)
@@ -518,7 +516,7 @@ class TestPaymentLedgerEntry(FrappeTestCase):
amount = 100
so = self.create_sales_order(qty=1, rate=amount, posting_date=transaction_date).save().submit()
pe = get_payment_entry(so.doctype, so.name).save().submit()
get_payment_entry(so.doctype, so.name).save().submit()
so.reload()
so.cancel()

View File

@@ -90,9 +90,7 @@ def make_journal_entry(doc, supplier, mode_of_payment=None):
je = frappe.new_doc("Journal Entry")
je.payment_order = doc.name
je.posting_date = nowdate()
mode_of_payment_type = frappe._dict(
frappe.get_all("Mode of Payment", fields=["name", "type"], as_list=1)
)
mode_of_payment_type = frappe._dict(frappe.get_all("Mode of Payment", fields=["name", "type"], as_list=1))
je.voucher_type = "Bank Entry"
if mode_of_payment and mode_of_payment_type.get(mode_of_payment) == "Cash":

View File

@@ -1,7 +1,6 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase
@@ -41,9 +40,7 @@ class TestPaymentOrder(FrappeTestCase):
payment_entry.insert()
payment_entry.submit()
doc = create_payment_order_against_payment_entry(
payment_entry, "Payment Entry", self.bank_account
)
doc = create_payment_order_against_payment_entry(payment_entry, "Payment Entry", self.bank_account)
reference_doc = doc.get("references")[0]
self.assertEqual(reference_doc.reference_name, payment_entry.name)
self.assertEqual(reference_doc.reference_doctype, "Payment Entry")

View File

@@ -67,7 +67,7 @@ class PaymentReconciliation(Document):
# end: auto-generated types
def __init__(self, *args, **kwargs):
super(PaymentReconciliation, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.common_filter_conditions = []
self.accounting_dimension_filter_conditions = []
self.ple_posting_date_filter = []
@@ -286,7 +286,6 @@ class PaymentReconciliation(Document):
self.return_invoices = self.return_invoices_query.run(as_dict=True)
def get_dr_or_cr_notes(self):
self.build_qb_filter_conditions(get_return_invoices=True)
ple = qb.DocType("Payment Ledger Entry")
@@ -412,9 +411,7 @@ class PaymentReconciliation(Document):
payment_entry[0].get("reference_name")
)
new_difference_amount = self.get_difference_amount(
payment_entry[0], invoice[0], allocated_amount
)
new_difference_amount = self.get_difference_amount(payment_entry[0], invoice[0], allocated_amount)
return new_difference_amount
@frappe.whitelist()
@@ -532,9 +529,9 @@ class PaymentReconciliation(Document):
if running_doc:
frappe.throw(
_("A Reconciliation Job {0} is running for the same filters. Cannot reconcile now").format(
get_link_to_form("Auto Reconcile", running_doc)
)
_(
"A Reconciliation Job {0} is running for the same filters. Cannot reconcile now"
).format(get_link_to_form("Auto Reconcile", running_doc))
)
return
@@ -627,9 +624,7 @@ class PaymentReconciliation(Document):
invoice_exchange_map.update(purchase_invoice_map)
journals = [
d.get("invoice_number") for d in invoices if d.get("invoice_type") == "Journal Entry"
]
journals = [d.get("invoice_number") for d in invoices if d.get("invoice_type") == "Journal Entry"]
journals.extend(
[d.get("reference_name") for d in payments if d.get("reference_type") == "Journal Entry"]
)
@@ -721,7 +716,7 @@ class PaymentReconciliation(Document):
def get_journal_filter_conditions(self):
conditions = []
je = qb.DocType("Journal Entry")
jea = qb.DocType("Journal Entry Account")
qb.DocType("Journal Entry Account")
conditions.append(je.company == self.company)
if self.from_payment_date:
@@ -841,7 +836,7 @@ def adjust_allocations_for_taxes(doc):
@frappe.whitelist()
def get_queries_for_dimension_filters(company: str = None):
def get_queries_for_dimension_filters(company: str | None = None):
dimensions_with_filters = []
for d in get_dimensions()[0]:
filters = {}

View File

@@ -1,7 +1,6 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe import qb
@@ -127,11 +126,14 @@ class TestPaymentReconciliation(FrappeTestCase):
setattr(self, x.attribute, acc.name)
def create_sales_invoice(
self, qty=1, rate=100, posting_date=nowdate(), do_not_save=False, do_not_submit=False
self, qty=1, rate=100, posting_date=None, do_not_save=False, do_not_submit=False
):
"""
Helper function to populate default values in sales invoice
"""
if posting_date is None:
posting_date = nowdate()
sinv = create_sales_invoice(
qty=qty,
rate=rate,
@@ -155,10 +157,13 @@ class TestPaymentReconciliation(FrappeTestCase):
)
return sinv
def create_payment_entry(self, amount=100, posting_date=nowdate(), customer=None):
def create_payment_entry(self, amount=100, posting_date=None, customer=None):
"""
Helper function to populate default values in payment entry
"""
if posting_date is None:
posting_date = nowdate()
payment = create_payment_entry(
company=self.company,
payment_type="Receive",
@@ -172,11 +177,14 @@ class TestPaymentReconciliation(FrappeTestCase):
return payment
def create_purchase_invoice(
self, qty=1, rate=100, posting_date=nowdate(), do_not_save=False, do_not_submit=False
self, qty=1, rate=100, posting_date=None, do_not_save=False, do_not_submit=False
):
"""
Helper function to populate default values in sales invoice
"""
if posting_date is None:
posting_date = nowdate()
pinv = make_purchase_invoice(
qty=qty,
rate=rate,
@@ -201,11 +209,14 @@ class TestPaymentReconciliation(FrappeTestCase):
return pinv
def create_purchase_order(
self, qty=1, rate=100, posting_date=nowdate(), do_not_save=False, do_not_submit=False
self, qty=1, rate=100, posting_date=None, do_not_save=False, do_not_submit=False
):
"""
Helper function to populate default values in sales invoice
"""
if posting_date is None:
posting_date = nowdate()
pord = create_purchase_order(
qty=qty,
rate=rate,
@@ -250,9 +261,7 @@ class TestPaymentReconciliation(FrappeTestCase):
pr.from_invoice_date = pr.to_invoice_date = pr.from_payment_date = pr.to_payment_date = nowdate()
return pr
def create_journal_entry(
self, acc1=None, acc2=None, amount=0, posting_date=None, cost_center=None
):
def create_journal_entry(self, acc1=None, acc2=None, amount=0, posting_date=None, cost_center=None):
je = frappe.new_doc("Journal Entry")
je.posting_date = posting_date or nowdate()
je.company = self.company
@@ -402,7 +411,7 @@ class TestPaymentReconciliation(FrappeTestCase):
rate = 100
invoices = []
payments = []
for i in range(5):
for _i in range(5):
invoices.append(self.create_sales_invoice(qty=1, rate=rate, posting_date=transaction_date))
pe = self.create_payment_entry(amount=rate, posting_date=transaction_date).save().submit()
payments.append(pe)
@@ -821,9 +830,7 @@ class TestPaymentReconciliation(FrappeTestCase):
cr_note.cancel()
pay = self.create_payment_entry(
amount=amount, posting_date=transaction_date, customer=self.customer3
)
pay = self.create_payment_entry(amount=amount, posting_date=transaction_date, customer=self.customer3)
pay.paid_from = self.debtors_eur
pay.paid_from_account_currency = "EUR"
pay.source_exchange_rate = exchange_rate
@@ -1025,9 +1032,7 @@ class TestPaymentReconciliation(FrappeTestCase):
rate = 100
# 'Main - PR' Cost Center
si1 = self.create_sales_invoice(
qty=1, rate=rate, posting_date=transaction_date, do_not_submit=True
)
si1 = self.create_sales_invoice(qty=1, rate=rate, posting_date=transaction_date, do_not_submit=True)
si1.cost_center = self.main_cc.name
si1.submit()
@@ -1043,9 +1048,7 @@ class TestPaymentReconciliation(FrappeTestCase):
je1 = je1.save().submit()
# 'Sub - PR' Cost Center
si2 = self.create_sales_invoice(
qty=1, rate=rate, posting_date=transaction_date, do_not_submit=True
)
si2 = self.create_sales_invoice(qty=1, rate=rate, posting_date=transaction_date, do_not_submit=True)
si2.cost_center = self.sub_cc.name
si2.submit()

View File

@@ -105,7 +105,7 @@ class PaymentRequest(Document):
)
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
if not hasattr(ref_doc, "order_type") or getattr(ref_doc, "order_type") != "Shopping Cart":
if not hasattr(ref_doc, "order_type") or ref_doc.order_type != "Shopping Cart":
ref_amount = get_amount(ref_doc, self.payment_account)
if not ref_amount:
frappe.throw(_("Payment Entry is already created"))
@@ -160,7 +160,7 @@ class PaymentRequest(Document):
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
if (
hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") == "Shopping Cart"
hasattr(ref_doc, "order_type") and ref_doc.order_type == "Shopping Cart"
) or self.flags.mute_email:
send_mail = False
@@ -172,9 +172,9 @@ class PaymentRequest(Document):
elif self.payment_channel == "Phone":
self.request_phone_payment()
advance_payment_doctypes = frappe.get_hooks(
"advance_payment_receivable_doctypes"
) + frappe.get_hooks("advance_payment_payable_doctypes")
advance_payment_doctypes = frappe.get_hooks("advance_payment_receivable_doctypes") + frappe.get_hooks(
"advance_payment_payable_doctypes"
)
if self.reference_doctype in advance_payment_doctypes:
# set advance payment status
ref_doc.set_total_advance_paid()
@@ -218,16 +218,16 @@ class PaymentRequest(Document):
self.set_as_cancelled()
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
advance_payment_doctypes = frappe.get_hooks(
"advance_payment_receivable_doctypes"
) + frappe.get_hooks("advance_payment_payable_doctypes")
advance_payment_doctypes = frappe.get_hooks("advance_payment_receivable_doctypes") + frappe.get_hooks(
"advance_payment_payable_doctypes"
)
if self.reference_doctype in advance_payment_doctypes:
# set advance payment status
ref_doc.set_total_advance_paid()
def make_invoice(self):
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
if hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") == "Shopping Cart":
if hasattr(ref_doc, "order_type") and ref_doc.order_type == "Shopping Cart":
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
si = make_sales_invoice(self.reference_name, ignore_permissions=True)
@@ -306,14 +306,10 @@ class PaymentRequest(Document):
else:
party_account = get_party_account("Customer", ref_doc.get("customer"), ref_doc.company)
party_account_currency = ref_doc.get("party_account_currency") or get_account_currency(
party_account
)
party_account_currency = ref_doc.get("party_account_currency") or get_account_currency(party_account)
bank_amount = self.grand_total
if (
party_account_currency == ref_doc.company_currency and party_account_currency != self.currency
):
if party_account_currency == ref_doc.company_currency and party_account_currency != self.currency:
party_amount = ref_doc.get("base_rounded_total") or ref_doc.get("base_grand_total")
else:
party_amount = self.grand_total
@@ -331,7 +327,7 @@ class PaymentRequest(Document):
"mode_of_payment": self.mode_of_payment,
"reference_no": self.name,
"reference_date": nowdate(),
"remarks": "Payment Entry against {0} {1} via Payment Request {2}".format(
"remarks": "Payment Entry against {} {} via Payment Request {}".format(
self.reference_doctype, self.reference_name, self.name
),
}
@@ -465,15 +461,11 @@ def make_payment_request(**args):
frappe.db.set_value(
"Sales Order", args.dn, "loyalty_points", int(args.loyalty_points), update_modified=False
)
frappe.db.set_value(
"Sales Order", args.dn, "loyalty_amount", loyalty_amount, update_modified=False
)
frappe.db.set_value("Sales Order", args.dn, "loyalty_amount", loyalty_amount, update_modified=False)
grand_total = grand_total - loyalty_amount
bank_account = (
get_party_bank_account(args.get("party_type"), args.get("party"))
if args.get("party_type")
else ""
get_party_bank_account(args.get("party_type"), args.get("party")) if args.get("party_type") else ""
)
draft_payment_request = frappe.db.get_value(
@@ -770,7 +762,10 @@ def get_paid_amount_against_order(dt, dn):
& (
(pe_ref.reference_name == dn)
| pe_ref.reference_name.isin(
frappe.qb.from_(inv_item).select(inv_item.parent).where(inv_item[inv_field] == dn).distinct()
frappe.qb.from_(inv_item)
.select(inv_item.parent)
.where(inv_item[inv_field] == dn)
.distinct()
)
)
)

View File

@@ -93,7 +93,7 @@ class TestPaymentRequest(unittest.TestCase):
return_doc=1,
)
pe = pr.create_payment_entry()
pr.create_payment_entry()
pr.load_from_db()
self.assertEqual(pr.status, "Paid")
@@ -158,7 +158,7 @@ class TestPaymentRequest(unittest.TestCase):
self.assertTrue(gl_entries)
for i, gle in enumerate(gl_entries):
for _i, gle in enumerate(gl_entries):
self.assertEqual(expected_gle[gle.account][0], gle.account)
self.assertEqual(expected_gle[gle.account][1], gle.debit)
self.assertEqual(expected_gle[gle.account][2], gle.credit)

View File

@@ -36,9 +36,7 @@ class PaymentTermsTemplate(Document):
total_portion += flt(term.get("invoice_portion", 0))
if flt(total_portion, 2) != 100.00:
frappe.msgprint(
_("Combined invoice portion must equal 100%"), raise_exception=1, indicator="red"
)
frappe.msgprint(_("Combined invoice portion must equal 100%"), raise_exception=1, indicator="red")
def validate_terms(self):
terms = []

View File

@@ -67,7 +67,8 @@ class PeriodClosingVoucher(AccountsController):
enqueue_after_commit=True,
)
frappe.msgprint(
_("The GL Entries will be cancelled in the background, it can take a few minutes."), alert=True
_("The GL Entries will be cancelled in the background, it can take a few minutes."),
alert=True,
)
else:
make_reverse_gl_entries(voucher_type="Period Closing Voucher", voucher_no=self.name)
@@ -109,9 +110,7 @@ class PeriodClosingVoucher(AccountsController):
self.posting_date, self.fiscal_year, self.company, label=_("Posting Date"), doc=self
)
self.year_start_date = get_fiscal_year(
self.posting_date, self.fiscal_year, company=self.company
)[1]
self.year_start_date = get_fiscal_year(self.posting_date, self.fiscal_year, company=self.company)[1]
self.check_if_previous_year_closed()
@@ -225,7 +224,9 @@ class PeriodClosingVoucher(AccountsController):
"credit_in_account_currency": abs(flt(acc.bal_in_account_currency))
if flt(acc.bal_in_account_currency) > 0
else 0,
"credit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) > 0 else 0,
"credit": abs(flt(acc.bal_in_company_currency))
if flt(acc.bal_in_company_currency) > 0
else 0,
"is_period_closing_voucher_entry": 1,
},
item=acc,
@@ -249,7 +250,9 @@ class PeriodClosingVoucher(AccountsController):
"credit_in_account_currency": abs(flt(acc.bal_in_account_currency))
if flt(acc.bal_in_account_currency) < 0
else 0,
"credit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) < 0 else 0,
"credit": abs(flt(acc.bal_in_company_currency))
if flt(acc.bal_in_company_currency) < 0
else 0,
"is_period_closing_voucher_entry": 1,
},
item=acc,

View File

@@ -70,7 +70,7 @@ class POSClosingEntry(StatusUpdater):
for key, value in pos_occurences.items():
if len(value) > 1:
error_list.append(
_("{} is added multiple times on rows: {}".format(frappe.bold(key), frappe.bold(value)))
_(f"{frappe.bold(key)} is added multiple times on rows: {frappe.bold(value)}")
)
if error_list:
@@ -165,9 +165,7 @@ def get_pos_invoices(start, end, pos_profile, user):
as_dict=1,
)
data = list(
filter(lambda d: get_datetime(start) <= get_datetime(d.timestamp) <= get_datetime(end), data)
)
data = list(filter(lambda d: get_datetime(start) <= get_datetime(d.timestamp) <= get_datetime(end), data))
# need to get taxes and payments so can't avoid get_doc
data = [frappe.get_doc("POS Invoice", d.name).as_dict() for d in data]
@@ -238,7 +236,11 @@ def make_closing_entry_from_opening(opening_entry):
else:
payments.append(
frappe._dict(
{"mode_of_payment": p.mode_of_payment, "opening_amount": 0, "expected_amount": p.amount}
{
"mode_of_payment": p.mode_of_payment,
"opening_amount": 0,
"expected_amount": p.amount,
}
)
)

View File

@@ -62,9 +62,7 @@ class TestPOSClosingEntry(unittest.TestCase):
test_user, pos_profile = init_user_and_profile()
opening_entry = create_opening_entry(pos_profile, test_user.name)
pos_inv = create_pos_invoice(
rate=3500, do_not_submit=1, item_name="Test Item", without_item_code=1
)
pos_inv = create_pos_invoice(rate=3500, do_not_submit=1, item_name="Test Item", without_item_code=1)
pos_inv.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3500})
pos_inv.submit()
@@ -211,7 +209,7 @@ def get_test_item_qty(pos_profile):
item_group="All Item Groups",
)
test_item_qty = [item for item in test_item_pos["items"] if item["item_code"] == "_Test Item"][
0
].get("actual_qty")
test_item_qty = next(item for item in test_item_pos["items"] if item["item_code"] == "_Test Item").get(
"actual_qty"
)
return test_item_qty

View File

@@ -183,7 +183,7 @@ class POSInvoice(SalesInvoice):
# end: auto-generated types
def __init__(self, *args, **kwargs):
super(POSInvoice, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
def validate(self):
if not cint(self.is_pos):
@@ -308,7 +308,9 @@ class POSInvoice(SalesInvoice):
)
if paid_amt and pay.amount != paid_amt:
return frappe.throw(_("Payment related to {0} is not completed").format(pay.mode_of_payment))
return frappe.throw(
_("Payment related to {0} is not completed").format(pay.mode_of_payment)
)
def validate_stock_availablility(self):
if self.is_return:
@@ -328,7 +330,7 @@ class POSInvoice(SalesInvoice):
available_stock, is_stock_item = get_stock_availability(d.item_code, d.warehouse)
item_code, warehouse, qty = (
item_code, warehouse, _qty = (
frappe.bold(d.item_code),
frappe.bold(d.warehouse),
frappe.bold(d.qty),
@@ -408,8 +410,7 @@ class POSInvoice(SalesInvoice):
if (
self.change_amount
and self.account_for_change_amount
and frappe.get_cached_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(

View File

@@ -245,7 +245,6 @@ class TestPOSInvoice(unittest.TestCase):
self.assertEqual(pos_return.get("payments")[1].amount, -500)
def test_pos_return_for_serialized_item(self):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
se = make_serialized_item(
@@ -287,7 +286,6 @@ class TestPOSInvoice(unittest.TestCase):
)
def test_partial_pos_returns(self):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
se = make_serialized_item(
@@ -359,9 +357,7 @@ class TestPOSInvoice(unittest.TestCase):
)
pos.set("payments", [])
pos.append(
"payments", {"mode_of_payment": "Bank Draft", "account": "_Test Bank - _TC", "amount": 50}
)
pos.append("payments", {"mode_of_payment": "Bank Draft", "account": "_Test Bank - _TC", "amount": 50})
pos.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 60, "default": 1}
)
@@ -379,7 +375,6 @@ class TestPOSInvoice(unittest.TestCase):
self.assertRaises(frappe.ValidationError, inv.insert)
def test_serialized_item_transaction(self):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
se = make_serialized_item(
@@ -434,7 +429,6 @@ class TestPOSInvoice(unittest.TestCase):
self.assertRaises(frappe.ValidationError, pos2.submit)
def test_delivered_serialized_item_transaction(self):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
se = make_serialized_item(
@@ -583,9 +577,7 @@ class TestPOSInvoice(unittest.TestCase):
from erpnext.accounts.doctype.loyalty_program.test_loyalty_program import create_records
create_records()
frappe.db.set_value(
"Customer", "Test Loyalty Customer", "loyalty_program", "Test Single Loyalty"
)
frappe.db.set_value("Customer", "Test Loyalty Customer", "loyalty_program", "Test Single Loyalty")
before_lp_details = get_loyalty_program_details_with_points(
"Test Loyalty Customer", company="_Test Company", loyalty_program="Test Single Loyalty"
)
@@ -659,9 +651,7 @@ class TestPOSInvoice(unittest.TestCase):
consolidate_pos_invoices()
pos_inv.load_from_db()
rounded_total = frappe.db.get_value(
"Sales Invoice", pos_inv.consolidated_invoice, "rounded_total"
)
rounded_total = frappe.db.get_value("Sales Invoice", pos_inv.consolidated_invoice, "rounded_total")
self.assertEqual(rounded_total, 3470)
def test_merging_into_sales_invoice_with_discount_and_inclusive_tax(self):
@@ -708,9 +698,7 @@ class TestPOSInvoice(unittest.TestCase):
consolidate_pos_invoices()
pos_inv.load_from_db()
rounded_total = frappe.db.get_value(
"Sales Invoice", pos_inv.consolidated_invoice, "rounded_total"
)
rounded_total = frappe.db.get_value("Sales Invoice", pos_inv.consolidated_invoice, "rounded_total")
self.assertEqual(rounded_total, 840)
def test_merging_with_validate_selling_price(self):
@@ -762,9 +750,7 @@ class TestPOSInvoice(unittest.TestCase):
consolidate_pos_invoices()
pos_inv2.load_from_db()
rounded_total = frappe.db.get_value(
"Sales Invoice", pos_inv2.consolidated_invoice, "rounded_total"
)
rounded_total = frappe.db.get_value("Sales Invoice", pos_inv2.consolidated_invoice, "rounded_total")
self.assertEqual(rounded_total, 400)
def test_pos_batch_reservation(self):
@@ -788,9 +774,7 @@ class TestPOSInvoice(unittest.TestCase):
batch_no = get_batch_from_bundle(se.items[0].serial_and_batch_bundle)
# POS Invoice 1, for the batch without bundle
pos_inv1 = create_pos_invoice(
item="_BATCH ITEM Test For Reserve", rate=300, qty=15, do_not_save=1
)
pos_inv1 = create_pos_invoice(item="_BATCH ITEM Test For Reserve", rate=300, qty=15, do_not_save=1)
pos_inv1.items[0].batch_no = batch_no
pos_inv1.save()
@@ -800,9 +784,7 @@ class TestPOSInvoice(unittest.TestCase):
self.assertFalse(pos_inv1.items[0].serial_and_batch_bundle)
batches = get_auto_batch_nos(
frappe._dict(
{"item_code": "_BATCH ITEM Test For Reserve", "warehouse": "_Test Warehouse - _TC"}
)
frappe._dict({"item_code": "_BATCH ITEM Test For Reserve", "warehouse": "_Test Warehouse - _TC"})
)
for batch in batches:
@@ -817,9 +799,7 @@ class TestPOSInvoice(unittest.TestCase):
self.assertTrue(pos_inv2.items[0].serial_and_batch_bundle)
batches = get_auto_batch_nos(
frappe._dict(
{"item_code": "_BATCH ITEM Test For Reserve", "warehouse": "_Test Warehouse - _TC"}
)
frappe._dict({"item_code": "_BATCH ITEM Test For Reserve", "warehouse": "_Test Warehouse - _TC"})
)
for batch in batches:
@@ -896,19 +876,19 @@ class TestPOSInvoice(unittest.TestCase):
pos_inv = create_pos_invoice(qty=1, do_not_submit=1)
pos_inv.items[0].rate = 300
pos_inv.save()
self.assertEquals(pos_inv.items[0].discount_percentage, 10)
self.assertEqual(pos_inv.items[0].discount_percentage, 10)
# rate shouldn't change
self.assertEquals(pos_inv.items[0].rate, 405)
self.assertEqual(pos_inv.items[0].rate, 405)
pos_inv.ignore_pricing_rule = 1
pos_inv.save()
self.assertEquals(pos_inv.ignore_pricing_rule, 1)
self.assertEqual(pos_inv.ignore_pricing_rule, 1)
# rate should reset since pricing rules are ignored
self.assertEquals(pos_inv.items[0].rate, 450)
self.assertEqual(pos_inv.items[0].rate, 450)
pos_inv.items[0].rate = 300
pos_inv.save()
self.assertEquals(pos_inv.items[0].rate, 300)
self.assertEqual(pos_inv.items[0].rate, 300)
finally:
item_price.delete()
@@ -920,7 +900,6 @@ class TestPOSInvoice(unittest.TestCase):
init_user_and_profile,
)
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
from erpnext.stock.doctype.serial_no.test_serial_no import get_serial_nos
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
frappe.db.savepoint("before_test_delivered_serial_no_case")

View File

@@ -54,7 +54,7 @@ class POSInvoiceMergeLog(Document):
for key, value in pos_occurences.items():
if len(value) > 1:
error_list.append(
_("{} is added multiple times on rows: {}".format(frappe.bold(key), frappe.bold(value)))
_(f"{frappe.bold(key)} is added multiple times on rows: {frappe.bold(value)}")
)
if error_list:
@@ -81,7 +81,9 @@ class POSInvoiceMergeLog(Document):
bold_pos_invoice = frappe.bold(d.pos_invoice)
bold_status = frappe.bold(status)
if docstatus != 1:
frappe.throw(_("Row #{}: POS Invoice {} is not submitted yet").format(d.idx, bold_pos_invoice))
frappe.throw(
_("Row #{}: POS Invoice {} is not submitted yet").format(d.idx, bold_pos_invoice)
)
if status == "Consolidated":
frappe.throw(
_("Row #{}: POS Invoice {} has been {}").format(d.idx, bold_pos_invoice, bold_status)
@@ -100,15 +102,17 @@ class POSInvoiceMergeLog(Document):
d.idx, bold_return_against, bold_pos_invoice, bold_unconsolidated
)
msg += " "
msg += _("Original invoice should be consolidated before or along with the return invoice.")
msg += _(
"Original invoice should be consolidated before or along with the return invoice."
)
msg += "<br><br>"
msg += _("You can add original invoice {} manually to proceed.").format(bold_return_against)
msg += _("You can add original invoice {} manually to proceed.").format(
bold_return_against
)
frappe.throw(msg)
def on_submit(self):
pos_invoice_docs = [
frappe.get_cached_doc("POS Invoice", d.pos_invoice) for d in self.pos_invoices
]
pos_invoice_docs = [frappe.get_cached_doc("POS Invoice", d.pos_invoice) for d in self.pos_invoices]
returns = [d for d in pos_invoice_docs if d.get("is_return") == 1]
sales = [d for d in pos_invoice_docs if d.get("is_return") == 0]
@@ -124,9 +128,7 @@ class POSInvoiceMergeLog(Document):
self.update_pos_invoices(pos_invoice_docs, sales_invoice, credit_note)
def on_cancel(self):
pos_invoice_docs = [
frappe.get_cached_doc("POS Invoice", d.pos_invoice) for d in self.pos_invoices
]
pos_invoice_docs = [frappe.get_cached_doc("POS Invoice", d.pos_invoice) for d in self.pos_invoices]
self.update_pos_invoices(pos_invoice_docs)
self.cancel_linked_invoices()
@@ -217,7 +219,9 @@ class POSInvoiceMergeLog(Document):
for t in taxes:
if t.account_head == tax.account_head and t.cost_center == tax.cost_center:
t.tax_amount = flt(t.tax_amount) + flt(tax.tax_amount_after_discount_amount)
t.base_tax_amount = flt(t.base_tax_amount) + flt(tax.base_tax_amount_after_discount_amount)
t.base_tax_amount = flt(t.base_tax_amount) + flt(
tax.base_tax_amount_after_discount_amount
)
update_item_wise_tax_detail(t, tax)
found = True
if not found:
@@ -333,9 +337,7 @@ def update_item_wise_tax_detail(consolidate_tax_row, tax_row):
else:
consolidated_tax_detail.update({item_code: [tax_data[0], tax_data[1]]})
consolidate_tax_row.item_wise_tax_detail = json.dumps(
consolidated_tax_detail, separators=(",", ":")
)
consolidate_tax_row.item_wise_tax_detail = json.dumps(consolidated_tax_detail, separators=(",", ":"))
def get_all_unconsolidated_invoices():
@@ -380,9 +382,7 @@ def consolidate_pos_invoices(pos_invoices=None, closing_entry=None):
if len(invoices) >= 10 and closing_entry:
closing_entry.set_status(update=True, status="Queued")
enqueue_job(
create_merge_logs, invoice_by_customer=invoice_by_customer, closing_entry=closing_entry
)
enqueue_job(create_merge_logs, invoice_by_customer=invoice_by_customer, closing_entry=closing_entry)
else:
create_merge_logs(invoice_by_customer, closing_entry)
@@ -431,9 +431,7 @@ def split_invoices(invoices):
if not item.serial_no and not item.serial_and_batch_bundle:
continue
return_against_is_added = any(
d for d in _invoices if d.pos_invoice == pos_invoice.return_against
)
return_against_is_added = any(d for d in _invoices if d.pos_invoice == pos_invoice.return_against)
if return_against_is_added:
break
@@ -482,7 +480,7 @@ def create_merge_logs(invoice_by_customer, closing_entry=None):
if closing_entry:
closing_entry.set_status(update=True, status="Failed")
if type(error_message) == list:
if isinstance(error_message, list):
error_message = frappe.json.dumps(error_message)
closing_entry.db_set("error_message", error_message)
raise
@@ -533,7 +531,7 @@ def enqueue_job(job, **kwargs):
timeout=10000,
event="processing_merge_logs",
job_id=job_id,
now=frappe.conf.developer_mode or frappe.flags.in_test
now=frappe.conf.developer_mode or frappe.flags.in_test,
)
if job == create_merge_logs:

View File

@@ -31,15 +31,11 @@ class TestPOSInvoiceMergeLog(unittest.TestCase):
pos_inv.submit()
pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
pos_inv2.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3200}
)
pos_inv2.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3200})
pos_inv2.submit()
pos_inv3 = create_pos_invoice(customer="_Test Customer 2", rate=2300, do_not_submit=1)
pos_inv3.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 2300}
)
pos_inv3.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 2300})
pos_inv3.submit()
consolidate_pos_invoices()
@@ -68,15 +64,11 @@ class TestPOSInvoiceMergeLog(unittest.TestCase):
pos_inv.submit()
pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
pos_inv2.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3200}
)
pos_inv2.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3200})
pos_inv2.submit()
pos_inv3 = create_pos_invoice(customer="_Test Customer 2", rate=2300, do_not_submit=1)
pos_inv3.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 2300}
)
pos_inv3.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 2300})
pos_inv3.submit()
pos_inv_cn = make_sales_return(pos_inv.name)
@@ -312,7 +304,7 @@ class TestPOSInvoiceMergeLog(unittest.TestCase):
init_user_and_profile()
item_rates = [69, 59, 29]
for i in [1, 2]:
for _i in [1, 2]:
inv = create_pos_invoice(is_return=1, do_not_save=1)
inv.items = []
for rate in item_rates:
@@ -406,7 +398,6 @@ class TestPOSInvoiceMergeLog(unittest.TestCase):
The second and third POS Invoice should be consolidated with a single Merge Log
"""
from erpnext.stock.doctype.serial_no.test_serial_no import get_serial_nos
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
frappe.db.sql("delete from `tabPOS Invoice`")

View File

@@ -180,10 +180,8 @@ class POSProfile(Document):
condition = " where pfu.default = 1 "
pos_view_users = frappe.db.sql_list(
"""select pfu.user
from `tabPOS Profile User` as pfu {0}""".format(
condition
)
f"""select pfu.user
from `tabPOS Profile User` as pfu {condition}"""
)
for user in pos_view_users:
@@ -210,16 +208,13 @@ def get_item_groups(pos_profile):
def get_child_nodes(group_type, root):
lft, rgt = frappe.db.get_value(group_type, root, ["lft", "rgt"])
return frappe.db.sql(
""" Select name, lft, rgt from `tab{tab}` where
lft >= {lft} and rgt <= {rgt} order by lft""".format(
tab=group_type, lft=lft, rgt=rgt
),
f""" Select name, lft, rgt from `tab{group_type}` where
lft >= {lft} and rgt <= {rgt} order by lft""",
as_dict=1,
)
def required_accounting_dimensions():
p = frappe.qb.DocType("Accounting Dimension")
c = frappe.qb.DocType("Accounting Dimension Detail")

View File

@@ -7,7 +7,6 @@ import frappe
from erpnext.accounts.doctype.pos_profile.pos_profile import (
get_child_nodes,
required_accounting_dimensions,
)
from erpnext.stock.get_item_details import get_pos_profile
@@ -55,11 +54,9 @@ def get_customers_list(pos_profile=None):
return (
frappe.db.sql(
""" select name, customer_name, customer_group,
f""" select name, customer_name, customer_group,
territory, customer_pos_id from tabCustomer where disabled = 0
and {cond}""".format(
cond=cond
),
and {cond}""",
tuple(customer_groups),
as_dict=1,
)
@@ -78,7 +75,7 @@ def get_items_list(pos_profile, company):
cond = "and i.item_group in (%s)" % (", ".join(["%s"] * len(args_list)))
return frappe.db.sql(
"""
f"""
select
i.name, i.item_code, i.item_name, i.description, i.item_group, i.has_batch_no,
i.has_serial_no, i.is_stock_item, i.brand, i.stock_uom, i.image,
@@ -91,10 +88,8 @@ def get_items_list(pos_profile, company):
where
i.disabled = 0 and i.has_variants = 0 and i.is_sales_item = 1 and i.is_fixed_asset = 0
{cond}
""".format(
cond=cond
),
tuple([company] + args_list),
""",
tuple([company, *args_list]),
as_dict=1,
)

View File

@@ -186,9 +186,9 @@ class PricingRule(Document):
if self.priority and cint(self.priority) == 1:
throw(
_("As the field {0} is enabled, the value of the field {1} should be more than 1.").format(
frappe.bold("Apply Discount on Discounted Rate"), frappe.bold("Priority")
)
_(
"As the field {0} is enabled, the value of the field {1} should be more than 1."
).format(frappe.bold("Apply Discount on Discounted Rate"), frappe.bold("Priority"))
)
def validate_applicable_for_selling_or_buying(self):
@@ -458,9 +458,11 @@ def get_pricing_rule_for_item(args, doc=None, for_validate=False):
)
if pricing_rule.apply_rule_on_other_items:
item_details["apply_rule_on_other_items"] = json.dumps(pricing_rule.apply_rule_on_other_items)
item_details["apply_rule_on_other_items"] = json.dumps(
pricing_rule.apply_rule_on_other_items
)
if pricing_rule.coupon_code_based == 1 and args.coupon_code == None:
if pricing_rule.coupon_code_based == 1 and args.coupon_code is None:
return item_details
if not pricing_rule.validate_applied_rule:
@@ -504,7 +506,6 @@ def update_args_for_pricing_rule(args):
if args.transaction_type == "selling":
if args.customer and not (args.customer_group and args.territory):
if args.quotation_to and args.quotation_to != "Customer":
customer = frappe._dict()
else:
@@ -535,9 +536,9 @@ def get_pricing_rule_details(args, pricing_rule):
def apply_price_discount_rule(pricing_rule, item_details, args):
item_details.pricing_rule_for = pricing_rule.rate_or_discount
if (
pricing_rule.margin_type in ["Amount", "Percentage"] and pricing_rule.currency == args.currency
) or (pricing_rule.margin_type == "Percentage"):
if (pricing_rule.margin_type in ["Amount", "Percentage"] and pricing_rule.currency == args.currency) or (
pricing_rule.margin_type == "Percentage"
):
item_details.margin_type = pricing_rule.margin_type
item_details.has_margin = True
@@ -685,7 +686,7 @@ def get_item_uoms(doctype, txt, searchfield, start, page_len, filters):
return frappe.get_all(
"UOM Conversion Detail",
filters={"parent": ("in", items), "uom": ("like", "{0}%".format(txt))},
filters={"parent": ("in", items), "uom": ("like", f"{txt}%")},
fields=["distinct uom"],
as_list=1,
)

View File

@@ -103,8 +103,6 @@ class TestPricingRule(unittest.TestCase):
self.assertEqual(details.get("discount_percentage"), 15)
def test_pricing_rule_for_margin(self):
from frappe import MandatoryError
from erpnext.stock.get_item_details import get_item_details
test_record = {
@@ -205,8 +203,6 @@ class TestPricingRule(unittest.TestCase):
self.assertEqual(details.get("discount_percentage"), 10)
def test_pricing_rule_for_variants(self):
from frappe import MandatoryError
from erpnext.stock.get_item_details import get_item_details
if not frappe.db.exists("Item", "Test Variant PRT"):
@@ -1181,8 +1177,7 @@ def delete_existing_pricing_rules():
"Pricing Rule Item Group",
"Pricing Rule Brand",
]:
frappe.db.sql("delete from `tab{0}`".format(doctype))
frappe.db.sql(f"delete from `tab{doctype}`")
def make_item_price(item, price_list_name, item_price):

View File

@@ -101,14 +101,12 @@ def _get_pricing_rules(apply_on, args, values):
if not args.get(apply_on_field):
return []
child_doc = "`tabPricing Rule {0}`".format(apply_on)
child_doc = f"`tabPricing Rule {apply_on}`"
conditions = item_variant_condition = item_conditions = ""
values[apply_on_field] = args.get(apply_on_field)
if apply_on_field in ["item_code", "brand"]:
item_conditions = "{child_doc}.{apply_on_field}= %({apply_on_field})s".format(
child_doc=child_doc, apply_on_field=apply_on_field
)
item_conditions = f"{child_doc}.{apply_on_field}= %({apply_on_field})s"
if apply_on_field == "item_code":
if args.get("uom", None):
@@ -121,23 +119,19 @@ def _get_pricing_rules(apply_on, args, values):
args.variant_of = frappe.get_cached_value("Item", args.item_code, "variant_of")
if args.variant_of:
item_variant_condition = " or {child_doc}.item_code=%(variant_of)s ".format(
child_doc=child_doc
)
item_variant_condition = f" or {child_doc}.item_code=%(variant_of)s "
values["variant_of"] = args.variant_of
elif apply_on_field == "item_group":
item_conditions = _get_tree_conditions(args, "Item Group", child_doc, False)
if args.get("uom", None):
item_conditions += (
" and ({child_doc}.uom='{item_uom}' or IFNULL({child_doc}.uom, '')='')".format(
child_doc=child_doc, item_uom=args.get("uom")
)
item_conditions += " and ({child_doc}.uom='{item_uom}' or IFNULL({child_doc}.uom, '')='')".format(
child_doc=child_doc, item_uom=args.get("uom")
)
conditions += get_other_conditions(conditions, values, args)
warehouse_conditions = _get_tree_conditions(args, "Warehouse", "`tabPricing Rule`")
if warehouse_conditions:
warehouse_conditions = " and {0}".format(warehouse_conditions)
warehouse_conditions = f" and {warehouse_conditions}"
if not args.price_list:
args.price_list = None
@@ -163,7 +157,7 @@ def _get_pricing_rules(apply_on, args, values):
item_variant_condition=item_variant_condition,
transaction_type=args.transaction_type,
warehouse_cond=warehouse_conditions,
apply_on_other_field="other_{0}".format(apply_on_field),
apply_on_other_field=f"other_{apply_on_field}",
conditions=conditions,
),
values,
@@ -202,14 +196,13 @@ def _get_tree_conditions(args, parenttype, table, allow_blank=True):
frappe.throw(_("Invalid {0}").format(args.get(field)))
parent_groups = frappe.db.sql_list(
"""select name from `tab%s`
where lft<=%s and rgt>=%s"""
% (parenttype, "%s", "%s"),
"""select name from `tab{}`
where lft<={} and rgt>={}""".format(parenttype, "%s", "%s"),
(lft, rgt),
)
if parenttype in ["Customer Group", "Item Group", "Territory"]:
parent_field = "parent_{0}".format(frappe.scrub(parenttype))
parent_field = f"parent_{frappe.scrub(parenttype)}"
root_name = frappe.db.get_list(
parenttype,
{"is_group": 1, parent_field: ("is", "not set")},
@@ -235,10 +228,10 @@ def _get_tree_conditions(args, parenttype, table, allow_blank=True):
def get_other_conditions(conditions, values, args):
for field in ["company", "customer", "supplier", "campaign", "sales_partner"]:
if args.get(field):
conditions += " and ifnull(`tabPricing Rule`.{0}, '') in (%({1})s, '')".format(field, field)
conditions += f" and ifnull(`tabPricing Rule`.{field}, '') in (%({field})s, '')"
values[field] = args.get(field)
else:
conditions += " and ifnull(`tabPricing Rule`.{0}, '') = ''".format(field)
conditions += f" and ifnull(`tabPricing Rule`.{field}, '') = ''"
for parenttype in ["Customer Group", "Territory", "Supplier Group"]:
group_condition = _get_tree_conditions(args, parenttype, "`tabPricing Rule`")
@@ -510,7 +503,7 @@ def get_qty_amount_data_for_cumulative(pr_doc, doc, items=None):
"transaction_date" if frappe.get_meta(doctype).has_field("transaction_date") else "posting_date"
)
child_doctype = "{0} Item".format(doctype)
child_doctype = f"{doctype} Item"
apply_on = frappe.scrub(pr_doc.get("apply_on"))
values = [pr_doc.valid_from, pr_doc.valid_upto]
@@ -520,9 +513,7 @@ def get_qty_amount_data_for_cumulative(pr_doc, doc, items=None):
warehouses = get_child_warehouses(pr_doc.warehouse)
condition += """ and `tab{child_doc}`.warehouse in ({warehouses})
""".format(
child_doc=child_doctype, warehouses=",".join(["%s"] * len(warehouses))
)
""".format(child_doc=child_doctype, warehouses=",".join(["%s"] * len(warehouses)))
values.extend(warehouses)
@@ -534,16 +525,14 @@ def get_qty_amount_data_for_cumulative(pr_doc, doc, items=None):
values.extend(items)
data_set = frappe.db.sql(
""" SELECT `tab{child_doc}`.stock_qty,
`tab{child_doc}`.amount
FROM `tab{child_doc}`, `tab{parent_doc}`
f""" SELECT `tab{child_doctype}`.stock_qty,
`tab{child_doctype}`.amount
FROM `tab{child_doctype}`, `tab{doctype}`
WHERE
`tab{child_doc}`.parent = `tab{parent_doc}`.name and `tab{parent_doc}`.{date_field}
between %s and %s and `tab{parent_doc}`.docstatus = 1
{condition} group by `tab{child_doc}`.name
""".format(
parent_doc=doctype, child_doc=child_doctype, condition=condition, date_field=date_field
),
`tab{child_doctype}`.parent = `tab{doctype}`.name and `tab{doctype}`.{date_field}
between %s and %s and `tab{doctype}`.docstatus = 1
{condition} group by `tab{child_doctype}`.name
""",
tuple(values),
as_dict=1,
)
@@ -562,11 +551,9 @@ def apply_pricing_rule_on_transaction(doc):
conditions = get_other_conditions(conditions, values, doc)
pricing_rules = frappe.db.sql(
""" Select `tabPricing Rule`.* from `tabPricing Rule`
f""" Select `tabPricing Rule`.* from `tabPricing Rule`
where {conditions} and `tabPricing Rule`.disable = 0
""".format(
conditions=conditions
),
""",
values,
as_dict=1,
)
@@ -591,7 +578,9 @@ def apply_pricing_rule_on_transaction(doc):
continue
if (
d.validate_applied_rule and doc.get(field) is not None and doc.get(field) < d.get(pr_field)
d.validate_applied_rule
and doc.get(field) is not None
and doc.get(field) < d.get(pr_field)
):
frappe.msgprint(_("User has not applied rule on the invoice {0}").format(doc.name))
else:
@@ -660,9 +649,7 @@ def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None):
qty = pricing_rule.free_qty or 1
if pricing_rule.is_recursive:
transaction_qty = (
args.get("qty") if args else doc.total_qty
) - pricing_rule.apply_recursion_over
transaction_qty = (args.get("qty") if args else doc.total_qty) - pricing_rule.apply_recursion_over
if transaction_qty:
qty = flt(transaction_qty) * qty / pricing_rule.recurse_for
if pricing_rule.round_free_qty:

View File

@@ -40,7 +40,7 @@ class TestProcessDeferredAccounting(unittest.TestCase):
si.save()
si.submit()
process_deferred_accounting = doc = frappe.get_doc(
process_deferred_accounting = frappe.get_doc(
dict(
doctype="Process Deferred Accounting",
posting_date="2023-07-01",

View File

@@ -66,9 +66,7 @@ class ProcessPaymentReconciliation(Document):
def on_cancel(self):
self.db_set("status", "Cancelled")
log = frappe.db.get_value(
"Process Payment Reconciliation Log", filters={"process_pr": self.name}
)
log = frappe.db.get_value("Process Payment Reconciliation Log", filters={"process_pr": self.name})
if log:
frappe.db.set_value("Process Payment Reconciliation Log", log, "status", "Cancelled")
@@ -416,7 +414,6 @@ def reconcile(doc: None | str = None) -> None:
# If Payment Entry, update details only for newly linked references
# This is for performance
if allocations[0].reference_type == "Payment Entry":
references = [(x.invoice_type, x.invoice_number) for x in allocations]
pe = frappe.get_doc(allocations[0].reference_type, allocations[0].reference_name)
pe.flags.ignore_validate_update_after_submit = True
@@ -430,13 +427,14 @@ def reconcile(doc: None | str = None) -> None:
# Update reconciled count
reconciled_count = frappe.db.count(
"Process Payment Reconciliation Log Allocations", filters={"parent": log, "reconciled": True}
"Process Payment Reconciliation Log Allocations",
filters={"parent": log, "reconciled": True},
)
frappe.db.set_value(
"Process Payment Reconciliation Log", log, "reconciled_entries", reconciled_count
)
except Exception as err:
except Exception:
# Update the parent doc about the exception
frappe.db.rollback()
@@ -474,15 +472,12 @@ def reconcile(doc: None | str = None) -> None:
frappe.db.set_value("Process Payment Reconciliation Log", log, "reconciled", True)
frappe.db.set_value("Process Payment Reconciliation", doc, "status", "Completed")
else:
if frappe.db.get_value("Process Payment Reconciliation", doc, "status") != "Paused":
# trigger next batch in job
# generate reconcile job name
allocation = get_next_allocation(log)
if allocation:
reconcile_job_name = (
f"process_{doc}_reconcile_allocation_{allocation[0].idx}_{allocation[-1].idx}"
)
reconcile_job_name = f"process_{doc}_reconcile_allocation_{allocation[0].idx}_{allocation[-1].idx}"
else:
reconcile_job_name = f"process_{doc}_reconcile"
@@ -506,7 +501,7 @@ def reconcile(doc: None | str = None) -> None:
def is_any_doc_running(for_filter: str | dict | None = None) -> str | None:
running_doc = None
if for_filter:
if type(for_filter) == str:
if isinstance(for_filter, str):
for_filter = frappe.json.loads(for_filter)
running_doc = frappe.db.get_value(

View File

@@ -24,9 +24,7 @@ class ProcessPaymentReconciliationLog(Document):
process_pr: DF.Link
reconciled: DF.Check
reconciled_entries: DF.Int
status: DF.Literal[
"Running", "Paused", "Reconciled", "Partially Reconciled", "Failed", "Cancelled"
]
status: DF.Literal["Running", "Paused", "Reconciled", "Partially Reconciled", "Failed", "Cancelled"]
total_allocations: DF.Int
# end: auto-generated types

View File

@@ -46,9 +46,7 @@ class ProcessStatementOfAccounts(Document):
company: DF.Link
cost_center: DF.TableMultiSelect[PSOACostCenter]
currency: DF.Link | None
customer_collection: DF.Literal[
"", "Customer Group", "Territory", "Sales Partner", "Sales Person"
]
customer_collection: DF.Literal["", "Customer Group", "Territory", "Sales Partner", "Sales Person"]
customers: DF.Table[ProcessStatementOfAccountsCustomer]
enable_auto_email: DF.Check
filter_duration: DF.Int
@@ -406,9 +404,7 @@ def get_customer_emails(customer_name, primary_mandatory, billing_and_primary=Tr
{mcond}
ORDER BY
contact.creation desc
""".format(
mcond=get_match_cond("Contact")
),
""".format(mcond=get_match_cond("Contact")),
customer_name,
)
@@ -481,9 +477,7 @@ def send_emails(document_name, from_scheduler=False, posting_date=None):
else:
new_to_date = add_months(new_to_date, 1 if doc.frequency == "Monthly" else 3)
new_from_date = add_months(new_to_date, -1 * doc.filter_duration)
doc.add_comment(
"Comment", "Emails sent on: " + frappe.utils.format_datetime(frappe.utils.now())
)
doc.add_comment("Comment", "Emails sent on: " + frappe.utils.format_datetime(frappe.utils.now()))
if doc.report == "General Ledger":
doc.db_set("to_date", new_to_date, commit=True)
doc.db_set("from_date", new_from_date, commit=True)

View File

@@ -1,7 +1,6 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase

View File

@@ -1,14 +1,11 @@
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from datetime import datetime
from typing import Union
import frappe
from frappe.model.document import Document
from frappe.utils import getdate
from erpnext.accounts.doctype.subscription.subscription import process_all
from erpnext.accounts.doctype.subscription.subscription import DateTimeLikeObject, process_all
class ProcessSubscription(Document):
@@ -30,7 +27,7 @@ class ProcessSubscription(Document):
def create_subscription_process(
subscription: str | None = None, posting_date: Union[str, datetime.date] | None = None
subscription: str | None = None, posting_date: DateTimeLikeObject | None = None
):
"""Create a new Process Subscription document"""
doc = frappe.new_doc("Process Subscription")

View File

@@ -169,9 +169,7 @@ class PromotionalScheme(Document):
docnames = frappe.get_all("Pricing Rule", filters={"promotional_scheme": self.name})
for docname in docnames:
if frappe.db.exists(
"Pricing Rule Detail", {"pricing_rule": docname.name, "docstatus": ("<", 2)}
):
if frappe.db.exists("Pricing Rule Detail", {"pricing_rule": docname.name, "docstatus": ("<", 2)}):
raise_for_transaction_exists(self.name)
if docnames and not transaction_exists:
@@ -246,7 +244,7 @@ def _get_pricing_rules(doc, child_doc, discount_fields, rules=None):
args = get_args_for_pricing_rule(doc)
applicable_for = frappe.scrub(doc.get("applicable_for"))
for idx, d in enumerate(doc.get(child_doc)):
for _idx, d in enumerate(doc.get(child_doc)):
if d.name in rules:
if not args.get(applicable_for):
docname = get_pricing_rule_docname(d)
@@ -256,7 +254,14 @@ def _get_pricing_rules(doc, child_doc, discount_fields, rules=None):
for applicable_for_value in args.get(applicable_for):
docname = get_pricing_rule_docname(d, applicable_for, applicable_for_value)
pr = prepare_pricing_rule(
args, doc, child_doc, discount_fields, d, docname, applicable_for, applicable_for_value
args,
doc,
child_doc,
discount_fields,
d,
docname,
applicable_for,
applicable_for_value,
)
new_doc.append(pr)
@@ -282,7 +287,7 @@ def _get_pricing_rules(doc, child_doc, discount_fields, rules=None):
def get_pricing_rule_docname(
row: dict, applicable_for: str = None, applicable_for_value: str = None
row: dict, applicable_for: str | None = None, applicable_for_value: str | None = None
) -> str:
fields = ["promotional_scheme_id", "name"]
filters = {"promotional_scheme_id": row.name}

View File

@@ -227,7 +227,7 @@ class PurchaseInvoice(BuyingController):
# end: auto-generated types
def __init__(self, *args, **kwargs):
super(PurchaseInvoice, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.status_updater = [
{
"source_dt": "Purchase Invoice Item",
@@ -244,7 +244,7 @@ class PurchaseInvoice(BuyingController):
]
def onload(self):
super(PurchaseInvoice, self).onload()
super().onload()
supplier_tds = frappe.db.get_value("Supplier", self.supplier, "tax_withholding_category")
self.set_onload("supplier_tds", supplier_tds)
@@ -264,7 +264,7 @@ class PurchaseInvoice(BuyingController):
self.validate_posting_time()
super(PurchaseInvoice, self).validate()
super().validate()
if not self.is_return:
self.po_required()
@@ -324,7 +324,6 @@ class PurchaseInvoice(BuyingController):
if flt(self.paid_amount) + flt(self.write_off_amount) - flt(
self.get("rounded_total") or self.grand_total
) > 1 / (10 ** (self.precision("base_grand_total") + 1)):
frappe.throw(_("""Paid amount + Write Off Amount can not be greater than Grand Total"""))
def create_remarks(self):
@@ -353,7 +352,7 @@ class PurchaseInvoice(BuyingController):
self.tax_withholding_category = tds_category
self.set_onload("supplier_tds", tds_category)
super(PurchaseInvoice, self).set_missing_values(for_validate)
super().set_missing_values(for_validate)
def validate_credit_to_acc(self):
if not self.credit_to:
@@ -392,7 +391,7 @@ class PurchaseInvoice(BuyingController):
check_on_hold_or_closed_status("Purchase Order", d.purchase_order)
def validate_with_previous_doc(self):
super(PurchaseInvoice, self).validate_with_previous_doc(
super().validate_with_previous_doc(
{
"Purchase Order": {
"ref_dn_field": "purchase_order",
@@ -440,7 +439,7 @@ class PurchaseInvoice(BuyingController):
exc=WarehouseMissingError,
)
super(PurchaseInvoice, self).validate_warehouse()
super().validate_warehouse()
def validate_item_code(self):
for d in self.get("items"):
@@ -476,7 +475,6 @@ class PurchaseInvoice(BuyingController):
or not frappe.db.get_value("Purchase Order Item", item.po_detail, "delivered_by_supplier")
)
):
if self.update_stock and item.warehouse and (not item.from_warehouse):
if (
for_validate
@@ -504,12 +502,16 @@ class PurchaseInvoice(BuyingController):
if negative_expense_booked_in_pr:
if (
for_validate and item.expense_account and item.expense_account != stock_not_billed_account
for_validate
and item.expense_account
and item.expense_account != stock_not_billed_account
):
msg = _(
"Row {0}: Expense Head changed to {1} because expense is booked against this account in Purchase Receipt {2}"
).format(
item.idx, frappe.bold(stock_not_billed_account), frappe.bold(item.purchase_receipt)
item.idx,
frappe.bold(stock_not_billed_account),
frappe.bold(item.purchase_receipt),
)
frappe.msgprint(msg, title=_("Expense Head Changed"))
@@ -518,7 +520,9 @@ class PurchaseInvoice(BuyingController):
# If no purchase receipt present then book expense in 'Stock Received But Not Billed'
# This is done in cases when Purchase Invoice is created before Purchase Receipt
if (
for_validate and item.expense_account and item.expense_account != stock_not_billed_account
for_validate
and item.expense_account
and item.expense_account != stock_not_billed_account
):
msg = _(
"Row {0}: Expense Head changed to {1} as no Purchase Receipt is created against Item {2}."
@@ -569,7 +573,6 @@ class PurchaseInvoice(BuyingController):
def po_required(self):
if frappe.db.get_single_value("Buying Settings", "po_required") == "Yes":
if frappe.get_value(
"Supplier", self.supplier, "allow_purchase_invoice_creation_without_purchase_order"
):
@@ -579,7 +582,9 @@ class PurchaseInvoice(BuyingController):
if not d.purchase_order:
msg = _("Purchase Order Required for item {}").format(frappe.bold(d.item_code))
msg += "<br><br>"
msg += _("To submit the invoice without purchase order please set {0} as {1} in {2}").format(
msg += _(
"To submit the invoice without purchase order please set {0} as {1} in {2}"
).format(
frappe.bold(_("Purchase Order Required")),
frappe.bold("No"),
get_link_to_form("Buying Settings", "Buying Settings", "Buying Settings"),
@@ -589,7 +594,6 @@ class PurchaseInvoice(BuyingController):
def pr_required(self):
stock_items = self.get_stock_items()
if frappe.db.get_single_value("Buying Settings", "pr_required") == "Yes":
if frappe.get_value(
"Supplier", self.supplier, "allow_purchase_invoice_creation_without_purchase_receipt"
):
@@ -622,7 +626,8 @@ class PurchaseInvoice(BuyingController):
frappe.throw(_("Purchase Order {0} is not submitted").format(d.purchase_order))
if d.purchase_receipt:
submitted = frappe.db.sql(
"select name from `tabPurchase Receipt` where docstatus = 1 and name = %s", d.purchase_receipt
"select name from `tabPurchase Receipt` where docstatus = 1 and name = %s",
d.purchase_receipt,
)
if not submitted:
frappe.throw(_("Purchase Receipt {0} is not submitted").format(d.purchase_receipt))
@@ -670,7 +675,9 @@ class PurchaseInvoice(BuyingController):
for item in self.get("items"):
if item.purchase_receipt:
frappe.throw(
_("Stock cannot be updated against Purchase Receipt {0}").format(item.purchase_receipt)
_("Stock cannot be updated against Purchase Receipt {0}").format(
item.purchase_receipt
)
)
def validate_for_repost(self):
@@ -680,7 +687,7 @@ class PurchaseInvoice(BuyingController):
validate_docs_for_deferred_accounting([], [self.name])
def on_submit(self):
super(PurchaseInvoice, self).on_submit()
super().on_submit()
self.check_prev_docstatus()
@@ -717,9 +724,7 @@ class PurchaseInvoice(BuyingController):
if self.update_stock == 1:
self.repost_future_sle_and_gle()
if (
frappe.db.get_single_value("Buying Settings", "project_update_frequency") == "Each Transaction"
):
if frappe.db.get_single_value("Buying Settings", "project_update_frequency") == "Each Transaction":
self.update_project()
update_linked_doc(self.doctype, self.name, self.inter_company_invoice_reference)
@@ -911,7 +916,7 @@ class PurchaseInvoice(BuyingController):
if flt(item.base_net_amount):
account_currency = get_account_currency(item.expense_account)
if item.item_code:
asset_category = frappe.get_cached_value("Item", item.item_code, "asset_category")
frappe.get_cached_value("Item", item.item_code, "asset_category")
if (
self.update_stock
@@ -1016,7 +1021,9 @@ class PurchaseInvoice(BuyingController):
if flt(item.rm_supp_cost):
supplier_warehouse_account = warehouse_account[self.supplier_warehouse]["account"]
if not supplier_warehouse_account:
frappe.throw(_("Please set account in Warehouse {0}").format(self.supplier_warehouse))
frappe.throw(
_("Please set account in Warehouse {0}").format(self.supplier_warehouse)
)
gl_entries.append(
self.get_gl_dict(
{
@@ -1066,10 +1073,9 @@ class PurchaseInvoice(BuyingController):
and self.conversion_rate != exchange_rate_map[item.purchase_receipt]
and item.net_rate == net_rate_map[item.pr_detail]
):
discrepancy_caused_by_exchange_rate_difference = (item.qty * item.net_rate) * (
exchange_rate_map[item.purchase_receipt] - self.conversion_rate
)
discrepancy_caused_by_exchange_rate_difference = (
item.qty * item.net_rate
) * (exchange_rate_map[item.purchase_receipt] - self.conversion_rate)
gl_entries.append(
self.get_gl_dict(
@@ -1111,7 +1117,7 @@ class PurchaseInvoice(BuyingController):
(item.purchase_receipt, valuation_tax_accounts),
)
stock_rbnb = (
(
self.get_company_default("asset_received_but_not_billed")
if item.is_fixed_asset
else self.stock_received_but_not_billed
@@ -1150,7 +1156,9 @@ class PurchaseInvoice(BuyingController):
default_provisional_account = self.get_company_default("default_provisional_account")
provisional_accounts = set(
[
d.provisional_expense_account if d.provisional_expense_account else default_provisional_account
d.provisional_expense_account
if d.provisional_expense_account
else default_provisional_account
for d in pr_items
]
)
@@ -1207,9 +1215,7 @@ class PurchaseInvoice(BuyingController):
},
)
def make_stock_adjustment_entry(
self, gl_entries, item, voucher_wise_stock_value, account_currency
):
def make_stock_adjustment_entry(self, gl_entries, item, voucher_wise_stock_value, account_currency):
net_amt_precision = item.precision("base_net_amount")
val_rate_db_precision = 6 if cint(item.precision("valuation_rate")) <= 6 else 9
@@ -1225,7 +1231,6 @@ class PurchaseInvoice(BuyingController):
and warehouse_debit_amount
!= flt(voucher_wise_stock_value.get((item.name, item.warehouse)), net_amt_precision)
):
cost_of_goods_sold_account = self.get_company_default("default_expense_account")
stock_amount = flt(voucher_wise_stock_value.get((item.name, item.warehouse)), net_amt_precision)
stock_adjustment_amt = warehouse_debit_amount - stock_amount
@@ -1448,9 +1453,7 @@ class PurchaseInvoice(BuyingController):
# base_rounding_adjustment may become zero due to small precision
# eg: rounding_adjustment = 0.01 and exchange rate = 0.05 and precision of base_rounding_adjustment is 2
# then base_rounding_adjustment becomes zero and error is thrown in GL Entry
if (
not self.is_internal_transfer() and self.rounding_adjustment and self.base_rounding_adjustment
):
if not self.is_internal_transfer() and self.rounding_adjustment and self.base_rounding_adjustment:
round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(
self.company, "Purchase Invoice", self.name, self.use_company_roundoff_cost_center
)
@@ -1473,7 +1476,7 @@ class PurchaseInvoice(BuyingController):
def on_cancel(self):
check_if_return_invoice_linked_with_payment_entry(self)
super(PurchaseInvoice, self).on_cancel()
super().on_cancel()
self.check_on_hold_or_closed_status()
@@ -1504,9 +1507,7 @@ class PurchaseInvoice(BuyingController):
if self.update_stock == 1:
self.repost_future_sle_and_gle()
if (
frappe.db.get_single_value("Buying Settings", "project_update_frequency") == "Each Transaction"
):
if frappe.db.get_single_value("Buying Settings", "project_update_frequency") == "Each Transaction":
self.update_project()
self.db_set("status", "Cancelled")
@@ -1538,9 +1539,7 @@ class PurchaseInvoice(BuyingController):
pj = frappe.qb.DocType("Project")
for proj, value in projects.items():
res = (
frappe.qb.from_(pj).select(pj.total_purchase_cost).where(pj.name == proj).for_update().run()
)
res = frappe.qb.from_(pj).select(pj.total_purchase_cost).where(pj.name == proj).for_update().run()
current_purchase_cost = res and res[0][0] or 0
frappe.db.set_value("Project", proj, "total_purchase_cost", current_purchase_cost + value)
@@ -1808,9 +1807,7 @@ def get_purchase_document_details(doc):
)
net_rate_map = frappe._dict(
frappe.get_all(
child_doctype, filters={"name": ("in", items)}, fields=["name", "net_rate"], as_list=1
)
frappe.get_all(child_doctype, filters={"name": ("in", items)}, fields=["name", "net_rate"], as_list=1)
)
return exchange_rate_map, net_rate_map

View File

@@ -2,8 +2,6 @@
# License: GNU General Public License v3. See license.txt
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import add_days, cint, flt, getdate, nowdate, today
@@ -233,7 +231,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
supplier.on_hold = 0
supplier.save()
except:
except Exception:
pass
else:
raise Exception
@@ -267,7 +265,6 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
self.assertEqual(pi.on_hold, 0)
def test_gl_entries_with_perpetual_inventory_against_pr(self):
pr = make_purchase_receipt(
company="_Test Company with perpetual inventory",
supplier_warehouse="Work In Progress - TCP1",
@@ -318,7 +315,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
]
)
for i, gle in enumerate(gl_entries):
for _i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account][0], gle.account)
self.assertEqual(expected_values[gle.account][1], gle.debit)
self.assertEqual(expected_values[gle.account][2], gle.credit)
@@ -342,9 +339,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
pi.submit()
# Get exchnage gain and loss account
exchange_gain_loss_account = frappe.db.get_value(
"Company", pi.company, "exchange_gain_loss_account"
)
exchange_gain_loss_account = frappe.db.get_value("Company", pi.company, "exchange_gain_loss_account")
# fetching the latest GL Entry with exchange gain and loss account account
amount = frappe.db.get_value(
@@ -560,12 +555,10 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
project = frappe.get_doc("Project", {"project_name": "_Test Project for Purchase"})
existing_purchase_cost = frappe.db.sql(
"""select sum(base_net_amount)
f"""select sum(base_net_amount)
from `tabPurchase Invoice Item`
where project = '{0}'
and docstatus=1""".format(
project.name
)
where project = '{project.name}'
and docstatus=1"""
)
existing_purchase_cost = existing_purchase_cost and existing_purchase_cost[0][0] or 0
@@ -740,7 +733,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
"credit",
"credit_in_account_currency",
):
for i, gle in enumerate(gl_entries):
for _i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account][field], gle[field])
# Check for valid currency
@@ -762,7 +755,6 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
self.assertFalse(gle)
def test_purchase_invoice_update_stock_gl_entry_with_perpetual_inventory(self):
pi = make_purchase_invoice(
update_stock=1,
posting_date=frappe.utils.nowdate(),
@@ -791,13 +783,12 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
(d[0], d) for d in [[pi.credit_to, 0.0, 250.0], [stock_in_hand_account, 250.0, 0.0]]
)
for i, gle in enumerate(gl_entries):
for _i, gle in enumerate(gl_entries):
self.assertEqual(expected_gl_entries[gle.account][0], gle.account)
self.assertEqual(expected_gl_entries[gle.account][1], gle.debit)
self.assertEqual(expected_gl_entries[gle.account][2], gle.credit)
def test_purchase_invoice_for_is_paid_and_update_stock_gl_entry_with_perpetual_inventory(self):
pi = make_purchase_invoice(
update_stock=1,
posting_date=frappe.utils.nowdate(),
@@ -832,7 +823,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
]
)
for i, gle in enumerate(gl_entries):
for _i, gle in enumerate(gl_entries):
self.assertEqual(expected_gl_entries[gle.account][0], gle.account)
self.assertEqual(expected_gl_entries[gle.account][1], gle.debit)
self.assertEqual(expected_gl_entries[gle.account][2], gle.credit)
@@ -904,9 +895,9 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
pi.load_from_db()
serial_no = get_serial_nos_from_bundle(pi.get("items")[0].serial_and_batch_bundle)[0]
rejected_serial_no = get_serial_nos_from_bundle(
pi.get("items")[0].rejected_serial_and_batch_bundle
)[0]
rejected_serial_no = get_serial_nos_from_bundle(pi.get("items")[0].rejected_serial_and_batch_bundle)[
0
]
self.assertEqual(
frappe.db.get_value("Serial No", serial_no, "warehouse"),
@@ -1036,12 +1027,8 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
def test_duplicate_due_date_in_terms(self):
pi = make_purchase_invoice(do_not_save=1)
pi.append(
"payment_schedule", dict(due_date="2017-01-01", invoice_portion=50.00, payment_amount=50)
)
pi.append(
"payment_schedule", dict(due_date="2017-01-01", invoice_portion=50.00, payment_amount=50)
)
pi.append("payment_schedule", dict(due_date="2017-01-01", invoice_portion=50.00, payment_amount=50))
pi.append("payment_schedule", dict(due_date="2017-01-01", invoice_portion=50.00, payment_amount=50))
self.assertRaises(frappe.ValidationError, pi.insert)
@@ -1079,9 +1066,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
cost_center = "_Test Cost Center for BS Account - _TC"
create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
pi = make_purchase_invoice_against_cost_center(
cost_center=cost_center, credit_to="Creditors - _TC"
)
pi = make_purchase_invoice_against_cost_center(cost_center=cost_center, credit_to="Creditors - _TC")
self.assertEqual(pi.cost_center, cost_center)
expected_values = {
@@ -1541,9 +1526,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
def test_provisional_accounting_entry(self):
setup_provisional_accounting()
pr = make_purchase_receipt(
item_code="_Test Non Stock Item", posting_date=add_days(nowdate(), -2)
)
pr = make_purchase_receipt(item_code="_Test Non Stock Item", posting_date=add_days(nowdate(), -2))
pi = create_purchase_invoice_from_receipt(pr.name)
pi.set_posting_time = 1
@@ -1552,7 +1535,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
pi.save()
pi.submit()
self.assertEquals(pr.items[0].provisional_expense_account, "Provision Account - _TC")
self.assertEqual(pr.items[0].provisional_expense_account, "Provision Account - _TC")
# Check GLE for Purchase Invoice
expected_gle = [
@@ -1579,9 +1562,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
["_Test Account Cost for Goods Sold - _TC", 250, 0, pi.posting_date],
]
check_gl_entries(
self, pr.name, expected_gle_for_purchase_receipt_post_pi_cancel, pr.posting_date
)
check_gl_entries(self, pr.name, expected_gle_for_purchase_receipt_post_pi_cancel, pr.posting_date)
toggle_provisional_accounting_setting()
@@ -1630,9 +1611,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
["_Test Account Cost for Goods Sold - _TC", 5000, 0, pi.posting_date],
]
check_gl_entries(
self, pr.name, expected_gle_for_purchase_receipt_post_pi_cancel, pr.posting_date
)
check_gl_entries(self, pr.name, expected_gle_for_purchase_receipt_post_pi_cancel, pr.posting_date)
toggle_provisional_accounting_setting()
@@ -1678,9 +1657,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
def test_adjust_incoming_rate(self):
frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 0)
frappe.db.set_single_value(
"Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate", 1
)
frappe.db.set_single_value("Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate", 1)
# Increase the cost of the item
@@ -1732,9 +1709,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
)
self.assertEqual(stock_value_difference, 50)
frappe.db.set_single_value(
"Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate", 0
)
frappe.db.set_single_value("Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate", 0)
# Don't adjust incoming rate
@@ -1764,7 +1739,6 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 1)
def test_item_less_defaults(self):
pi = frappe.new_doc("Purchase Invoice")
pi.supplier = "_Test Supplier"
pi.company = "_Test Company"
@@ -2301,7 +2275,7 @@ def make_purchase_invoice(**args):
pi.cost_center = args.parent_cost_center
bundle_id = None
if not args.use_serial_batch_fields and ((args.get("batch_no") or args.get("serial_no"))):
if not args.use_serial_batch_fields and (args.get("batch_no") or args.get("serial_no")):
batches = {}
qty = args.qty if args.qty is not None else 5
item_code = args.item or args.item_code or "_Test Item"
@@ -2450,9 +2424,7 @@ def setup_provisional_accounting(**args):
parent_account=args.parent_account or "Current Liabilities - _TC",
company=company,
)
toggle_provisional_accounting_setting(
enable=1, company=company, provisional_account=provisional_account
)
toggle_provisional_accounting_setting(enable=1, company=company, provisional_account=provisional_account)
def toggle_provisional_accounting_setting(**args):

View File

@@ -37,4 +37,4 @@ class PurchaseTaxesandChargesTemplate(Document):
def autoname(self):
if self.company and self.title:
abbr = frappe.get_cached_value("Company", self.company, "abbr")
self.name = "{0} - {1}".format(self.title, abbr)
self.name = f"{self.title} - {abbr}"

View File

@@ -27,7 +27,7 @@ class RepostAccountingLedger(Document):
# end: auto-generated types
def __init__(self, *args, **kwargs):
super(RepostAccountingLedger, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self._allowed_types = get_allowed_types_from_settings()
def validate(self):
@@ -154,7 +154,9 @@ def start_repost(account_repost_doc=str) -> None:
doc = frappe.get_doc(x.voucher_type, x.voucher_no)
if repost_doc.delete_cancelled_entries:
frappe.db.delete("GL Entry", filters={"voucher_type": doc.doctype, "voucher_no": doc.name})
frappe.db.delete(
"GL Entry", filters={"voucher_type": doc.doctype, "voucher_no": doc.name}
)
frappe.db.delete(
"Payment Ledger Entry", filters={"voucher_type": doc.doctype, "voucher_no": doc.name}
)
@@ -200,7 +202,9 @@ def validate_docs_for_deferred_accounting(sales_docs, purchase_docs):
if docs_with_deferred_revenue or docs_with_deferred_expense:
frappe.throw(
_("Documents: {0} have deferred revenue/expense enabled for them. Cannot repost.").format(
frappe.bold(comma_and([x[0] for x in docs_with_deferred_expense + docs_with_deferred_revenue]))
frappe.bold(
comma_and([x[0] for x in docs_with_deferred_expense + docs_with_deferred_revenue])
)
)
)

View File

@@ -9,7 +9,6 @@ from frappe.utils import add_days, nowdate, today
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request
from erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger import start_repost
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.accounts.test.accounts_mixin import AccountsTestMixin
from erpnext.accounts.utils import get_fiscal_year

View File

@@ -40,7 +40,7 @@ def start_payment_ledger_repost(docname=None):
frappe.db.set_value(repost_doc.doctype, repost_doc.name, "repost_error_log", "")
frappe.db.set_value(repost_doc.doctype, repost_doc.name, "repost_status", "Completed")
except Exception as e:
except Exception:
frappe.db.rollback()
traceback = frappe.get_traceback(with_context=True)
@@ -75,7 +75,7 @@ class RepostPaymentLedger(Document):
# end: auto-generated types
def __init__(self, *args, **kwargs):
super(RepostPaymentLedger, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.vouchers = []
def before_validate(self):

View File

@@ -235,7 +235,7 @@ class SalesInvoice(SellingController):
# end: auto-generated types
def __init__(self, *args, **kwargs):
super(SalesInvoice, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.status_updater = [
{
"source_dt": "Sales Invoice Item",
@@ -272,7 +272,7 @@ class SalesInvoice(SellingController):
self.indicator_title = _("Paid")
def validate(self):
super(SalesInvoice, self).validate()
super().validate()
self.validate_auto_set_posting_time()
if not (self.is_pos or self.is_debit_note):
@@ -475,9 +475,7 @@ class SalesInvoice(SellingController):
self.update_time_sheet(self.name)
if (
frappe.db.get_single_value("Selling Settings", "sales_update_frequency") == "Each Transaction"
):
if frappe.db.get_single_value("Selling Settings", "sales_update_frequency") == "Each Transaction":
update_company_current_month_sales(self.company)
self.update_project()
update_linked_doc(self.doctype, self.name, self.inter_company_invoice_reference)
@@ -493,9 +491,7 @@ class SalesInvoice(SellingController):
and not self.dont_create_loyalty_points
):
self.make_loyalty_point_entry()
elif (
self.is_return and self.return_against and not self.is_consolidated and self.loyalty_program
):
elif self.is_return and self.return_against and not self.is_consolidated and self.loyalty_program:
against_si_doc = frappe.get_doc("Sales Invoice", self.return_against)
against_si_doc.delete_loyalty_point_entry()
against_si_doc.make_loyalty_point_entry()
@@ -524,11 +520,11 @@ class SalesInvoice(SellingController):
def check_if_consolidated_invoice(self):
# since POS Invoice extends Sales Invoice, we explicitly check if doctype is Sales Invoice
if self.doctype == "Sales Invoice" and self.is_consolidated:
invoice_or_credit_note = (
"consolidated_credit_note" if self.is_return else "consolidated_invoice"
)
invoice_or_credit_note = "consolidated_credit_note" if self.is_return else "consolidated_invoice"
pos_closing_entry = frappe.get_all(
"POS Invoice Merge Log", filters={invoice_or_credit_note: self.name}, pluck="pos_closing_entry"
"POS Invoice Merge Log",
filters={invoice_or_credit_note: self.name},
pluck="pos_closing_entry",
)
if pos_closing_entry and pos_closing_entry[0]:
msg = _("To cancel a {} you need to cancel the POS Closing Entry {}.").format(
@@ -540,13 +536,13 @@ class SalesInvoice(SellingController):
def before_cancel(self):
self.check_if_consolidated_invoice()
super(SalesInvoice, self).before_cancel()
super().before_cancel()
self.update_time_sheet(None)
def on_cancel(self):
check_if_return_invoice_linked_with_payment_entry(self)
super(SalesInvoice, self).on_cancel()
super().on_cancel()
self.check_sales_order_on_hold_or_close("sales_order")
@@ -578,16 +574,12 @@ class SalesInvoice(SellingController):
if self.coupon_code:
update_coupon_code_count(self.coupon_code, "cancelled")
if (
frappe.db.get_single_value("Selling Settings", "sales_update_frequency") == "Each Transaction"
):
if frappe.db.get_single_value("Selling Settings", "sales_update_frequency") == "Each Transaction":
update_company_current_month_sales(self.company)
self.update_project()
if not self.is_return and not self.is_consolidated and self.loyalty_program:
self.delete_loyalty_point_entry()
elif (
self.is_return and self.return_against and not self.is_consolidated and self.loyalty_program
):
elif self.is_return and self.return_against and not self.is_consolidated and self.loyalty_program:
against_si_doc = frappe.get_doc("Sales Invoice", self.return_against)
against_si_doc.delete_loyalty_point_entry()
against_si_doc.make_loyalty_point_entry()
@@ -694,7 +686,7 @@ class SalesInvoice(SellingController):
if not self.due_date and self.customer:
self.due_date = get_due_date(self.posting_date, "Customer", self.customer, self.company)
super(SalesInvoice, self).set_missing_values(for_validate)
super().set_missing_values(for_validate)
print_format = pos.get("print_format") if pos else None
if not print_format and not cint(frappe.db.get_value("Print Format", "POS Invoice", "disabled")):
@@ -885,7 +877,8 @@ class SalesInvoice(SellingController):
if account.report_type != "Balance Sheet":
msg = (
_("Please ensure {} account is a Balance Sheet account.").format(frappe.bold("Debit To")) + " "
_("Please ensure {} account is a Balance Sheet account.").format(frappe.bold("Debit To"))
+ " "
)
msg += _(
"You can change the parent account to a Balance Sheet account or select a different account."
@@ -914,11 +907,16 @@ class SalesInvoice(SellingController):
)
def validate_with_previous_doc(self):
super(SalesInvoice, self).validate_with_previous_doc(
super().validate_with_previous_doc(
{
"Sales Order": {
"ref_dn_field": "sales_order",
"compare_fields": [["customer", "="], ["company", "="], ["project", "="], ["currency", "="]],
"compare_fields": [
["customer", "="],
["company", "="],
["project", "="],
["currency", "="],
],
},
"Sales Order Item": {
"ref_dn_field": "so_detail",
@@ -928,7 +926,12 @@ class SalesInvoice(SellingController):
},
"Delivery Note": {
"ref_dn_field": "delivery_note",
"compare_fields": [["customer", "="], ["company", "="], ["project", "="], ["currency", "="]],
"compare_fields": [
["customer", "="],
["company", "="],
["project", "="],
["currency", "="],
],
},
"Delivery Note Item": {
"ref_dn_field": "dn_detail",
@@ -983,13 +986,14 @@ class SalesInvoice(SellingController):
}
for key, value in prev_doc_field_map.items():
if frappe.db.get_single_value("Selling Settings", value[0]) == "Yes":
if frappe.get_value("Customer", self.customer, value[0]):
continue
for d in self.get("items"):
if d.item_code and not d.get(key.lower().replace(" ", "_")) and not self.get(value[1]):
msgprint(_("{0} is mandatory for Item {1}").format(key, d.item_code), raise_exception=1)
msgprint(
_("{0} is mandatory for Item {1}").format(key, d.item_code), raise_exception=1
)
def validate_proj_cust(self):
"""check for does customer belong to same project as entered.."""
@@ -1011,7 +1015,7 @@ class SalesInvoice(SellingController):
frappe.throw(_("Paid amount + Write Off Amount can not be greater than Grand Total"))
def validate_warehouse(self):
super(SalesInvoice, self).validate_warehouse()
super().validate_warehouse()
for d in self.get_item_list():
if (
@@ -1331,7 +1335,9 @@ class SalesInvoice(SellingController):
add_asset_activity(asset.name, _("Asset returned"))
if asset.calculate_depreciation:
posting_date = frappe.db.get_value("Sales Invoice", self.return_against, "posting_date")
posting_date = frappe.db.get_value(
"Sales Invoice", self.return_against, "posting_date"
)
reverse_depreciation_entry_made_after_disposal(asset, posting_date)
notes = _(
"This schedule was created when Asset {0} was returned through Sales Invoice {1}."
@@ -1379,7 +1385,9 @@ class SalesInvoice(SellingController):
else item.deferred_revenue_account
)
amount, base_amount = self.get_amount_and_base_amount(item, enable_discount_accounting)
amount, base_amount = self.get_amount_and_base_amount(
item, enable_discount_accounting
)
account_currency = get_account_currency(income_account)
gl_entries.append(
@@ -1403,7 +1411,7 @@ class SalesInvoice(SellingController):
# expense account gl entries
if cint(self.update_stock) and erpnext.is_perpetual_inventory_enabled(self.company):
gl_entries += super(SalesInvoice, self).get_gl_entries()
gl_entries += super().get_gl_entries()
def get_asset(self, item):
if item.get("asset"):
@@ -1466,7 +1474,6 @@ class SalesInvoice(SellingController):
def make_pos_gl_entries(self, gl_entries):
if cint(self.is_pos):
skip_change_gl_entries = not cint(
frappe.db.get_single_value("Accounts Settings", "post_change_gl_entries")
)
@@ -1624,7 +1631,9 @@ class SalesInvoice(SellingController):
"credit_in_account_currency": flt(
self.rounding_adjustment, self.precision("rounding_adjustment")
),
"credit": flt(self.base_rounding_adjustment, self.precision("base_rounding_adjustment")),
"credit": flt(
self.base_rounding_adjustment, self.precision("base_rounding_adjustment")
),
"cost_center": round_off_cost_center
if self.use_company_roundoff_cost_center
else (self.cost_center or round_off_cost_center),
@@ -1646,7 +1655,11 @@ class SalesInvoice(SellingController):
)
billed_amt = billed_amt and billed_amt[0][0] or 0
frappe.db.set_value(
"Delivery Note Item", d.dn_detail, "billed_amt", billed_amt, update_modified=update_modified
"Delivery Note Item",
d.dn_detail,
"billed_amt",
billed_amt,
update_modified=update_modified,
)
updated_delivery_notes.append(d.delivery_note)
elif d.so_detail:
@@ -1701,7 +1714,6 @@ class SalesInvoice(SellingController):
and getdate(lp_details.from_date) <= getdate(self.posting_date)
and (not lp_details.to_date or getdate(lp_details.to_date) >= getdate(self.posting_date))
):
collection_factor = lp_details.collection_factor if lp_details.collection_factor else 1.0
points_earned = cint(eligible_amount / collection_factor)
@@ -1961,7 +1973,6 @@ def validate_inter_company_party(doctype, party, company, inter_company_referenc
def update_linked_doc(doctype, name, inter_company_reference):
if doctype in ["Sales Invoice", "Purchase Invoice"]:
ref_field = "inter_company_invoice_reference"
else:
@@ -1972,7 +1983,6 @@ def update_linked_doc(doctype, name, inter_company_reference):
def unlink_inter_company_doc(doctype, name, inter_company_reference):
if doctype in ["Sales Invoice", "Purchase Invoice"]:
ref_doc = "Purchase Invoice" if doctype == "Sales Invoice" else "Sales Invoice"
ref_field = "inter_company_invoice_reference"
@@ -2147,16 +2157,13 @@ def get_internal_party(parties, link_doctype, doc):
def validate_inter_company_transaction(doc, doctype):
details = get_inter_company_details(doc, doctype)
price_list = (
doc.selling_price_list
if doctype in ["Sales Invoice", "Sales Order", "Delivery Note"]
else doc.buying_price_list
)
valid_price_list = frappe.db.get_value(
"Price List", {"name": price_list, "buying": 1, "selling": 1}
)
valid_price_list = frappe.db.get_value("Price List", {"name": price_list, "buying": 1, "selling": 1})
if not valid_price_list and not doc.is_internal_transfer():
frappe.throw(_("Selected Price List should have buying and selling fields checked."))
@@ -2417,9 +2424,7 @@ def update_pr_items(doc, sales_item_map, purchase_item_map, parent_child_map, wa
for item in doc.get("items"):
item.warehouse = warehouse_map.get(sales_item_map.get(item.delivery_note_item))
if not item.warehouse and item.get("purchase_order") and item.get("purchase_order_item"):
item.warehouse = frappe.db.get_value(
"Purchase Order Item", item.purchase_order_item, "warehouse"
)
item.warehouse = frappe.db.get_value("Purchase Order Item", item.purchase_order_item, "warehouse")
def get_delivery_note_details(internal_reference):
@@ -2665,9 +2670,7 @@ def check_if_return_invoice_linked_with_payment_entry(self):
# If a Return invoice is linked with payment entry along with other invoices,
# the cancellation of the Return causes allocated amount to be greater than paid
if not frappe.db.get_single_value(
"Accounts Settings", "unlink_payment_on_cancellation_of_invoice"
):
if not frappe.db.get_single_value("Accounts Settings", "unlink_payment_on_cancellation_of_invoice"):
return
payment_entries = []

View File

@@ -2,7 +2,6 @@
# License: GNU General Public License v3. See license.txt
import copy
import unittest
import frappe
from frappe.model.dynamic_links import get_dynamic_link_map
@@ -925,7 +924,7 @@ class TestSalesInvoice(FrappeTestCase):
]
)
for i, gle in enumerate(gl_entries):
for _i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account][0], gle.account)
self.assertEqual(expected_values[gle.account][1], gle.debit)
self.assertEqual(expected_values[gle.account][2], gle.credit)
@@ -951,7 +950,7 @@ class TestSalesInvoice(FrappeTestCase):
write_off_account="_Test Write Off - TCP1",
)
pr = make_purchase_receipt(
make_purchase_receipt(
company="_Test Company with perpetual inventory",
item_code="_Test FG Item",
warehouse="Stores - TCP1",
@@ -1332,7 +1331,7 @@ class TestSalesInvoice(FrappeTestCase):
expected_values = dict(
(d[0], d) for d in [["Debtors - TCP1", 100.0, 0.0], ["Sales - TCP1", 0.0, 100.0]]
)
for i, gle in enumerate(gl_entries):
for _i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account][0], gle.account)
self.assertEqual(expected_values[gle.account][1], gle.debit)
self.assertEqual(expected_values[gle.account][2], gle.credit)
@@ -1356,7 +1355,7 @@ class TestSalesInvoice(FrappeTestCase):
[test_records[1]["items"][0]["income_account"], 0.0, 100.0],
]
)
for i, gle in enumerate(gl_entries):
for _i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account][0], gle.account)
self.assertEqual(expected_values[gle.account][1], gle.debit)
self.assertEqual(expected_values[gle.account][2], gle.credit)
@@ -1431,7 +1430,6 @@ class TestSalesInvoice(FrappeTestCase):
si.cancel()
def test_serialized(self):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
se = make_serialized_item()
@@ -1771,7 +1769,7 @@ class TestSalesInvoice(FrappeTestCase):
"credit",
"credit_in_account_currency",
):
for i, gle in enumerate(gl_entries):
for _i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account][field], gle[field])
# cancel
@@ -2315,12 +2313,8 @@ class TestSalesInvoice(FrappeTestCase):
def test_duplicate_due_date_in_terms(self):
si = create_sales_invoice(do_not_save=1)
si.append(
"payment_schedule", dict(due_date="2017-01-01", invoice_portion=50.00, payment_amount=50)
)
si.append(
"payment_schedule", dict(due_date="2017-01-01", invoice_portion=50.00, payment_amount=50)
)
si.append("payment_schedule", dict(due_date="2017-01-01", invoice_portion=50.00, payment_amount=50))
si.append("payment_schedule", dict(due_date="2017-01-01", invoice_portion=50.00, payment_amount=50))
self.assertRaises(frappe.ValidationError, si.insert)
@@ -2514,9 +2508,7 @@ class TestSalesInvoice(FrappeTestCase):
item.no_of_months = 12
item.save()
si = create_sales_invoice(
item=item.name, posting_date="2019-01-16", rate=50000, do_not_submit=True
)
si = create_sales_invoice(item=item.name, posting_date="2019-01-16", rate=50000, do_not_submit=True)
si.items[0].enable_deferred_revenue = 1
si.items[0].service_start_date = "2019-01-16"
si.items[0].service_end_date = "2019-03-31"
@@ -2837,21 +2829,16 @@ class TestSalesInvoice(FrappeTestCase):
item.save()
sales_invoice = create_sales_invoice(item="T Shirt", rate=700, do_not_submit=True)
self.assertEqual(
sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 12 - _TC"
)
self.assertEqual(sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 12 - _TC")
# Apply discount
sales_invoice.apply_discount_on = "Net Total"
sales_invoice.discount_amount = 300
sales_invoice.save()
self.assertEqual(
sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 10 - _TC"
)
self.assertEqual(sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 10 - _TC")
@change_settings("Selling Settings", {"enable_discount_accounting": 1})
def test_sales_invoice_with_discount_accounting_enabled(self):
discount_account = create_account(
account_name="Discount Account",
parent_account="Indirect Expenses - _TC",
@@ -2869,7 +2856,6 @@ class TestSalesInvoice(FrappeTestCase):
@change_settings("Selling Settings", {"enable_discount_accounting": 1})
def test_additional_discount_for_sales_invoice_with_discount_accounting_enabled(self):
from erpnext.accounts.doctype.repost_accounting_ledger.test_repost_accounting_ledger import (
update_repost_settings,
)
@@ -2882,7 +2868,7 @@ class TestSalesInvoice(FrappeTestCase):
company="_Test Company",
)
tds_payable_account = create_account(
create_account(
account_name="TDS Payable",
account_type="Tax",
parent_account="Duties and Taxes - _TC",
@@ -3204,9 +3190,7 @@ class TestSalesInvoice(FrappeTestCase):
"""
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
over_billing_allowance = frappe.db.get_single_value(
"Accounts Settings", "over_billing_allowance"
)
over_billing_allowance = frappe.db.get_single_value("Accounts Settings", "over_billing_allowance")
frappe.db.set_single_value("Accounts Settings", "over_billing_allowance", 0)
dn = create_delivery_note()
@@ -3398,7 +3382,7 @@ class TestSalesInvoice(FrappeTestCase):
self.assertEqual(len(journals), 1)
je_type = frappe.get_cached_value("Journal Entry", journals[0], "voucher_type")
self.assertEqual(je_type, "Exchange Gain Or Loss")
ledger_outstanding = frappe.db.get_all(
frappe.db.get_all(
"Payment Ledger Entry",
filters={"against_voucher_no": si.name, "delinked": 0},
fields=["sum(amount), sum(amount_in_account_currency)"],
@@ -3660,41 +3644,6 @@ def set_advance_flag(company, flag, default_account):
)
def get_sales_invoice_for_e_invoice():
si = make_sales_invoice_for_ewaybill()
si.naming_series = "INV-2020-.#####"
si.items = []
si.append(
"items",
{
"item_code": "_Test Item",
"uom": "Nos",
"warehouse": "_Test Warehouse - _TC",
"qty": 2000,
"rate": 12,
"income_account": "Sales - _TC",
"expense_account": "Cost of Goods Sold - _TC",
"cost_center": "_Test Cost Center - _TC",
},
)
si.append(
"items",
{
"item_code": "_Test Item 2",
"uom": "Nos",
"warehouse": "_Test Warehouse - _TC",
"qty": 420,
"rate": 15,
"income_account": "Sales - _TC",
"expense_account": "Cost of Goods Sold - _TC",
"cost_center": "_Test Cost Center - _TC",
},
)
return si
def check_gl_entries(doc, voucher_no, expected_gle, posting_date, voucher_type="Sales Invoice"):
gl = frappe.qb.DocType("GL Entry")
q = (

View File

@@ -42,7 +42,7 @@ class SalesTaxesandChargesTemplate(Document):
def autoname(self):
if self.company and self.title:
abbr = frappe.get_cached_value("Company", self.company, "abbr")
self.name = "{0} - {1}".format(self.title, abbr)
self.name = f"{self.title} - {abbr}"
def set_missing_values(self):
for data in self.taxes:
@@ -57,10 +57,8 @@ def valdiate_taxes_and_charges_template(doc):
if doc.is_default == 1:
frappe.db.sql(
"""update `tab{0}` set is_default = 0
where is_default = 1 and name != %s and company = %s""".format(
doc.doctype
),
f"""update `tab{doc.doctype}` set is_default = 0
where is_default = 1 and name != %s and company = %s""",
(doc.name, doc.company),
)

View File

@@ -205,7 +205,9 @@ class ShareTransfer(Document):
doc = self.get_shareholder_doc(shareholder)
for entry in doc.share_balance:
if (
entry.share_type != self.share_type or entry.from_no > self.to_no or entry.to_no < self.from_no
entry.share_type != self.share_type
or entry.from_no > self.to_no
or entry.to_no < self.from_no
):
continue # since query lies outside bounds
elif entry.from_no <= self.from_no and entry.to_no >= self.to_no: # both inside
@@ -257,7 +259,9 @@ class ShareTransfer(Document):
for entry in current_entries:
# use spaceage logic here
if (
entry.share_type != self.share_type or entry.from_no > self.to_no or entry.to_no < self.from_no
entry.share_type != self.share_type
or entry.from_no > self.to_no
or entry.to_no < self.from_no
):
new_entries.append(entry)
continue # since query lies outside bounds
@@ -267,7 +271,9 @@ class ShareTransfer(Document):
if entry.to_no == self.to_no:
pass # nothing to append
else:
new_entries.append(self.return_share_balance_entry(self.to_no + 1, entry.to_no, entry.rate))
new_entries.append(
self.return_share_balance_entry(self.to_no + 1, entry.to_no, entry.rate)
)
else:
if entry.to_no == self.to_no:
new_entries.append(
@@ -277,7 +283,9 @@ class ShareTransfer(Document):
new_entries.append(
self.return_share_balance_entry(entry.from_no, self.from_no - 1, entry.rate)
)
new_entries.append(self.return_share_balance_entry(self.to_no + 1, entry.to_no, entry.rate))
new_entries.append(
self.return_share_balance_entry(self.to_no + 1, entry.to_no, entry.rate)
)
elif entry.from_no >= self.from_no and entry.to_no <= self.to_no:
# split and check
pass # nothing to append
@@ -309,7 +317,7 @@ class ShareTransfer(Document):
def get_shareholder_doc(self, shareholder):
# Get Shareholder doc based on the Shareholder name
if shareholder:
query_filters = {"name": shareholder}
pass
name = frappe.db.get_value("Shareholder", {"name": shareholder}, "name")

View File

@@ -71,7 +71,8 @@ class ShippingRule(Document):
zero_to_values.append(d)
elif d.from_value >= d.to_value:
throw(
_("From value must be less than to value in row {0}").format(d.idx), FromGreaterThanToError
_("From value must be less than to value in row {0}").format(d.idx),
FromGreaterThanToError,
)
# check if more than two or more rows has To Value = 0
@@ -114,9 +115,7 @@ class ShippingRule(Document):
def get_shipping_amount_from_rules(self, value):
for condition in self.get("conditions"):
if not condition.to_value or (
flt(condition.from_value) <= flt(value) <= flt(condition.to_value)
):
if not condition.to_value or (flt(condition.from_value) <= flt(value) <= flt(condition.to_value)):
return condition.shipping_amount
return 0.0
@@ -131,7 +130,9 @@ class ShippingRule(Document):
)
if shipping_country not in [d.country for d in self.countries]:
frappe.throw(
_("Shipping rule not applicable for country {0} in Shipping Address").format(shipping_country)
_("Shipping rule not applicable for country {0} in Shipping Address").format(
shipping_country
)
)
def add_shipping_rule_to_tax_table(self, doc, shipping_amount):
@@ -199,11 +200,9 @@ class ShippingRule(Document):
messages = []
for d1, d2 in overlaps:
messages.append(
"%s-%s = %s "
% (d1.from_value, d1.to_value, fmt_money(d1.shipping_amount, currency=company_currency))
f"{d1.from_value}-{d1.to_value} = {fmt_money(d1.shipping_amount, currency=company_currency)} "
+ _("and")
+ " %s-%s = %s"
% (d2.from_value, d2.to_value, fmt_money(d2.shipping_amount, currency=company_currency))
+ f" {d2.from_value}-{d2.to_value} = {fmt_money(d2.shipping_amount, currency=company_currency)}"
)
msgprint("\n".join(messages), raise_exception=OverlappingConditionError)

View File

@@ -45,7 +45,6 @@ class TestShippingRule(unittest.TestCase):
def create_shipping_rule(shipping_rule_type, shipping_rule_name):
if frappe.db.exists("Shipping Rule", shipping_rule_name):
return frappe.get_doc("Shipping Rule", shipping_rule_name)

View File

@@ -2,8 +2,7 @@
# For license information, please see license.txt
from datetime import datetime
from typing import Dict, List, Optional, Union
from datetime import date
import frappe
from frappe import _
@@ -37,7 +36,7 @@ class InvoiceNotCancelled(frappe.ValidationError):
pass
DateTimeLikeObject = Union[str, datetime.date]
DateTimeLikeObject = str | date
class Subscription(Document):
@@ -88,7 +87,7 @@ class Subscription(Document):
# update start just before the subscription doc is created
self.update_subscription_period(self.start_date)
def update_subscription_period(self, date: Optional["DateTimeLikeObject"] = None):
def update_subscription_period(self, date: DateTimeLikeObject | None = None):
"""
Subscription period is the period to be billed. This method updates the
beginning of the billing period and end of the billing period.
@@ -99,15 +98,13 @@ class Subscription(Document):
self.current_invoice_start = self.get_current_invoice_start(date)
self.current_invoice_end = self.get_current_invoice_end(self.current_invoice_start)
def _get_subscription_period(self, date: Optional["DateTimeLikeObject"] = None):
def _get_subscription_period(self, date: DateTimeLikeObject | None = None):
_current_invoice_start = self.get_current_invoice_start(date)
_current_invoice_end = self.get_current_invoice_end(_current_invoice_start)
return _current_invoice_start, _current_invoice_end
def get_current_invoice_start(
self, date: Optional["DateTimeLikeObject"] = None
) -> Union[datetime.date, str]:
def get_current_invoice_start(self, date: DateTimeLikeObject | None = None) -> DateTimeLikeObject:
"""
This returns the date of the beginning of the current billing period.
If the `date` parameter is not given , it will be automatically set as today's
@@ -130,9 +127,7 @@ class Subscription(Document):
return _current_invoice_start
def get_current_invoice_end(
self, date: Optional["DateTimeLikeObject"] = None
) -> Union[datetime.date, str]:
def get_current_invoice_end(self, date: DateTimeLikeObject | None = None) -> DateTimeLikeObject:
"""
This returns the date of the end of the current billing period.
If the subscription is in trial period, it will be set as the end of the
@@ -174,7 +169,7 @@ class Subscription(Document):
return _current_invoice_end
@staticmethod
def validate_plans_billing_cycle(billing_cycle_data: List[Dict[str, str]]) -> None:
def validate_plans_billing_cycle(billing_cycle_data: list[dict[str, str]]) -> None:
"""
Makes sure that all `Subscription Plan` in the `Subscription` have the
same billing interval
@@ -182,7 +177,7 @@ class Subscription(Document):
if billing_cycle_data and len(billing_cycle_data) != 1:
frappe.throw(_("You can only have Plans with the same billing cycle in a Subscription"))
def get_billing_cycle_and_interval(self) -> List[Dict[str, str]]:
def get_billing_cycle_and_interval(self) -> list[dict[str, str]]:
"""
Returns a dict representing the billing interval and cycle for this `Subscription`.
You shouldn't need to call this directly. Use `get_billing_cycle` instead.
@@ -199,7 +194,7 @@ class Subscription(Document):
return billing_info
def get_billing_cycle_data(self) -> Dict[str, int]:
def get_billing_cycle_data(self) -> dict[str, int]:
"""
Returns dict contain the billing cycle data.
You shouldn't need to call this directly. Use `get_billing_cycle` instead.
@@ -226,15 +221,13 @@ class Subscription(Document):
return data
def set_subscription_status(self, posting_date: Optional["DateTimeLikeObject"] = None) -> None:
def set_subscription_status(self, posting_date: DateTimeLikeObject | None = None) -> None:
"""
Sets the status of the `Subscription`
"""
if self.is_trialling():
self.status = "Trialing"
elif (
self.status == "Active" and self.end_date and getdate(posting_date) > getdate(self.end_date)
):
elif self.status == "Active" and self.end_date and getdate(posting_date) > getdate(self.end_date):
self.status = "Completed"
elif self.is_past_grace_period():
self.status = self.get_status_for_past_grace_period()
@@ -252,7 +245,7 @@ class Subscription(Document):
@staticmethod
def period_has_passed(
end_date: Union[str, datetime.date], posting_date: Optional["DateTimeLikeObject"] = None
end_date: DateTimeLikeObject, posting_date: DateTimeLikeObject | None = None
) -> bool:
"""
Returns true if the given `end_date` has passed
@@ -272,7 +265,7 @@ class Subscription(Document):
return status
def is_past_grace_period(self, posting_date: Optional["DateTimeLikeObject"] = None) -> bool:
def is_past_grace_period(self, posting_date: DateTimeLikeObject | None = None) -> bool:
"""
Returns `True` if the grace period for the `Subscription` has passed
"""
@@ -282,9 +275,7 @@ class Subscription(Document):
grace_period = cint(frappe.get_value("Subscription Settings", None, "grace_period"))
return getdate(posting_date) >= getdate(add_days(self.current_invoice.due_date, grace_period))
def current_invoice_is_past_due(
self, posting_date: Optional["DateTimeLikeObject"] = None
) -> bool:
def current_invoice_is_past_due(self, posting_date: DateTimeLikeObject | None = None) -> bool:
"""
Returns `True` if the current generated invoice is overdue
"""
@@ -334,14 +325,15 @@ class Subscription(Document):
unsupported_plans = []
for x in subscription_plan_currencies:
if x.currency != party_billing_currency:
unsupported_plans.append("{0}".format(get_link_to_form("Subscription Plan", x.name)))
unsupported_plans.append("{}".format(get_link_to_form("Subscription Plan", x.name)))
if unsupported_plans:
unsupported_plans = [
_(
"Below Subscription Plans are of different currency to the party default billing currency/Company currency: {0}"
).format(frappe.bold(party_billing_currency))
] + unsupported_plans
).format(frappe.bold(party_billing_currency)),
*unsupported_plans,
]
frappe.throw(
unsupported_plans, frappe.ValidationError, "Unsupported Subscription Plans", as_list=True
@@ -384,9 +376,9 @@ class Subscription(Document):
def generate_invoice(
self,
from_date: Optional[Union[str, datetime.date]] = None,
to_date: Optional[Union[str, datetime.date]] = None,
posting_date: Optional[Union[str, datetime.date]] = None,
from_date: DateTimeLikeObject | None = None,
to_date: DateTimeLikeObject | None = None,
posting_date: DateTimeLikeObject | None = None,
) -> Document:
"""
Creates a `Invoice` for the `Subscription`, updates `self.invoices` and
@@ -397,9 +389,9 @@ class Subscription(Document):
def create_invoice(
self,
from_date: Optional[Union[str, datetime.date]] = None,
to_date: Optional[Union[str, datetime.date]] = None,
posting_date: Optional[Union[str, datetime.date]] = None,
from_date: DateTimeLikeObject | None = None,
to_date: DateTimeLikeObject | None = None,
posting_date: DateTimeLikeObject | None = None,
) -> Document:
"""
Creates a `Invoice`, submits it and returns it
@@ -503,9 +495,7 @@ class Subscription(Document):
return invoice
def get_items_from_plans(
self, plans: List[Dict[str, str]], prorate: Optional[bool] = None
) -> List[Dict]:
def get_items_from_plans(self, plans: list[dict[str, str]], prorate: bool | None = None) -> list[dict]:
"""
Returns the `Item`s linked to `Subscription Plan`
"""
@@ -581,7 +571,7 @@ class Subscription(Document):
return items
@frappe.whitelist()
def process(self, posting_date: Optional["DateTimeLikeObject"] = None) -> bool:
def process(self, posting_date: DateTimeLikeObject | None = None) -> bool:
"""
To be called by task periodically. It checks the subscription and takes appropriate action
as need be. It calls either of these methods depending the `Subscription` status:
@@ -606,7 +596,7 @@ class Subscription(Document):
self.save()
def can_generate_new_invoice(self, posting_date: Optional["DateTimeLikeObject"] = None) -> bool:
def can_generate_new_invoice(self, posting_date: DateTimeLikeObject | None = None) -> bool:
if self.cancelation_date:
return False
@@ -628,8 +618,8 @@ class Subscription(Document):
def is_current_invoice_generated(
self,
_current_start_date: Union[datetime.date, str] = None,
_current_end_date: Union[datetime.date, str] = None,
_current_start_date: DateTimeLikeObject | None = None,
_current_end_date: DateTimeLikeObject | None = None,
) -> bool:
if not (_current_start_date and _current_end_date):
_current_start_date, _current_end_date = self._get_subscription_period(
@@ -644,13 +634,13 @@ class Subscription(Document):
return False
@property
def current_invoice(self) -> Union[Document, None]:
def current_invoice(self) -> Document | None:
"""
Adds property for accessing the current_invoice
"""
return self.get_current_invoice()
def get_current_invoice(self) -> Union[Document, None]:
def get_current_invoice(self) -> Document | None:
"""
Returns the most recent generated invoice.
"""
@@ -675,7 +665,7 @@ class Subscription(Document):
self.cancelation_date = nowdate()
@property
def invoices(self) -> List[Dict]:
def invoices(self) -> list[dict]:
return frappe.get_all(
self.invoice_document_type,
filters={"subscription": self.name},
@@ -725,7 +715,7 @@ class Subscription(Document):
self.save()
@frappe.whitelist()
def restart_subscription(self, posting_date: Optional["DateTimeLikeObject"] = None) -> None:
def restart_subscription(self, posting_date: DateTimeLikeObject | None = None) -> None:
"""
This sets the subscription as active. The subscription will be made to be like a new
subscription and the `Subscription` will lose all the history of generated invoices
@@ -745,10 +735,10 @@ def is_prorate() -> int:
def get_prorata_factor(
period_end: Union[datetime.date, str],
period_start: Union[datetime.date, str],
is_prepaid: Optional[int] = None,
) -> Union[int, float]:
period_end: DateTimeLikeObject,
period_start: DateTimeLikeObject,
is_prepaid: int | None = None,
) -> int | float:
if is_prepaid:
return 1
@@ -757,9 +747,7 @@ def get_prorata_factor(
return diff / plan_days
def process_all(
subscription: str | None = None, posting_date: Optional["DateTimeLikeObject"] = None
) -> None:
def process_all(subscription: str | None = None, posting_date: DateTimeLikeObject | None = None) -> None:
"""
Task to updates the status of all `Subscription` apart from those that are cancelled
"""

View File

@@ -1,7 +1,6 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase
@@ -201,9 +200,7 @@ class TestSubscription(FrappeTestCase):
invoice = subscription.get_current_invoice()
diff = flt(date_diff(nowdate(), subscription.current_invoice_start) + 1)
plan_days = flt(
date_diff(subscription.current_invoice_end, subscription.current_invoice_start) + 1
)
plan_days = flt(date_diff(subscription.current_invoice_end, subscription.current_invoice_start) + 1)
prorate_factor = flt(diff / plan_days)
self.assertEqual(
@@ -249,9 +246,7 @@ class TestSubscription(FrappeTestCase):
invoice = subscription.get_current_invoice()
diff = flt(date_diff(nowdate(), subscription.current_invoice_start) + 1)
plan_days = flt(
date_diff(subscription.current_invoice_end, subscription.current_invoice_start) + 1
)
plan_days = flt(date_diff(subscription.current_invoice_end, subscription.current_invoice_start) + 1)
prorate_factor = flt(diff / plan_days)
self.assertEqual(flt(invoice.grand_total, 2), flt(prorate_factor * 900, 2))
@@ -385,9 +380,7 @@ class TestSubscription(FrappeTestCase):
settings.prorate = 1
settings.save()
subscription = create_subscription(
generate_invoice_at="Beginning of the current subscription period"
)
subscription = create_subscription(generate_invoice_at="Beginning of the current subscription period")
subscription.process()
subscription.cancel_subscription()
@@ -546,9 +539,7 @@ def make_plans():
billing_interval_count=3,
currency="INR",
)
create_plan(
plan_name="_Test Plan Multicurrency", cost=50, billing_interval="Month", currency="USD"
)
create_plan(plan_name="_Test Plan Multicurrency", cost=50, billing_interval="Month", currency="USD")
def create_plan(**kwargs):
@@ -575,9 +566,7 @@ def create_parties():
customer = frappe.new_doc("Customer")
customer.customer_name = "_Test Subscription Customer"
customer.billing_currency = "USD"
customer.append(
"accounts", {"company": "_Test Company", "account": "_Test Receivable USD - _TC"}
)
customer.append("accounts", {"company": "_Test Company", "account": "_Test Receivable USD - _TC"})
customer.insert()
@@ -600,9 +589,7 @@ def create_subscription(**kwargs):
subscription.additional_discount_percentage = kwargs.get("additional_discount_percentage")
subscription.additional_discount_amount = kwargs.get("additional_discount_amount")
subscription.follow_calendar_months = kwargs.get("follow_calendar_months")
subscription.generate_new_invoices_past_due_date = kwargs.get(
"generate_new_invoices_past_due_date"
)
subscription.generate_new_invoices_past_due_date = kwargs.get("generate_new_invoices_past_due_date")
subscription.submit_invoice = kwargs.get("submit_invoice")
subscription.days_until_due = kwargs.get("days_until_due")
subscription.number_of_days = kwargs.get("number_of_days")

View File

@@ -112,27 +112,23 @@ class TaxRule(Document):
for d in filters:
if conds:
conds += " and "
conds += """ifnull({0}, '') = {1}""".format(d, frappe.db.escape(cstr(filters[d])))
conds += f"""ifnull({d}, '') = {frappe.db.escape(cstr(filters[d]))}"""
if self.from_date and self.to_date:
conds += """ and ((from_date > '{from_date}' and from_date < '{to_date}') or
(to_date > '{from_date}' and to_date < '{to_date}') or
('{from_date}' > from_date and '{from_date}' < to_date) or
('{from_date}' = from_date and '{to_date}' = to_date))""".format(
from_date=self.from_date, to_date=self.to_date
)
conds += f""" and ((from_date > '{self.from_date}' and from_date < '{self.to_date}') or
(to_date > '{self.from_date}' and to_date < '{self.to_date}') or
('{self.from_date}' > from_date and '{self.from_date}' < to_date) or
('{self.from_date}' = from_date and '{self.to_date}' = to_date))"""
elif self.from_date and not self.to_date:
conds += """ and to_date > '{from_date}'""".format(from_date=self.from_date)
conds += f""" and to_date > '{self.from_date}'"""
elif self.to_date and not self.from_date:
conds += """ and from_date < '{to_date}'""".format(to_date=self.to_date)
conds += f""" and from_date < '{self.to_date}'"""
tax_rule = frappe.db.sql(
"select name, priority \
from `tabTax Rule` where {0} and name != '{1}'".format(
conds, self.name
),
f"select name, priority \
from `tabTax Rule` where {conds} and name != '{self.name}'",
as_dict=1,
)
@@ -189,27 +185,25 @@ def get_tax_template(posting_date, args):
conditions.append("(from_date is null) and (to_date is null)")
conditions.append(
"ifnull(tax_category, '') = {0}".format(frappe.db.escape(cstr(args.get("tax_category"))))
"ifnull(tax_category, '') = {}".format(frappe.db.escape(cstr(args.get("tax_category"))))
)
if "tax_category" in args.keys():
del args["tax_category"]
for key, value in args.items():
if key == "use_for_shopping_cart":
conditions.append("use_for_shopping_cart = {0}".format(1 if value else 0))
conditions.append(f"use_for_shopping_cart = {1 if value else 0}")
elif key == "customer_group":
if not value:
value = get_root_of("Customer Group")
customer_group_condition = get_customer_group_condition(value)
conditions.append("ifnull({0}, '') in ('', {1})".format(key, customer_group_condition))
conditions.append(f"ifnull({key}, '') in ('', {customer_group_condition})")
else:
conditions.append("ifnull({0}, '') in ('', {1})".format(key, frappe.db.escape(cstr(value))))
conditions.append(f"ifnull({key}, '') in ('', {frappe.db.escape(cstr(value))})")
tax_rule = frappe.db.sql(
"""select * from `tabTax Rule`
where {0}""".format(
" and ".join(conditions)
),
where {}""".format(" and ".join(conditions)),
as_dict=True,
)
@@ -234,7 +228,7 @@ def get_tax_template(posting_date, args):
)[0]
tax_template = rule.sales_tax_template or rule.purchase_tax_template
doctype = "{0} Taxes and Charges Template".format(rule.tax_type)
doctype = f"{rule.tax_type} Taxes and Charges Template"
if frappe.db.get_value(doctype, tax_template, "disabled") == 1:
return None
@@ -244,9 +238,7 @@ def get_tax_template(posting_date, args):
def get_customer_group_condition(customer_group):
condition = ""
customer_groups = [
"%s" % (frappe.db.escape(d.name)) for d in get_parent_customer_groups(customer_group)
]
customer_groups = ["%s" % (frappe.db.escape(d.name)) for d in get_parent_customer_groups(customer_group)]
if customer_groups:
condition = ",".join(["%s"] * len(customer_groups)) % (tuple(customer_groups))
return condition

View File

@@ -57,13 +57,11 @@ class TaxWithholdingCategory(Document):
def validate_thresholds(self):
for d in self.get("rates"):
if (
d.cumulative_threshold and d.single_threshold and d.cumulative_threshold < d.single_threshold
):
if d.cumulative_threshold and d.single_threshold and d.cumulative_threshold < d.single_threshold:
frappe.throw(
_("Row #{0}: Cumulative threshold cannot be less than Single Transaction threshold").format(
d.idx
)
_(
"Row #{0}: Cumulative threshold cannot be less than Single Transaction threshold"
).format(d.idx)
)
@@ -319,9 +317,7 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N
def get_invoice_vouchers(parties, tax_details, company, party_type="Supplier"):
doctype = "Purchase Invoice" if party_type == "Supplier" else "Sales Invoice"
field = (
"base_tax_withholding_net_total as base_net_total"
if party_type == "Supplier"
else "base_net_total"
"base_tax_withholding_net_total as base_net_total" if party_type == "Supplier" else "base_net_total"
)
voucher_wise_amount = {}
vouchers = []
@@ -375,9 +371,7 @@ def get_invoice_vouchers(parties, tax_details, company, party_type="Supplier"):
return vouchers, voucher_wise_amount
def get_advance_vouchers(
parties, company=None, from_date=None, to_date=None, party_type="Supplier"
):
def get_advance_vouchers(parties, company=None, from_date=None, to_date=None, party_type="Supplier"):
"""
Use Payment Ledger to fetch unallocated Advance Payments
"""
@@ -398,9 +392,7 @@ def get_advance_vouchers(
if from_date and to_date:
conditions.append(ple.posting_date[from_date:to_date])
advances = (
qb.from_(ple).select(ple.voucher_no).distinct().where(Criterion.all(conditions)).run(as_list=1)
)
advances = qb.from_(ple).select(ple.voucher_no).distinct().where(Criterion.all(conditions)).run(as_list=1)
if advances:
advances = [x[0] for x in advances]
@@ -566,9 +558,7 @@ def get_tcs_amount(parties, inv, tax_details, vouchers, adv_vouchers):
conditions.append(ple.voucher_no == ple.against_voucher_no)
conditions.append(ple.company == inv.company)
advances = (
qb.from_(ple).select(Abs(Sum(ple.amount))).where(Criterion.all(conditions)).run(as_list=1)
)
qb.from_(ple).select(Abs(Sum(ple.amount))).where(Criterion.all(conditions)).run(as_list=1)
advance_amt = (
qb.from_(ple).select(Abs(Sum(ple.amount))).where(Criterion.all(conditions)).run()[0][0] or 0.0
@@ -627,9 +617,7 @@ def get_limit_consumed(ldc, parties):
return limit_consumed
def get_lower_deduction_amount(
current_amount, limit_consumed, certificate_limit, rate, tax_details
):
def get_lower_deduction_amount(current_amount, limit_consumed, certificate_limit, rate, tax_details):
if certificate_limit - flt(limit_consumed) - flt(current_amount) >= 0:
return current_amount * rate / 100
else:
@@ -641,9 +629,7 @@ def get_lower_deduction_amount(
def is_valid_certificate(ldc, posting_date, limit_consumed):
available_amount = flt(ldc.certificate_limit) - flt(limit_consumed)
if (
getdate(ldc.valid_from) <= getdate(posting_date) <= getdate(ldc.valid_upto)
) and available_amount > 0:
if (getdate(ldc.valid_from) <= getdate(posting_date) <= getdate(ldc.valid_upto)) and available_amount > 0:
return True
return False

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