mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-25 21:05:19 +00:00
Merge branch 'develop' into version-15-beta
This commit is contained in:
@@ -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": []
|
||||
}
|
||||
@@ -89,7 +89,7 @@
|
||||
"label": "Entry Type",
|
||||
"oldfieldname": "voucher_type",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Journal Entry\nInter Company Journal Entry\nBank Entry\nCash Entry\nCredit Card Entry\nDebit Note\nCredit Note\nContra Entry\nExcise Entry\nWrite Off Entry\nOpening Entry\nDepreciation Entry\nExchange Rate Revaluation\nExchange Gain Or Loss\nDeferred Revenue\nDeferred Expense\nReversal Of ITC",
|
||||
"options": "Journal Entry\nInter Company Journal Entry\nBank Entry\nCash Entry\nCredit Card Entry\nDebit Note\nCredit Note\nContra Entry\nExcise Entry\nWrite Off Entry\nOpening Entry\nDepreciation Entry\nExchange Rate Revaluation\nExchange Gain Or Loss\nDeferred Revenue\nDeferred Expense",
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
@@ -555,7 +555,45 @@
|
||||
"name": "Journal Entry",
|
||||
"naming_rule": "By \"Naming Series\" field",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"import": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Auditor"
|
||||
}
|
||||
],
|
||||
"search_fields": "voucher_type,posting_date, due_date, cheque_no",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
|
||||
@@ -230,84 +230,88 @@ class PaymentEntry(AccountsController):
|
||||
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 @@ def get_outstanding_reference_documents(args, validate=False):
|
||||
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(
|
||||
|
||||
@@ -185,6 +185,7 @@ function refresh_payments(d, frm) {
|
||||
}
|
||||
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", {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -8,9 +8,11 @@ import frappe
|
||||
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 @@ class TestPOSClosingEntry(unittest.TestCase):
|
||||
|
||||
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 @@ def init_user_and_profile(**args):
|
||||
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
|
||||
|
||||
@@ -542,6 +542,7 @@ def get_stock_availability(item_code, warehouse):
|
||||
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 +596,6 @@ def get_pos_reserved_qty(item_code, warehouse):
|
||||
.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)
|
||||
|
||||
@@ -95,7 +95,6 @@ class POSInvoiceMergeLog(Document):
|
||||
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 @@ class POSInvoiceMergeLog(Document):
|
||||
|
||||
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 @@ class POSInvoiceMergeLog(Document):
|
||||
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 @@ def split_invoices(invoices):
|
||||
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:
|
||||
|
||||
@@ -100,11 +100,14 @@ def get_party_tax_withholding_details(inv, tax_withholding_category=None):
|
||||
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
|
||||
|
||||
@@ -744,13 +744,18 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters, d):
|
||||
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
|
||||
|
||||
|
||||
@@ -188,6 +188,11 @@ frappe.query_reports["General Ledger"] = {
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -182,12 +182,18 @@ def get_gl_entries(filters, accounting_dimensions):
|
||||
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 @@ def get_gl_entries(filters, accounting_dimensions):
|
||||
{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 @@ def get_columns(filters):
|
||||
"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"),
|
||||
|
||||
@@ -908,6 +908,7 @@ def get_outstanding_invoices(
|
||||
min_outstanding=None,
|
||||
max_outstanding=None,
|
||||
accounting_dimensions=None,
|
||||
vouchers=None,
|
||||
):
|
||||
|
||||
ple = qb.DocType("Payment Ledger Entry")
|
||||
@@ -933,6 +934,7 @@ def get_outstanding_invoices(
|
||||
|
||||
ple_query = QueryPaymentLedger()
|
||||
invoice_list = ple_query.get_voucher_outstandings(
|
||||
vouchers=vouchers,
|
||||
common_filter=common_filter,
|
||||
posting_date=posting_date,
|
||||
min_outstanding=min_outstanding,
|
||||
|
||||
@@ -33,6 +33,7 @@ frappe.ui.form.on('Asset Category', {
|
||||
var d = locals[cdt][cdn];
|
||||
return {
|
||||
"filters": {
|
||||
"account_type": "Depreciation",
|
||||
"root_type": ["in", ["Expense", "Income"]],
|
||||
"is_group": 0,
|
||||
"company": d.company_name
|
||||
|
||||
@@ -53,7 +53,7 @@ class AssetCategory(Document):
|
||||
account_type_map = {
|
||||
"fixed_asset_account": {"account_type": ["Fixed Asset"]},
|
||||
"accumulated_depreciation_account": {"account_type": ["Accumulated Depreciation"]},
|
||||
"depreciation_expense_account": {"root_type": ["Expense", "Income"]},
|
||||
"depreciation_expense_account": {"account_type": ["Depreciation"]},
|
||||
"capital_work_in_progress_account": {"account_type": ["Capital Work in Progress"]},
|
||||
}
|
||||
for d in self.accounts:
|
||||
|
||||
@@ -193,7 +193,7 @@ class RequestforQuotation(BuyingController):
|
||||
"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,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -716,7 +716,9 @@ class AccountsController(TransactionBase):
|
||||
|
||||
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 @@ class AccountsController(TransactionBase):
|
||||
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:
|
||||
|
||||
@@ -57,7 +57,8 @@ erpnext.stock.StockController = class StockController extends frappe.ui.form.Con
|
||||
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 @@ erpnext.stock.StockController = class StockController extends frappe.ui.form.Con
|
||||
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"));
|
||||
|
||||
@@ -225,6 +225,7 @@ erpnext.PointOfSale.Controller = class {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 @@ def get_reserved_serial_nos_for_pos(kwargs):
|
||||
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 @@ def get_reserved_serial_nos_for_pos(kwargs):
|
||||
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 @@ def get_reserved_serial_nos_for_pos(kwargs):
|
||||
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):
|
||||
|
||||
Reference in New Issue
Block a user