mirror of
https://github.com/frappe/erpnext.git
synced 2026-04-13 03:45:08 +00:00
Merge branch 'version-14-hotfix' into mergify/bp/version-14-hotfix/pr-41659
This commit is contained in:
@@ -33,7 +33,7 @@ class POSClosingEntry(StatusUpdater):
|
||||
for key, value in pos_occurences.items():
|
||||
if len(value) > 1:
|
||||
error_list.append(
|
||||
_(f"{frappe.bold(key)} is added multiple times on rows: {frappe.bold(value)}")
|
||||
_("{0} is added multiple times on rows: {1}").format(frappe.bold(key), frappe.bold(value))
|
||||
)
|
||||
|
||||
if error_list:
|
||||
|
||||
@@ -29,7 +29,7 @@ class POSInvoiceMergeLog(Document):
|
||||
for key, value in pos_occurences.items():
|
||||
if len(value) > 1:
|
||||
error_list.append(
|
||||
_(f"{frappe.bold(key)} is added multiple times on rows: {frappe.bold(value)}")
|
||||
_("{0} is added multiple times on rows: {1}").format(frappe.bold(key), frappe.bold(value))
|
||||
)
|
||||
|
||||
if error_list:
|
||||
|
||||
@@ -284,7 +284,7 @@ class PurchaseInvoice(BuyingController):
|
||||
stock_not_billed_account = self.get_company_default("stock_received_but_not_billed")
|
||||
stock_items = self.get_stock_items()
|
||||
|
||||
asset_received_but_not_billed = None
|
||||
self.asset_received_but_not_billed = None
|
||||
|
||||
if self.update_stock:
|
||||
self.validate_item_code()
|
||||
@@ -367,26 +367,45 @@ class PurchaseInvoice(BuyingController):
|
||||
frappe.msgprint(msg, title=_("Expense Head Changed"))
|
||||
|
||||
item.expense_account = stock_not_billed_account
|
||||
elif item.is_fixed_asset and item.pr_detail:
|
||||
if not asset_received_but_not_billed:
|
||||
asset_received_but_not_billed = self.get_company_default("asset_received_but_not_billed")
|
||||
item.expense_account = asset_received_but_not_billed
|
||||
elif item.is_fixed_asset:
|
||||
account_type = (
|
||||
"capital_work_in_progress_account"
|
||||
if is_cwip_accounting_enabled(item.asset_category)
|
||||
else "fixed_asset_account"
|
||||
)
|
||||
asset_category_account = get_asset_category_account(
|
||||
account_type, item=item.item_code, company=self.company
|
||||
)
|
||||
if not asset_category_account:
|
||||
form_link = get_link_to_form("Asset Category", item.asset_category)
|
||||
throw(
|
||||
_("Please set Fixed Asset Account in {} against {}.").format(form_link, self.company),
|
||||
title=_("Missing Account"),
|
||||
account = None
|
||||
if item.pr_detail:
|
||||
if not self.asset_received_but_not_billed:
|
||||
self.asset_received_but_not_billed = self.get_company_default(
|
||||
"asset_received_but_not_billed"
|
||||
)
|
||||
|
||||
# check if 'Asset Received But Not Billed' account is credited in Purchase receipt or not
|
||||
arbnb_booked_in_pr = frappe.db.get_value(
|
||||
"GL Entry",
|
||||
{
|
||||
"voucher_type": "Purchase Receipt",
|
||||
"voucher_no": item.purchase_receipt,
|
||||
"account": self.asset_received_but_not_billed,
|
||||
},
|
||||
"name",
|
||||
)
|
||||
item.expense_account = asset_category_account
|
||||
if arbnb_booked_in_pr:
|
||||
account = self.asset_received_but_not_billed
|
||||
|
||||
if not account:
|
||||
account_type = (
|
||||
"capital_work_in_progress_account"
|
||||
if is_cwip_accounting_enabled(item.asset_category)
|
||||
else "fixed_asset_account"
|
||||
)
|
||||
account = get_asset_category_account(
|
||||
account_type, item=item.item_code, company=self.company
|
||||
)
|
||||
if not account:
|
||||
form_link = get_link_to_form("Asset Category", item.asset_category)
|
||||
throw(
|
||||
_("Please set Fixed Asset Account in {} against {}.").format(
|
||||
form_link, self.company
|
||||
),
|
||||
title=_("Missing Account"),
|
||||
)
|
||||
item.expense_account = account
|
||||
elif not item.expense_account and for_validate:
|
||||
throw(_("Expense account is mandatory for item {0}").format(item.item_code or item.item_name))
|
||||
|
||||
|
||||
@@ -53,13 +53,15 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2024-05-23 17:00:42.984798",
|
||||
"modified": "2024-06-03 17:30:37.012593",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Repost Accounting Ledger",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
@@ -68,7 +70,9 @@
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"select": 1,
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"in_create": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2023-11-07 14:24:13.321522",
|
||||
"modified": "2024-06-06 13:56:37.908879",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Repost Accounting Ledger Settings",
|
||||
@@ -30,13 +30,17 @@
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"role": "Administrator",
|
||||
"select": 1,
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"read": 1,
|
||||
"role": "System Manager",
|
||||
"select": 1
|
||||
"select": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
|
||||
@@ -98,13 +98,15 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2024-05-23 17:00:31.540640",
|
||||
"modified": "2024-06-03 17:31:04.472279",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Repost Payment Ledger",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
@@ -113,7 +115,9 @@
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"select": 1,
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
|
||||
@@ -2979,10 +2979,8 @@ class TestSalesInvoice(FrappeTestCase):
|
||||
["2021-06-30", 20000.0, 21366.12, True],
|
||||
["2022-06-30", 20000.0, 41366.12, False],
|
||||
["2023-06-30", 20000.0, 61366.12, False],
|
||||
["2024-06-30", 20000.0, 81366.12, False],
|
||||
["2025-06-06", 18633.88, 100000.0, False],
|
||||
["2024-06-06", 38633.88, 100000.0, False],
|
||||
]
|
||||
|
||||
for i, schedule in enumerate(asset.schedules):
|
||||
self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date)
|
||||
self.assertEqual(expected_values[i][1], schedule.depreciation_amount)
|
||||
|
||||
@@ -49,7 +49,6 @@ def get_conditions(filters):
|
||||
|
||||
if filters.account_type:
|
||||
conditions["account_type"] = filters.account_type
|
||||
return conditions
|
||||
|
||||
if filters.company:
|
||||
conditions["company"] = filters.company
|
||||
|
||||
@@ -5,14 +5,15 @@
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import flt
|
||||
from pypika import Order
|
||||
|
||||
import erpnext
|
||||
from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import (
|
||||
add_sub_total_row,
|
||||
add_total_row,
|
||||
apply_group_by_conditions,
|
||||
get_grand_total,
|
||||
get_group_by_and_display_fields,
|
||||
get_group_by_conditions,
|
||||
get_tax_accounts,
|
||||
)
|
||||
from erpnext.accounts.report.utils import get_query_columns, get_values_for_columns
|
||||
@@ -29,7 +30,7 @@ def _execute(filters=None, additional_table_columns=None):
|
||||
|
||||
company_currency = erpnext.get_company_currency(filters.company)
|
||||
|
||||
item_list = get_items(filters, get_query_columns(additional_table_columns))
|
||||
item_list = get_items(filters, additional_table_columns)
|
||||
aii_account_map = get_aii_accounts()
|
||||
if item_list:
|
||||
itemised_tax, tax_columns = get_tax_accounts(
|
||||
@@ -287,59 +288,87 @@ def get_columns(additional_table_columns, filters):
|
||||
return columns
|
||||
|
||||
|
||||
def get_conditions(filters):
|
||||
conditions = ""
|
||||
def apply_conditions(query, pi, pii, filters):
|
||||
for opts in ("company", "supplier", "item_code", "mode_of_payment"):
|
||||
if filters.get(opts):
|
||||
query = query.where(pi[opts] == filters[opts])
|
||||
|
||||
for opts in (
|
||||
("company", " and `tabPurchase Invoice`.company=%(company)s"),
|
||||
("supplier", " and `tabPurchase Invoice`.supplier = %(supplier)s"),
|
||||
("item_code", " and `tabPurchase Invoice Item`.item_code = %(item_code)s"),
|
||||
("from_date", " and `tabPurchase Invoice`.posting_date>=%(from_date)s"),
|
||||
("to_date", " and `tabPurchase Invoice`.posting_date<=%(to_date)s"),
|
||||
("mode_of_payment", " and ifnull(mode_of_payment, '') = %(mode_of_payment)s"),
|
||||
):
|
||||
if filters.get(opts[0]):
|
||||
conditions += opts[1]
|
||||
if filters.get("from_date"):
|
||||
query = query.where(pi.posting_date >= filters.get("from_date"))
|
||||
|
||||
if filters.get("to_date"):
|
||||
query = query.where(pi.posting_date <= filters.get("to_date"))
|
||||
|
||||
if filters.get("item_group"):
|
||||
query = query.where(pii.item_group == filters.get("item_group"))
|
||||
|
||||
if not filters.get("group_by"):
|
||||
conditions += (
|
||||
"ORDER BY `tabPurchase Invoice`.posting_date desc, `tabPurchase Invoice Item`.item_code desc"
|
||||
)
|
||||
query = query.orderby(pi.posting_date, order=Order.desc)
|
||||
query = query.orderby(pii.item_group, order=Order.desc)
|
||||
else:
|
||||
conditions += get_group_by_conditions(filters, "Purchase Invoice")
|
||||
query = apply_group_by_conditions(filters, "Purchase Invoice")
|
||||
|
||||
return conditions
|
||||
return query
|
||||
|
||||
|
||||
def get_items(filters, additional_query_columns):
|
||||
conditions = get_conditions(filters)
|
||||
if additional_query_columns:
|
||||
additional_query_columns = "," + ",".join(additional_query_columns)
|
||||
return frappe.db.sql(
|
||||
"""
|
||||
select
|
||||
`tabPurchase Invoice Item`.`name`, `tabPurchase Invoice Item`.`parent`,
|
||||
`tabPurchase Invoice`.posting_date, `tabPurchase Invoice`.credit_to, `tabPurchase Invoice`.company,
|
||||
`tabPurchase Invoice`.supplier, `tabPurchase Invoice`.remarks, `tabPurchase Invoice`.base_net_total,
|
||||
`tabPurchase Invoice`.unrealized_profit_loss_account,
|
||||
`tabPurchase Invoice Item`.`item_code`, `tabPurchase Invoice Item`.description,
|
||||
`tabPurchase Invoice Item`.`item_name` as pi_item_name, `tabPurchase Invoice Item`.`item_group`
|
||||
,`tabPurchase Invoice Item`.`item_group` as pi_item_group,
|
||||
`tabItem`.`item_name` as i_item_name, `tabItem`.`item_group` as i_item_group,
|
||||
`tabPurchase Invoice Item`.`project`, `tabPurchase Invoice Item`.`purchase_order`,
|
||||
`tabPurchase Invoice Item`.`purchase_receipt`, `tabPurchase Invoice Item`.`po_detail`,
|
||||
`tabPurchase Invoice Item`.`expense_account`, `tabPurchase Invoice Item`.`stock_qty`,
|
||||
`tabPurchase Invoice Item`.`stock_uom`, `tabPurchase Invoice Item`.`base_net_amount`,
|
||||
`tabPurchase Invoice`.`supplier_name`, `tabPurchase Invoice`.`mode_of_payment` {}
|
||||
from `tabPurchase Invoice`, `tabPurchase Invoice Item`, `tabItem`
|
||||
where `tabPurchase Invoice`.name = `tabPurchase Invoice Item`.`parent` and
|
||||
`tabItem`.name = `tabPurchase Invoice Item`.`item_code` and
|
||||
`tabPurchase Invoice`.docstatus = 1 {}
|
||||
""".format(additional_query_columns, conditions),
|
||||
filters,
|
||||
as_dict=1,
|
||||
def get_items(filters, additional_table_columns):
|
||||
pi = frappe.qb.DocType("Purchase Invoice")
|
||||
pii = frappe.qb.DocType("Purchase Invoice Item")
|
||||
Item = frappe.qb.DocType("Item")
|
||||
query = (
|
||||
frappe.qb.from_(pi)
|
||||
.join(pii)
|
||||
.on(pi.name == pii.parent)
|
||||
.left_join(Item)
|
||||
.on(pii.item_code == Item.name)
|
||||
.select(
|
||||
pii.name.as_("pii_name"),
|
||||
pii.parent,
|
||||
pi.posting_date,
|
||||
pi.credit_to,
|
||||
pi.company,
|
||||
pi.supplier,
|
||||
pi.remarks,
|
||||
pi.base_net_total,
|
||||
pi.unrealized_profit_loss_account,
|
||||
pii.item_code,
|
||||
pii.description,
|
||||
pii.item_group,
|
||||
pii.item_name.as_("pi_item_name"),
|
||||
pii.item_group.as_("pi_item_group"),
|
||||
Item.item_name.as_("i_item_name"),
|
||||
Item.item_group.as_("i_item_group"),
|
||||
pii.project,
|
||||
pii.purchase_order,
|
||||
pii.purchase_receipt,
|
||||
pii.po_detail,
|
||||
pii.expense_account,
|
||||
pii.stock_qty,
|
||||
pii.stock_uom,
|
||||
pii.base_net_amount,
|
||||
pi.supplier_name,
|
||||
pi.mode_of_payment,
|
||||
)
|
||||
.where(pi.docstatus == 1)
|
||||
)
|
||||
|
||||
if filters.get("supplier"):
|
||||
query = query.where(pi.supplier == filters["supplier"])
|
||||
if filters.get("company"):
|
||||
query = query.where(pi.company == filters["company"])
|
||||
|
||||
if additional_table_columns:
|
||||
for column in additional_table_columns:
|
||||
if column.get("_doctype"):
|
||||
table = frappe.qb.DocType(column.get("_doctype"))
|
||||
query = query.select(table[column.get("fieldname")])
|
||||
else:
|
||||
query = query.select(pi[column.get("fieldname")])
|
||||
|
||||
query = apply_conditions(query, pi, pii, filters)
|
||||
|
||||
return query.run(as_dict=True)
|
||||
|
||||
|
||||
def get_aii_accounts():
|
||||
return dict(frappe.db.sql("select name, stock_received_but_not_billed from tabCompany"))
|
||||
|
||||
@@ -41,6 +41,12 @@ frappe.query_reports["Item-wise Sales Register"] = {
|
||||
label: __("Warehouse"),
|
||||
fieldtype: "Link",
|
||||
options: "Warehouse",
|
||||
get_query: function () {
|
||||
const company = frappe.query_report.get_filter_value("company");
|
||||
return {
|
||||
filters: { company: company },
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldname: "brand",
|
||||
|
||||
@@ -7,6 +7,7 @@ from frappe import _
|
||||
from frappe.model.meta import get_field_precision
|
||||
from frappe.utils import cstr, flt
|
||||
from frappe.utils.xlsxutils import handle_html
|
||||
from pypika import Order
|
||||
|
||||
from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments
|
||||
from erpnext.accounts.report.utils import get_query_columns, get_values_for_columns
|
||||
@@ -26,7 +27,7 @@ def _execute(filters=None, additional_table_columns=None, additional_conditions=
|
||||
|
||||
company_currency = frappe.get_cached_value("Company", filters.get("company"), "default_currency")
|
||||
|
||||
item_list = get_items(filters, get_query_columns(additional_table_columns), additional_conditions)
|
||||
item_list = get_items(filters, additional_table_columns, additional_conditions)
|
||||
if item_list:
|
||||
itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency)
|
||||
|
||||
@@ -83,9 +84,7 @@ def _execute(filters=None, additional_table_columns=None, additional_conditions=
|
||||
"company": d.company,
|
||||
"sales_order": d.sales_order,
|
||||
"delivery_note": d.delivery_note,
|
||||
"income_account": d.unrealized_profit_loss_account
|
||||
if d.is_internal_customer == 1
|
||||
else d.income_account,
|
||||
"income_account": get_income_account(d),
|
||||
"cost_center": d.cost_center,
|
||||
"stock_qty": d.stock_qty,
|
||||
"stock_uom": d.stock_uom,
|
||||
@@ -150,6 +149,15 @@ def _execute(filters=None, additional_table_columns=None, additional_conditions=
|
||||
return columns, data, None, None, None, skip_total_row
|
||||
|
||||
|
||||
def get_income_account(row):
|
||||
if row.enable_deferred_revenue:
|
||||
return row.deferred_revenue_account
|
||||
elif row.is_internal_customer == 1:
|
||||
return row.unrealized_profit_loss_account
|
||||
else:
|
||||
return row.income_account
|
||||
|
||||
|
||||
def get_columns(additional_table_columns, filters):
|
||||
columns = []
|
||||
|
||||
@@ -333,93 +341,140 @@ def get_columns(additional_table_columns, filters):
|
||||
return columns
|
||||
|
||||
|
||||
def get_conditions(filters, additional_conditions=None):
|
||||
conditions = ""
|
||||
def apply_conditions(query, si, sii, filters, additional_conditions=None):
|
||||
for opts in ("company", "customer", "item_code"):
|
||||
if filters.get(opts):
|
||||
query = query.where(si[opts] == filters[opts])
|
||||
|
||||
for opts in (
|
||||
("company", " and `tabSales Invoice`.company=%(company)s"),
|
||||
("customer", " and `tabSales Invoice`.customer = %(customer)s"),
|
||||
("item_code", " and `tabSales Invoice Item`.item_code = %(item_code)s"),
|
||||
("from_date", " and `tabSales Invoice`.posting_date>=%(from_date)s"),
|
||||
("to_date", " and `tabSales Invoice`.posting_date<=%(to_date)s"),
|
||||
):
|
||||
if filters.get(opts[0]):
|
||||
conditions += opts[1]
|
||||
if filters.get("from_date"):
|
||||
query = query.where(si.posting_date >= filters.get("from_date"))
|
||||
|
||||
if additional_conditions:
|
||||
conditions += additional_conditions
|
||||
if filters.get("to_date"):
|
||||
query = query.where(si.posting_date <= filters.get("to_date"))
|
||||
|
||||
if filters.get("mode_of_payment"):
|
||||
conditions += """ and exists(select name from `tabSales Invoice Payment`
|
||||
where parent=`tabSales Invoice`.name
|
||||
and ifnull(`tabSales Invoice Payment`.mode_of_payment, '') = %(mode_of_payment)s)"""
|
||||
sales_invoice = frappe.db.get_all(
|
||||
"Sales Invoice Payment", {"mode_of_payment": filters.get("mode_of_payment")}, pluck="parent"
|
||||
)
|
||||
query = query.where(si.name.isin(sales_invoice))
|
||||
|
||||
if filters.get("warehouse"):
|
||||
if frappe.db.get_value("Warehouse", filters.get("warehouse"), "is_group"):
|
||||
lft, rgt = frappe.db.get_all(
|
||||
"Warehouse", filters={"name": filters.get("warehouse")}, fields=["lft", "rgt"], as_list=True
|
||||
)[0]
|
||||
conditions += f"and ifnull(`tabSales Invoice Item`.warehouse, '') in (select name from `tabWarehouse` where lft > {lft} and rgt < {rgt}) "
|
||||
warehouses = frappe.db.get_all("Warehouse", {"lft": (">", lft), "rgt": ("<", rgt)}, pluck="name")
|
||||
query = query.where(sii.warehouse.isin(warehouses))
|
||||
else:
|
||||
conditions += """and ifnull(`tabSales Invoice Item`.warehouse, '') = %(warehouse)s"""
|
||||
query = query.where(sii.warehouse == filters.get("warehouse"))
|
||||
|
||||
if filters.get("brand"):
|
||||
conditions += """and ifnull(`tabSales Invoice Item`.brand, '') = %(brand)s"""
|
||||
query = query.where(sii.brand == filters.get("brand"))
|
||||
|
||||
if filters.get("item_group"):
|
||||
conditions += """and ifnull(`tabSales Invoice Item`.item_group, '') = %(item_group)s"""
|
||||
query = query.where(sii.item_group == filters.get("item_group"))
|
||||
|
||||
if filters.get("income_account"):
|
||||
query = query.where(
|
||||
(sii.income_account == filters.get("income_account"))
|
||||
| (sii.deferred_revenue_account == filters.get("income_account"))
|
||||
| (si.unrealized_profit_loss_account == filters.get("income_account"))
|
||||
)
|
||||
|
||||
if not filters.get("group_by"):
|
||||
conditions += "ORDER BY `tabSales Invoice`.posting_date desc, `tabSales Invoice Item`.item_group desc"
|
||||
query = query.orderby(si.posting_date, order=Order.desc)
|
||||
query = query.orderby(sii.item_group, order=Order.desc)
|
||||
else:
|
||||
conditions += get_group_by_conditions(filters, "Sales Invoice")
|
||||
query = apply_group_by_conditions(query, si, sii, filters)
|
||||
|
||||
return conditions
|
||||
for key, value in (additional_conditions or {}).items():
|
||||
query = query.where(si[key] == value)
|
||||
|
||||
return query
|
||||
|
||||
|
||||
def get_group_by_conditions(filters, doctype):
|
||||
def apply_group_by_conditions(query, si, ii, filters):
|
||||
if filters.get("group_by") == "Invoice":
|
||||
return f"ORDER BY `tab{doctype} Item`.parent desc"
|
||||
query = query.orderby(ii.parent, order=Order.desc)
|
||||
elif filters.get("group_by") == "Item":
|
||||
return f"ORDER BY `tab{doctype} Item`.`item_code`"
|
||||
query = query.orderby(ii.item_code)
|
||||
elif filters.get("group_by") == "Item Group":
|
||||
return "ORDER BY `tab{} Item`.{}".format(doctype, frappe.scrub(filters.get("group_by")))
|
||||
query = query.orderby(ii.item_group)
|
||||
elif filters.get("group_by") in ("Customer", "Customer Group", "Territory", "Supplier"):
|
||||
return "ORDER BY `tab{}`.{}".format(doctype, frappe.scrub(filters.get("group_by")))
|
||||
query = query.orderby(si[frappe.scrub(filters.get("group_by"))])
|
||||
|
||||
return query
|
||||
|
||||
|
||||
def get_items(filters, additional_query_columns, additional_conditions=None):
|
||||
conditions = get_conditions(filters, additional_conditions)
|
||||
si = frappe.qb.DocType("Sales Invoice")
|
||||
sii = frappe.qb.DocType("Sales Invoice Item")
|
||||
item = frappe.qb.DocType("Item")
|
||||
|
||||
query = (
|
||||
frappe.qb.from_(si)
|
||||
.join(sii)
|
||||
.on(si.name == sii.parent)
|
||||
.left_join(item)
|
||||
.on(sii.item_code == item.name)
|
||||
.select(
|
||||
sii.name,
|
||||
sii.parent,
|
||||
si.posting_date,
|
||||
si.debit_to,
|
||||
si.unrealized_profit_loss_account,
|
||||
si.is_internal_customer,
|
||||
si.customer,
|
||||
si.remarks,
|
||||
si.territory,
|
||||
si.company,
|
||||
si.base_net_total,
|
||||
sii.project,
|
||||
sii.item_code,
|
||||
sii.description,
|
||||
sii.item_name,
|
||||
sii.item_group,
|
||||
sii.item_name.as_("si_item_name"),
|
||||
sii.item_group.as_("si_item_group"),
|
||||
item.item_name.as_("i_item_name"),
|
||||
item.item_group.as_("i_item_group"),
|
||||
sii.sales_order,
|
||||
sii.delivery_note,
|
||||
sii.income_account,
|
||||
sii.cost_center,
|
||||
sii.enable_deferred_revenue,
|
||||
sii.deferred_revenue_account,
|
||||
sii.stock_qty,
|
||||
sii.stock_uom,
|
||||
sii.base_net_rate,
|
||||
sii.base_net_amount,
|
||||
si.customer_name,
|
||||
si.customer_group,
|
||||
sii.so_detail,
|
||||
si.update_stock,
|
||||
sii.uom,
|
||||
sii.qty,
|
||||
)
|
||||
.where(si.docstatus == 1)
|
||||
)
|
||||
|
||||
if additional_query_columns:
|
||||
additional_query_columns = "," + ",".join(additional_query_columns)
|
||||
return frappe.db.sql(
|
||||
"""
|
||||
select
|
||||
`tabSales Invoice Item`.name, `tabSales Invoice Item`.parent,
|
||||
`tabSales Invoice`.posting_date, `tabSales Invoice`.debit_to,
|
||||
`tabSales Invoice`.unrealized_profit_loss_account,
|
||||
`tabSales Invoice`.is_internal_customer,
|
||||
`tabSales Invoice`.customer, `tabSales Invoice`.remarks,
|
||||
`tabSales Invoice`.territory, `tabSales Invoice`.company, `tabSales Invoice`.base_net_total,
|
||||
`tabSales Invoice Item`.project,
|
||||
`tabSales Invoice Item`.item_code, `tabSales Invoice Item`.description,
|
||||
`tabSales Invoice Item`.`item_name`, `tabSales Invoice Item`.`item_group`,
|
||||
`tabSales Invoice Item`.`item_name` as si_item_name, `tabSales Invoice Item`.`item_group` as si_item_group,
|
||||
`tabItem`.`item_name` as i_item_name, `tabItem`.`item_group` as i_item_group,
|
||||
`tabSales Invoice Item`.sales_order, `tabSales Invoice Item`.delivery_note,
|
||||
`tabSales Invoice Item`.income_account, `tabSales Invoice Item`.cost_center,
|
||||
`tabSales Invoice Item`.stock_qty, `tabSales Invoice Item`.stock_uom,
|
||||
`tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount,
|
||||
`tabSales Invoice`.customer_name, `tabSales Invoice`.customer_group, `tabSales Invoice Item`.so_detail,
|
||||
`tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty {}
|
||||
from `tabSales Invoice`, `tabSales Invoice Item`, `tabItem`
|
||||
where `tabSales Invoice`.name = `tabSales Invoice Item`.parent and
|
||||
`tabItem`.name = `tabSales Invoice Item`.`item_code` and
|
||||
`tabSales Invoice`.docstatus = 1 {}
|
||||
""".format(additional_query_columns, conditions),
|
||||
filters,
|
||||
as_dict=1,
|
||||
) # nosec
|
||||
for column in additional_query_columns:
|
||||
if column.get("_doctype"):
|
||||
table = frappe.qb.DocType(column.get("_doctype"))
|
||||
query = query.select(table[column.get("fieldname")])
|
||||
else:
|
||||
query = query.select(si[column.get("fieldname")])
|
||||
|
||||
if filters.get("customer"):
|
||||
query = query.where(si.customer == filters["customer"])
|
||||
|
||||
if filters.get("customer_group"):
|
||||
query = query.where(si.customer_group == filters["customer_group"])
|
||||
|
||||
query = apply_conditions(query, si, sii, filters, additional_conditions)
|
||||
|
||||
return query.run(as_dict=True)
|
||||
|
||||
|
||||
def get_delivery_notes_against_sales_order(item_list):
|
||||
@@ -427,16 +482,14 @@ def get_delivery_notes_against_sales_order(item_list):
|
||||
so_item_rows = list(set([d.so_detail for d in item_list]))
|
||||
|
||||
if so_item_rows:
|
||||
delivery_notes = frappe.db.sql(
|
||||
"""
|
||||
select parent, so_detail
|
||||
from `tabDelivery Note Item`
|
||||
where docstatus=1 and so_detail in (%s)
|
||||
group by so_detail, parent
|
||||
"""
|
||||
% (", ".join(["%s"] * len(so_item_rows))),
|
||||
tuple(so_item_rows),
|
||||
as_dict=1,
|
||||
dn_item = frappe.qb.DocType("Delivery Note Item")
|
||||
delivery_notes = (
|
||||
frappe.qb.from_(dn_item)
|
||||
.select(dn_item.parent, dn_item.so_detail)
|
||||
.where(dn_item.docstatus == 1)
|
||||
.where(dn_item.so_detail.isin(so_item_rows))
|
||||
.groupby(dn_item.so_detail, dn_item.parent)
|
||||
.run(as_dict=True)
|
||||
)
|
||||
|
||||
for dn in delivery_notes:
|
||||
@@ -446,15 +499,16 @@ def get_delivery_notes_against_sales_order(item_list):
|
||||
|
||||
|
||||
def get_grand_total(filters, doctype):
|
||||
return frappe.db.sql(
|
||||
f""" SELECT
|
||||
SUM(`tab{doctype}`.base_grand_total)
|
||||
FROM `tab{doctype}`
|
||||
WHERE `tab{doctype}`.docstatus = 1
|
||||
and posting_date between %s and %s
|
||||
""",
|
||||
(filters.get("from_date"), filters.get("to_date")),
|
||||
)[0][0] # nosec
|
||||
return flt(
|
||||
frappe.db.get_value(
|
||||
doctype,
|
||||
{
|
||||
"docstatus": 1,
|
||||
"posting_date": ("between", [filters.get("from_date"), filters.get("to_date")]),
|
||||
},
|
||||
"sum(base_grand_total)",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def get_tax_accounts(
|
||||
|
||||
@@ -12,6 +12,7 @@ from frappe.utils import (
|
||||
add_months,
|
||||
add_years,
|
||||
cint,
|
||||
cstr,
|
||||
date_diff,
|
||||
flt,
|
||||
get_datetime,
|
||||
@@ -361,9 +362,11 @@ class Asset(AccountsController):
|
||||
final_number_of_depreciations = cint(finance_book.total_number_of_depreciations) - cint(
|
||||
self.number_of_depreciations_booked
|
||||
)
|
||||
|
||||
has_pro_rata = self.check_is_pro_rata(finance_book)
|
||||
if has_pro_rata:
|
||||
depr_already_booked = any(
|
||||
[d.journal_entry for d in self.get("schedules") if d.finance_book == finance_book.finance_book]
|
||||
)
|
||||
if has_pro_rata and not depr_already_booked:
|
||||
final_number_of_depreciations += 1
|
||||
|
||||
has_wdv_or_dd_non_yearly_pro_rata = False
|
||||
@@ -543,7 +546,7 @@ class Asset(AccountsController):
|
||||
"depreciation_amount": depreciation_amount,
|
||||
"depreciation_method": finance_book.depreciation_method,
|
||||
"finance_book": finance_book.finance_book,
|
||||
"finance_book_id": finance_book.idx,
|
||||
"finance_book_id": cstr(finance_book.idx),
|
||||
"shift": shift,
|
||||
},
|
||||
)
|
||||
@@ -749,7 +752,6 @@ class Asset(AccountsController):
|
||||
):
|
||||
straight_line_idx = []
|
||||
finance_books = []
|
||||
|
||||
for i, d in enumerate(self.get("schedules")):
|
||||
if ignore_booked_entry and d.journal_entry:
|
||||
continue
|
||||
@@ -771,7 +773,10 @@ class Asset(AccountsController):
|
||||
finance_books.append(int(d.finance_book_id))
|
||||
|
||||
depreciation_amount = flt(d.depreciation_amount, d.precision("depreciation_amount"))
|
||||
value_after_depreciation -= flt(depreciation_amount)
|
||||
if not d.journal_entry:
|
||||
value_after_depreciation = flt(
|
||||
flt(value_after_depreciation) - depreciation_amount, d.precision("depreciation_amount")
|
||||
)
|
||||
|
||||
# for the last row, if depreciation method = Straight Line
|
||||
if (
|
||||
@@ -783,10 +788,13 @@ class Asset(AccountsController):
|
||||
book = self.get("finance_books")[cint(d.finance_book_id) - 1]
|
||||
|
||||
if not book.shift_based:
|
||||
depreciation_amount += flt(
|
||||
adjustment_amount = flt(
|
||||
value_after_depreciation - flt(book.expected_value_after_useful_life),
|
||||
d.precision("depreciation_amount"),
|
||||
)
|
||||
depreciation_amount = flt(
|
||||
depreciation_amount + adjustment_amount, d.precision("depreciation_amount")
|
||||
)
|
||||
|
||||
d.depreciation_amount = depreciation_amount
|
||||
accumulated_depreciation += d.depreciation_amount
|
||||
@@ -1433,7 +1441,7 @@ def get_straight_line_or_manual_depr_amount(asset, row, schedule_idx, number_of_
|
||||
# if the Depreciation Schedule is being modified after Asset Repair due to increase in asset value
|
||||
elif asset.flags.increase_in_asset_value_due_to_repair:
|
||||
return (flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)) / flt(
|
||||
row.total_number_of_depreciations
|
||||
number_of_pending_depreciations
|
||||
)
|
||||
# if the Depreciation Schedule is being modified after Asset Value Adjustment due to decrease in asset value
|
||||
elif asset.flags.decrease_in_asset_value_due_to_value_adjustment:
|
||||
|
||||
@@ -1355,9 +1355,9 @@ class TestDepreciationBasics(AssetSetup):
|
||||
|
||||
for schedule in asset.schedules:
|
||||
if schedule.idx <= 3:
|
||||
self.assertEqual(schedule.finance_book_id, 1)
|
||||
self.assertEqual(schedule.finance_book_id, "1")
|
||||
else:
|
||||
self.assertEqual(schedule.finance_book_id, 2)
|
||||
self.assertEqual(schedule.finance_book_id, "2")
|
||||
|
||||
def test_depreciation_entry_cancellation(self):
|
||||
asset = create_asset(
|
||||
|
||||
@@ -103,12 +103,11 @@ class TestAssetValueAdjustment(unittest.TestCase):
|
||||
["2023-05-31", 9983.33, 45408.05],
|
||||
["2023-06-30", 9983.33, 55391.38],
|
||||
["2023-07-31", 9983.33, 65374.71],
|
||||
["2023-08-31", 8300.0, 73674.71],
|
||||
["2023-09-30", 8300.0, 81974.71],
|
||||
["2023-10-31", 8300.0, 90274.71],
|
||||
["2023-11-30", 8300.0, 98574.71],
|
||||
["2023-12-31", 8300.0, 106874.71],
|
||||
["2024-01-15", 8300.0, 115174.71],
|
||||
["2023-08-31", 9960.0, 75334.71],
|
||||
["2023-09-30", 9960.0, 85294.71],
|
||||
["2023-10-31", 9960.0, 95254.71],
|
||||
["2023-11-30", 9960.0, 105214.71],
|
||||
["2023-12-15", 9960.0, 115174.71],
|
||||
]
|
||||
|
||||
schedules = [
|
||||
|
||||
@@ -576,6 +576,11 @@ def get_requested_item_qty(sales_order):
|
||||
def make_material_request(source_name, target_doc=None):
|
||||
requested_item_qty = get_requested_item_qty(source_name)
|
||||
|
||||
def postprocess(source, target):
|
||||
if source.tc_name and frappe.db.get_value("Terms and Conditions", source.tc_name, "buying") != 1:
|
||||
target.tc_name = None
|
||||
target.terms = None
|
||||
|
||||
def get_remaining_qty(so_item):
|
||||
return flt(
|
||||
flt(so_item.qty)
|
||||
@@ -631,6 +636,7 @@ def make_material_request(source_name, target_doc=None):
|
||||
},
|
||||
},
|
||||
target_doc,
|
||||
postprocess,
|
||||
)
|
||||
|
||||
return doc
|
||||
@@ -932,11 +938,19 @@ def make_purchase_order_for_default_supplier(source_name, selected_items=None, t
|
||||
target.discount_amount = 0.0
|
||||
target.inter_company_order_reference = ""
|
||||
target.shipping_rule = ""
|
||||
target.tc_name = ""
|
||||
target.terms = ""
|
||||
target.payment_terms_template = ""
|
||||
target.payment_schedule = []
|
||||
|
||||
default_price_list = frappe.get_value("Supplier", supplier, "default_price_list")
|
||||
if default_price_list:
|
||||
target.buying_price_list = default_price_list
|
||||
|
||||
default_payment_terms = frappe.get_value("Supplier", supplier, "payment_terms")
|
||||
if default_payment_terms:
|
||||
target.payment_terms_template = default_payment_terms
|
||||
|
||||
if any(item.delivered_by_supplier == 1 for item in source.items):
|
||||
if source.shipping_address_name:
|
||||
target.shipping_address = source.shipping_address_name
|
||||
@@ -988,7 +1002,6 @@ def make_purchase_order_for_default_supplier(source_name, selected_items=None, t
|
||||
"contact_person",
|
||||
"taxes_and_charges",
|
||||
"shipping_address",
|
||||
"terms",
|
||||
],
|
||||
"validation": {"docstatus": ["=", 1]},
|
||||
},
|
||||
@@ -1056,6 +1069,10 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None):
|
||||
target.discount_amount = 0.0
|
||||
target.inter_company_order_reference = ""
|
||||
target.shipping_rule = ""
|
||||
target.tc_name = ""
|
||||
target.terms = ""
|
||||
target.payment_terms_template = ""
|
||||
target.payment_schedule = []
|
||||
|
||||
if is_drop_ship_order(target):
|
||||
target.customer = source.customer
|
||||
@@ -1091,7 +1108,6 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None):
|
||||
"contact_person",
|
||||
"taxes_and_charges",
|
||||
"shipping_address",
|
||||
"terms",
|
||||
],
|
||||
"validation": {"docstatus": ["=", 1]},
|
||||
},
|
||||
|
||||
@@ -12,10 +12,11 @@ frappe.ui.form.on("Company", {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
frm.call("check_if_transactions_exist").then((r) => {
|
||||
frm.toggle_enable("default_currency", !r.message);
|
||||
});
|
||||
if (!frm.doc.__islocal) {
|
||||
frm.call("check_if_transactions_exist").then((r) => {
|
||||
frm.toggle_enable("default_currency", !r.message);
|
||||
});
|
||||
}
|
||||
},
|
||||
setup: function (frm) {
|
||||
frm.__rename_queue = "long";
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
"idx": 1,
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"modified": "2023-08-28 17:26:46.826501",
|
||||
"modified": "2024-06-12 16:10:31.451257",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Department",
|
||||
@@ -132,6 +132,10 @@
|
||||
"role": "HR Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Employee",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"show_name_in_global_search": 1,
|
||||
|
||||
Reference in New Issue
Block a user