Merge pull request #36666 from batonac/batonac-plaid-fixes
fix: Plaid Integration status and categories
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.json b/erpnext/accounts/doctype/gl_entry/gl_entry.json
index e6d97a1..5063ec6 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.json
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.json
@@ -32,7 +32,11 @@
"finance_book",
"to_rename",
"due_date",
- "is_cancelled"
+ "is_cancelled",
+ "transaction_currency",
+ "debit_in_transaction_currency",
+ "credit_in_transaction_currency",
+ "transaction_exchange_rate"
],
"fields": [
{
@@ -253,15 +257,40 @@
"fieldname": "is_cancelled",
"fieldtype": "Check",
"label": "Is Cancelled"
+ },
+ {
+ "fieldname": "transaction_currency",
+ "fieldtype": "Link",
+ "label": "Transaction Currency",
+ "options": "Currency"
+ },
+ {
+ "fieldname": "transaction_exchange_rate",
+ "fieldtype": "Float",
+ "label": "Transaction Exchange Rate"
+ },
+ {
+ "fieldname": "debit_in_transaction_currency",
+ "fieldtype": "Currency",
+ "label": "Debit Amount in Transaction Currency",
+ "options": "transaction_currency"
+ },
+ {
+ "fieldname": "credit_in_transaction_currency",
+ "fieldtype": "Currency",
+ "label": "Credit Amount in Transaction Currency",
+ "options": "transaction_currency"
}
],
"icon": "fa fa-list",
"idx": 1,
"in_create": 1,
- "modified": "2020-04-07 16:22:33.766994",
+ "links": [],
+ "modified": "2023-08-16 21:38:44.072267",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GL Entry",
+ "naming_rule": "Expression (old style)",
"owner": "Administrator",
"permissions": [
{
@@ -290,5 +319,6 @@
"quick_entry": 1,
"search_fields": "voucher_no,account,posting_date,against_voucher",
"sort_field": "modified",
- "sort_order": "DESC"
+ "sort_order": "DESC",
+ "states": []
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index c6576f7..ac31e8a 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -230,84 +230,88 @@
return False
def validate_allocated_amount_with_latest_data(self):
- latest_references = get_outstanding_reference_documents(
- {
- "posting_date": self.posting_date,
- "company": self.company,
- "party_type": self.party_type,
- "payment_type": self.payment_type,
- "party": self.party,
- "party_account": self.paid_from if self.payment_type == "Receive" else self.paid_to,
- "get_outstanding_invoices": True,
- "get_orders_to_be_billed": True,
- },
- validate=True,
- )
+ if self.references:
+ uniq_vouchers = set([(x.reference_doctype, x.reference_name) for x in self.references])
+ vouchers = [frappe._dict({"voucher_type": x[0], "voucher_no": x[1]}) for x in uniq_vouchers]
+ latest_references = get_outstanding_reference_documents(
+ {
+ "posting_date": self.posting_date,
+ "company": self.company,
+ "party_type": self.party_type,
+ "payment_type": self.payment_type,
+ "party": self.party,
+ "party_account": self.paid_from if self.payment_type == "Receive" else self.paid_to,
+ "get_outstanding_invoices": True,
+ "get_orders_to_be_billed": True,
+ "vouchers": vouchers,
+ },
+ validate=True,
+ )
- # Group latest_references by (voucher_type, voucher_no)
- latest_lookup = {}
- for d in latest_references:
- d = frappe._dict(d)
- latest_lookup.setdefault((d.voucher_type, d.voucher_no), frappe._dict())[d.payment_term] = d
+ # Group latest_references by (voucher_type, voucher_no)
+ latest_lookup = {}
+ for d in latest_references:
+ d = frappe._dict(d)
+ latest_lookup.setdefault((d.voucher_type, d.voucher_no), frappe._dict())[d.payment_term] = d
- for idx, d in enumerate(self.get("references"), start=1):
- latest = latest_lookup.get((d.reference_doctype, d.reference_name)) or frappe._dict()
+ for idx, d in enumerate(self.get("references"), start=1):
+ latest = latest_lookup.get((d.reference_doctype, d.reference_name)) or frappe._dict()
- # 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
- ):
- frappe.throw(
- _(
- "{0} has Payment Term based allocation enabled. Select a Payment Term for Row #{1} in Payment References section"
- ).format(frappe.bold(d.reference_name), frappe.bold(idx))
- )
-
- # if no payment template is used by invoice and has a custom term(no `payment_term`), then invoice outstanding will be in 'None' key
- latest = latest.get(d.payment_term) or latest.get(None)
-
- # 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)
- )
- # The reference has already been partly paid
- elif latest.outstanding_amount < latest.invoice_amount and flt(
- d.outstanding_amount, d.precision("outstanding_amount")
- ) != flt(latest.outstanding_amount, d.precision("outstanding_amount")):
- frappe.throw(
- _(
- "{0} {1} has already been partly paid. Please use the 'Get Outstanding Invoice' or the 'Get Outstanding Orders' button to get the latest outstanding amounts."
- ).format(_(d.reference_doctype), d.reference_name)
- )
-
- fail_message = _("Row #{0}: Allocated Amount cannot be greater than outstanding amount.")
-
- if (
- d.payment_term
- and (
- (flt(d.allocated_amount)) > 0
- 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)
- ):
- 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
+ # 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
+ ):
+ frappe.throw(
+ _(
+ "{0} has Payment Term based allocation enabled. Select a Payment Term for Row #{1} in Payment References section"
+ ).format(frappe.bold(d.reference_name), frappe.bold(idx))
)
- )
- if (flt(d.allocated_amount)) > 0 and flt(d.allocated_amount) > flt(latest.outstanding_amount):
- frappe.throw(fail_message.format(d.idx))
+ # if no payment template is used by invoice and has a custom term(no `payment_term`), then invoice outstanding will be in 'None' key
+ latest = latest.get(d.payment_term) or latest.get(None)
- # Check for negative outstanding invoices as well
- if flt(d.allocated_amount) < 0 and flt(d.allocated_amount) < flt(latest.outstanding_amount):
- frappe.throw(fail_message.format(d.idx))
+ # 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)
+ )
+ # The reference has already been partly paid
+ elif latest.outstanding_amount < latest.invoice_amount and flt(
+ d.outstanding_amount, d.precision("outstanding_amount")
+ ) != flt(latest.outstanding_amount, d.precision("outstanding_amount")):
+ frappe.throw(
+ _(
+ "{0} {1} has already been partly paid. Please use the 'Get Outstanding Invoice' or the 'Get Outstanding Orders' button to get the latest outstanding amounts."
+ ).format(_(d.reference_doctype), d.reference_name)
+ )
+
+ fail_message = _("Row #{0}: Allocated Amount cannot be greater than outstanding amount.")
+
+ if (
+ d.payment_term
+ and (
+ (flt(d.allocated_amount)) > 0
+ 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)
+ ):
+ 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
+ )
+ )
+
+ if (flt(d.allocated_amount)) > 0 and flt(d.allocated_amount) > flt(latest.outstanding_amount):
+ frappe.throw(fail_message.format(d.idx))
+
+ # Check for negative outstanding invoices as well
+ if flt(d.allocated_amount) < 0 and flt(d.allocated_amount) < flt(latest.outstanding_amount):
+ frappe.throw(fail_message.format(d.idx))
def delink_advance_entry_references(self):
for reference in self.references:
@@ -1587,6 +1591,7 @@
min_outstanding=args.get("outstanding_amt_greater_than"),
max_outstanding=args.get("outstanding_amt_less_than"),
accounting_dimensions=accounting_dimensions_filter,
+ vouchers=args.get("vouchers") or None,
)
outstanding_invoices = split_invoices_based_on_payment_terms(
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
index 91e71e9..faceaf3 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
@@ -185,6 +185,7 @@
}
if (payment) {
payment.expected_amount += flt(p.amount);
+ payment.closing_amount = payment.expected_amount;
payment.difference = payment.closing_amount - payment.expected_amount;
} else {
frm.add_child("payment_reconciliation", {
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json
index 9d15e6c..a98a24c 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json
@@ -221,6 +221,7 @@
"read_only": 1
},
{
+ "default": "Now",
"fieldname": "posting_time",
"fieldtype": "Time",
"label": "Posting Time",
@@ -235,7 +236,7 @@
"link_fieldname": "pos_closing_entry"
}
],
- "modified": "2022-08-01 11:37:14.991228",
+ "modified": "2023-08-10 16:25:49.322697",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Closing Entry",
diff --git a/erpnext/accounts/doctype/pos_closing_entry/test_pos_closing_entry.py b/erpnext/accounts/doctype/pos_closing_entry/test_pos_closing_entry.py
index 1deb3c5..93ba90a 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/test_pos_closing_entry.py
+++ b/erpnext/accounts/doctype/pos_closing_entry/test_pos_closing_entry.py
@@ -8,9 +8,11 @@
from erpnext.accounts.doctype.pos_closing_entry.pos_closing_entry import (
make_closing_entry_from_opening,
)
+from erpnext.accounts.doctype.pos_invoice.pos_invoice import make_sales_return
from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_invoice
from erpnext.accounts.doctype.pos_opening_entry.test_pos_opening_entry import create_opening_entry
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
+from erpnext.selling.page.point_of_sale.point_of_sale import get_items
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
@@ -67,6 +69,36 @@
self.assertTrue(pcv_doc.name)
+ def test_pos_qty_for_item(self):
+ """
+ Test if quantity is calculated correctly for an item in POS Closing Entry
+ """
+ test_user, pos_profile = init_user_and_profile()
+ opening_entry = create_opening_entry(pos_profile, test_user.name)
+
+ test_item_qty = get_test_item_qty(pos_profile)
+
+ pos_inv1 = create_pos_invoice(rate=3500, do_not_submit=1)
+ pos_inv1.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3500})
+ pos_inv1.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.submit()
+
+ # make return entry of pos_inv2
+ pos_return = make_sales_return(pos_inv2.name)
+ pos_return.paid_amount = pos_return.grand_total
+ pos_return.save()
+ pos_return.submit()
+
+ pcv_doc = make_closing_entry_from_opening(opening_entry)
+ pcv_doc.submit()
+
+ opening_entry = create_opening_entry(pos_profile, test_user.name)
+ test_item_qty_after_sales = get_test_item_qty(pos_profile)
+ self.assertEqual(test_item_qty_after_sales, test_item_qty - 1)
+
def test_cancelling_of_pos_closing_entry(self):
test_user, pos_profile = init_user_and_profile()
opening_entry = create_opening_entry(pos_profile, test_user.name)
@@ -123,3 +155,19 @@
pos_profile.save()
return test_user, pos_profile
+
+
+def get_test_item_qty(pos_profile):
+ test_item_pos = get_items(
+ start=0,
+ page_length=5,
+ price_list="Standard Selling",
+ pos_profile=pos_profile.name,
+ search_term="_Test Item",
+ 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")
+ return test_item_qty
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
index 6f0b801..ae132eb 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
@@ -131,6 +131,7 @@
args: { "pos_profile": frm.pos_profile },
callback: ({ message: profile }) => {
this.update_customer_groups_settings(profile?.customer_groups);
+ this.frm.set_value("company", profile?.company);
},
});
}
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
index 4b2fcec..842f159 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
@@ -49,6 +49,7 @@
self.validate_pos()
self.validate_payment_amount()
self.validate_loyalty_transaction()
+ self.validate_company_with_pos_company()
if self.coupon_code:
from erpnext.accounts.doctype.pricing_rule.utils import validate_coupon_code
@@ -281,6 +282,14 @@
if total_amount_in_payments and total_amount_in_payments < invoice_total:
frappe.throw(_("Total payments amount can't be greater than {}").format(-invoice_total))
+ def validate_company_with_pos_company(self):
+ if self.company != frappe.db.get_value("POS Profile", self.pos_profile, "company"):
+ frappe.throw(
+ _("Company {} does not match with POS Profile Company {}").format(
+ self.company, frappe.db.get_value("POS Profile", self.pos_profile, "company")
+ )
+ )
+
def validate_loyalty_transaction(self):
if self.redeem_loyalty_points and (
not self.loyalty_redemption_account or not self.loyalty_redemption_cost_center
@@ -359,6 +368,7 @@
profile = {}
if self.pos_profile:
profile = frappe.get_doc("POS Profile", self.pos_profile)
+ self.company = profile.get("company")
if not self.get("payments") and not for_validate:
update_multi_mode_option(self, profile)
@@ -542,6 +552,7 @@
is_stock_item = True
bin_qty = get_bin_qty(item_code, warehouse)
pos_sales_qty = get_pos_reserved_qty(item_code, warehouse)
+
return bin_qty - pos_sales_qty, is_stock_item
else:
is_stock_item = True
@@ -595,7 +606,6 @@
.where(
(p_inv.name == p_item.parent)
& (IfNull(p_inv.consolidated_invoice, "") == "")
- & (p_inv.is_return == 0)
& (p_item.docstatus == 1)
& (p_item.item_code == item_code)
& (p_item.warehouse == warehouse)
diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
index d8cbcc1..b587ce6 100644
--- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
+++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
@@ -95,7 +95,6 @@
sales_invoice = self.process_merging_into_sales_invoice(sales)
self.save() # save consolidated_sales_invoice & consolidated_credit_note ref in merge log
-
self.update_pos_invoices(pos_invoice_docs, sales_invoice, credit_note)
def on_cancel(self):
@@ -108,7 +107,6 @@
def process_merging_into_sales_invoice(self, data):
sales_invoice = self.get_new_sales_invoice()
-
sales_invoice = self.merge_pos_invoice_into(sales_invoice, data)
sales_invoice.is_consolidated = 1
@@ -165,8 +163,7 @@
for i in items:
if (
i.item_code == item.item_code
- and not i.serial_no
- and not i.batch_no
+ and not i.serial_and_batch_bundle
and i.uom == item.uom
and i.net_rate == item.net_rate
and i.warehouse == item.warehouse
@@ -385,6 +382,7 @@
for d in invoices
if d.is_return and d.return_against
]
+
for pos_invoice in pos_return_docs:
for item in pos_invoice.items:
if not item.serial_no and not item.serial_and_batch_bundle:
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index d17ca08..954b4e7 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -100,11 +100,14 @@
tax_details = get_tax_withholding_details(tax_withholding_category, posting_date, inv.company)
if not tax_details:
- frappe.throw(
- _("Please set associated account in Tax Withholding Category {0} against Company {1}").format(
- tax_withholding_category, inv.company
- )
+ frappe.msgprint(
+ _(
+ "Skipping Tax Withholding Category {0} as there is no associated account set for Company {1} in it."
+ ).format(tax_withholding_category, inv.company)
)
+ if inv.doctype == "Purchase Invoice":
+ return {}, [], {}
+ return {}
if party_type == "Customer" and not tax_details.cumulative_threshold:
# TCS is only chargeable on sum of invoiced value
diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
index 080e45a..0051ba6 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
@@ -744,13 +744,18 @@
if from_date:
additional_conditions.append(gle.posting_date >= from_date)
- finance_book = filters.get("finance_book")
- company_fb = frappe.get_cached_value("Company", d.name, "default_finance_book")
+ finance_books = []
+ finance_books.append("")
+ if filter_fb := filters.get("finance_book"):
+ finance_books.append(filter_fb)
if filters.get("include_default_book_entries"):
- additional_conditions.append((gle.finance_book.isin([finance_book, company_fb, "", None])))
+ if company_fb := frappe.get_cached_value("Company", d.name, "default_finance_book"):
+ finance_books.append(company_fb)
+
+ additional_conditions.append((gle.finance_book.isin(finance_books)) | gle.finance_book.isnull())
else:
- additional_conditions.append((gle.finance_book.isin([finance_book, "", None])))
+ additional_conditions.append((gle.finance_book.isin(finance_books)) | gle.finance_book.isnull())
return additional_conditions
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index 57a9091..37d0659 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -188,6 +188,11 @@
"fieldname": "show_net_values_in_party_account",
"label": __("Show Net Values in Party Account"),
"fieldtype": "Check"
+ },
+ {
+ "fieldname": "add_values_in_transaction_currency",
+ "label": __("Add Columns in Transaction Currency"),
+ "fieldtype": "Check"
}
]
}
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index d7af167..e05a4e7 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -182,12 +182,18 @@
if accounting_dimensions:
dimension_fields = ", ".join(accounting_dimensions) + ","
+ transaction_currency_fields = ""
+ if filters.get("add_values_in_transaction_currency"):
+ transaction_currency_fields = (
+ "debit_in_transaction_currency, credit_in_transaction_currency, transaction_currency,"
+ )
+
gl_entries = frappe.db.sql(
"""
select
name as gl_entry, posting_date, account, party_type, party,
voucher_type, voucher_no, {dimension_fields}
- cost_center, project,
+ cost_center, project, {transaction_currency_fields}
against_voucher_type, against_voucher, account_currency,
remarks, against, is_opening, creation {select_fields}
from `tabGL Entry`
@@ -195,6 +201,7 @@
{order_by_statement}
""".format(
dimension_fields=dimension_fields,
+ transaction_currency_fields=transaction_currency_fields,
select_fields=select_fields,
conditions=get_conditions(filters),
order_by_statement=order_by_statement,
@@ -562,6 +569,34 @@
"fieldtype": "Float",
"width": 130,
},
+ ]
+
+ if filters.get("add_values_in_transaction_currency"):
+ columns += [
+ {
+ "label": _("Debit (Transaction)"),
+ "fieldname": "debit_in_transaction_currency",
+ "fieldtype": "Currency",
+ "width": 130,
+ "options": "transaction_currency",
+ },
+ {
+ "label": _("Credit (Transaction)"),
+ "fieldname": "credit_in_transaction_currency",
+ "fieldtype": "Currency",
+ "width": 130,
+ "options": "transaction_currency",
+ },
+ {
+ "label": "Transaction Currency",
+ "fieldname": "transaction_currency",
+ "fieldtype": "Link",
+ "options": "Currency",
+ "width": 70,
+ },
+ ]
+
+ columns += [
{"label": _("Voucher Type"), "fieldname": "voucher_type", "width": 120},
{
"label": _("Voucher No"),
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index c24442e..bccf6f1 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -908,6 +908,7 @@
min_outstanding=None,
max_outstanding=None,
accounting_dimensions=None,
+ vouchers=None,
):
ple = qb.DocType("Payment Ledger Entry")
@@ -933,6 +934,7 @@
ple_query = QueryPaymentLedger()
invoice_list = ple_query.get_voucher_outstandings(
+ vouchers=vouchers,
common_filter=common_filter,
posting_date=posting_date,
min_outstanding=min_outstanding,
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
index e938577..56840c1 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
@@ -193,7 +193,7 @@
"supplier": data.get("supplier"),
"supplier_name": data.get("supplier_name"),
"update_password_link": f'<a href="{update_password_link}" class="btn btn-default btn-xs" target="_blank">{_("Set Password")}</a>',
- "portal_link": f'<a href="{rfq_link}" class="btn btn-default btn-sm" target="_blank"> {_("Submit your Quotation")} </a>',
+ "portal_link": f'<a href="{rfq_link}" class="btn btn-default btn-xs" target="_blank"> {_("Submit your Quotation")} </a>',
"user_fullname": full_name,
}
)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index fbf97aa..340ec01 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -716,7 +716,9 @@
def validate_enabled_taxes_and_charges(self):
taxes_and_charges_doctype = self.meta.get_options("taxes_and_charges")
- if frappe.get_cached_value(taxes_and_charges_doctype, self.taxes_and_charges, "disabled"):
+ if self.taxes_and_charges and frappe.get_cached_value(
+ taxes_and_charges_doctype, self.taxes_and_charges, "disabled"
+ ):
frappe.throw(
_("{0} '{1}' is disabled").format(taxes_and_charges_doctype, self.taxes_and_charges)
)
@@ -803,8 +805,28 @@
gl_dict, account_currency, self.get("conversion_rate"), self.company_currency
)
+ # Update details in transaction currency
+ gl_dict.update(
+ {
+ "transaction_currency": self.get("currency") or self.company_currency,
+ "transaction_exchange_rate": self.get("conversion_rate", 1),
+ "debit_in_transaction_currency": self.get_value_in_transaction_currency(
+ account_currency, args, "debit"
+ ),
+ "credit_in_transaction_currency": self.get_value_in_transaction_currency(
+ account_currency, args, "credit"
+ ),
+ }
+ )
+
return gl_dict
+ def get_value_in_transaction_currency(self, account_currency, args, field):
+ if account_currency == self.get("currency"):
+ return args.get(field + "_in_account_currency")
+ else:
+ return flt(args.get(field, 0) / self.get("conversion_rate", 1))
+
def validate_qty_is_not_zero(self):
if self.doctype != "Purchase Receipt":
for item in self.items:
diff --git a/erpnext/public/js/controllers/stock_controller.js b/erpnext/public/js/controllers/stock_controller.js
index 720423b..e9c409e 100644
--- a/erpnext/public/js/controllers/stock_controller.js
+++ b/erpnext/public/js/controllers/stock_controller.js
@@ -57,7 +57,8 @@
from_date: me.frm.doc.posting_date,
to_date: moment(me.frm.doc.modified).format('YYYY-MM-DD'),
company: me.frm.doc.company,
- show_cancelled_entries: me.frm.doc.docstatus === 2
+ show_cancelled_entries: me.frm.doc.docstatus === 2,
+ ignore_prepared_report: true
};
frappe.set_route("query-report", "Stock Ledger");
}, __("View"));
@@ -75,7 +76,8 @@
to_date: moment(me.frm.doc.modified).format('YYYY-MM-DD'),
company: me.frm.doc.company,
group_by: "Group by Voucher (Consolidated)",
- show_cancelled_entries: me.frm.doc.docstatus === 2
+ show_cancelled_entries: me.frm.doc.docstatus === 2,
+ ignore_prepared_report: true
};
frappe.set_route("query-report", "General Ledger");
}, __("View"));
diff --git a/erpnext/public/js/utils/demo.js b/erpnext/public/js/utils/demo.js
index b59c476..3ebc5ef 100644
--- a/erpnext/public/js/utils/demo.js
+++ b/erpnext/public/js/utils/demo.js
@@ -11,7 +11,7 @@
function render_clear_demo_button() {
let wait_for_onboaring_tours = setInterval(() => {
- if ($("#driver-page-overlay").length) {
+ if ($("#driver-page-overlay").length || $("#show-dialog").length) {
return;
}
setup_clear_demo_button();
diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js
index 720d142..db6255a 100644
--- a/erpnext/selling/page/point_of_sale/pos_controller.js
+++ b/erpnext/selling/page/point_of_sale/pos_controller.js
@@ -225,6 +225,7 @@
voucher.pos_opening_entry = this.pos_opening;
voucher.period_end_date = frappe.datetime.now_datetime();
voucher.posting_date = frappe.datetime.now_date();
+ voucher.posting_time = frappe.datetime.now_time();
frappe.set_route('Form', 'POS Closing Entry', voucher.name);
}
diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.json b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.json
index 15bd2f0..d46b07a 100644
--- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.json
+++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.json
@@ -115,7 +115,8 @@
"fieldtype": "Dynamic Link",
"label": "Voucher No",
"no_copy": 1,
- "options": "voucher_type"
+ "options": "voucher_type",
+ "search_index": 1
},
{
"default": "0",
@@ -229,7 +230,8 @@
"fieldtype": "Data",
"label": "Voucher Detail No",
"no_copy": 1,
- "read_only": 1
+ "read_only": 1,
+ "search_index": 1
},
{
"allow_bulk_edit": 1,
@@ -248,7 +250,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2023-07-26 12:56:03.072224",
+ "modified": "2023-07-28 12:56:03.072224",
"modified_by": "Administrator",
"module": "Stock",
"name": "Serial and Batch Bundle",
diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py
index 43bd7ac..1f90c5b 100644
--- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py
+++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py
@@ -3,7 +3,7 @@
import collections
import csv
-from collections import defaultdict
+from collections import Counter, defaultdict
from typing import Dict, List
import frappe
@@ -1197,6 +1197,7 @@
filters=[
["POS Invoice", "consolidated_invoice", "is", "not set"],
["POS Invoice", "docstatus", "=", 1],
+ ["POS Invoice", "is_return", "=", 0],
["POS Invoice Item", "item_code", "=", kwargs.item_code],
["POS Invoice", "name", "!=", kwargs.ignore_voucher_no],
],
@@ -1214,7 +1215,6 @@
for d in get_serial_batch_ledgers(kwargs.item_code, docstatus=1, name=ids):
ignore_serial_nos.append(d.serial_no)
- # Will be deprecated in v16
returned_serial_nos = []
for pos_invoice in pos_invoices:
if pos_invoice.serial_no:
@@ -1242,8 +1242,13 @@
child_doc, parent_doc, ignore_voucher_detail_no=kwargs.get("ignore_voucher_detail_no")
)
)
+ # Counter is used to create a hashmap of serial nos, which contains count of each serial no
+ # so we subtract returned serial nos from ignore serial nos after creating a counter of each to get the items which we need to ignore(which are sold)
- return list(set(ignore_serial_nos) - set(returned_serial_nos))
+ ignore_serial_nos_counter = Counter(ignore_serial_nos)
+ returned_serial_nos_counter = Counter(returned_serial_nos)
+
+ return list(ignore_serial_nos_counter - returned_serial_nos_counter)
def get_reserved_batches_for_pos(kwargs):
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 248b705..258a503 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -647,7 +647,7 @@
def update_distinct_item_warehouses(self, dependant_sle):
key = (dependant_sle.item_code, dependant_sle.warehouse)
- val = frappe._dict({"sle": dependant_sle, "dependent_voucher_detail_nos": []})
+ val = frappe._dict({"sle": dependant_sle})
if key not in self.distinct_item_warehouses:
self.distinct_item_warehouses[key] = val
@@ -661,6 +661,8 @@
if getdate(dependant_sle.posting_date) < getdate(existing_sle_posting_date):
val.sle_changed = True
+ dependent_voucher_detail_nos.append(dependant_sle.voucher_detail_no)
+ val.dependent_voucher_detail_nos = dependent_voucher_detail_nos
self.distinct_item_warehouses[key] = val
self.new_items_found = True
elif dependant_sle.voucher_detail_no not in set(dependent_voucher_detail_nos):