Merge pull request #35144 from rohitwaghchaure/feat-reserved-qty-for-production-plan-in-bin
feat: reserve qty against production plan raw materials in BIN
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 082128a..3df48e2 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -654,6 +654,28 @@
self.precision("base_received_amount"),
)
+ def calculate_base_allocated_amount_for_reference(self, d) -> float:
+ base_allocated_amount = 0
+ if d.reference_doctype in frappe.get_hooks("advance_payment_doctypes"):
+ # When referencing Sales/Purchase Order, use the source/target exchange rate depending on payment type.
+ # This is so there are no Exchange Gain/Loss generated for such doctypes
+
+ exchange_rate = 1
+ if self.payment_type == "Receive":
+ exchange_rate = self.source_exchange_rate
+ elif self.payment_type == "Pay":
+ exchange_rate = self.target_exchange_rate
+
+ base_allocated_amount += flt(
+ flt(d.allocated_amount) * flt(exchange_rate), self.precision("base_paid_amount")
+ )
+ else:
+ base_allocated_amount += flt(
+ flt(d.allocated_amount) * flt(d.exchange_rate), self.precision("base_paid_amount")
+ )
+
+ return base_allocated_amount
+
def set_total_allocated_amount(self):
if self.payment_type == "Internal Transfer":
return
@@ -662,9 +684,7 @@
for d in self.get("references"):
if d.allocated_amount:
total_allocated_amount += flt(d.allocated_amount)
- base_total_allocated_amount += flt(
- flt(d.allocated_amount) * flt(d.exchange_rate), self.precision("base_paid_amount")
- )
+ base_total_allocated_amount += self.calculate_base_allocated_amount_for_reference(d)
self.total_allocated_amount = abs(total_allocated_amount)
self.base_total_allocated_amount = abs(base_total_allocated_amount)
@@ -881,9 +901,7 @@
}
)
- allocated_amount_in_company_currency = flt(
- flt(d.allocated_amount) * flt(d.exchange_rate), self.precision("paid_amount")
- )
+ allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference(d)
gle.update(
{
@@ -1715,6 +1733,13 @@
# bank or cash
bank = get_bank_cash_account(doc, bank_account)
+ # if default bank or cash account is not set in company master and party has default company bank account, fetch it
+ if party_type in ["Customer", "Supplier"] and not bank:
+ party_bank_account = get_party_bank_account(party_type, doc.get(scrub(party_type)))
+ if party_bank_account:
+ account = frappe.db.get_value("Bank Account", party_bank_account, "account")
+ bank = get_bank_cash_account(doc, account)
+
paid_amount, received_amount = set_paid_amount_and_received_amount(
dt, party_account_currency, bank, outstanding_amount, payment_type, bank_amount, doc
)
@@ -1931,19 +1956,27 @@
paid_amount = received_amount = 0
if party_account_currency == bank.account_currency:
paid_amount = received_amount = abs(outstanding_amount)
- elif payment_type == "Receive":
- paid_amount = abs(outstanding_amount)
- if bank_amount:
- received_amount = bank_amount
- else:
- received_amount = paid_amount * doc.get("conversion_rate", 1)
else:
- received_amount = abs(outstanding_amount)
- if bank_amount:
- paid_amount = bank_amount
+ company_currency = frappe.get_cached_value("Company", doc.get("company"), "default_currency")
+ if payment_type == "Receive":
+ paid_amount = abs(outstanding_amount)
+ if bank_amount:
+ received_amount = bank_amount
+ else:
+ if company_currency != bank.account_currency:
+ received_amount = paid_amount / doc.get("conversion_rate", 1)
+ else:
+ received_amount = paid_amount * doc.get("conversion_rate", 1)
else:
- # if party account currency and bank currency is different then populate paid amount as well
- paid_amount = received_amount * doc.get("conversion_rate", 1)
+ received_amount = abs(outstanding_amount)
+ if bank_amount:
+ paid_amount = bank_amount
+ else:
+ if company_currency != bank.account_currency:
+ paid_amount = received_amount / doc.get("conversion_rate", 1)
+ else:
+ # if party account currency and bank currency is different then populate paid amount as well
+ paid_amount = received_amount * doc.get("conversion_rate", 1)
return paid_amount, received_amount
diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
index 67049c4..68f333d 100644
--- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
@@ -51,6 +51,38 @@
so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid")
self.assertEqual(so_advance_paid, 0)
+ def test_payment_against_sales_order_usd_to_inr(self):
+ so = make_sales_order(
+ customer="_Test Customer USD", currency="USD", qty=1, rate=100, do_not_submit=True
+ )
+ so.conversion_rate = 50
+ so.submit()
+ pe = get_payment_entry("Sales Order", so.name)
+ pe.source_exchange_rate = 55
+ pe.received_amount = 5500
+ pe.insert()
+ pe.submit()
+
+ # there should be no difference amount
+ pe.reload()
+ self.assertEqual(pe.difference_amount, 0)
+ self.assertEqual(pe.deductions, [])
+
+ expected_gle = dict(
+ (d[0], d)
+ for d in [["_Test Receivable USD - _TC", 0, 5500, so.name], ["Cash - _TC", 5500.0, 0, None]]
+ )
+
+ self.validate_gl_entries(pe.name, expected_gle)
+
+ so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid")
+ self.assertEqual(so_advance_paid, 100)
+
+ pe.cancel()
+
+ so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid")
+ self.assertEqual(so_advance_paid, 0)
+
def test_payment_entry_for_blocked_supplier_invoice(self):
supplier = frappe.get_doc("Supplier", "_Test Supplier")
supplier.on_hold = 1
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index b4d369e..f76dfff 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -89,6 +89,7 @@
"column_break8",
"grand_total",
"rounding_adjustment",
+ "use_company_roundoff_cost_center",
"rounded_total",
"in_words",
"total_advance",
@@ -1559,13 +1560,19 @@
"fieldname": "only_include_allocated_payments",
"fieldtype": "Check",
"label": "Only Include Allocated Payments"
+ },
+ {
+ "default": "0",
+ "fieldname": "use_company_roundoff_cost_center",
+ "fieldtype": "Check",
+ "label": "Use Company Default Round Off Cost Center"
}
],
"icon": "fa fa-file-text",
"idx": 204,
"is_submittable": 1,
"links": [],
- "modified": "2023-04-03 22:57:14.074982",
+ "modified": "2023-04-28 12:57:50.832598",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index a617447..868a150 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -978,7 +978,7 @@
def make_precision_loss_gl_entry(self, gl_entries):
round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(
- self.company, "Purchase Invoice", self.name
+ self.company, "Purchase Invoice", self.name, self.use_company_roundoff_cost_center
)
precision_loss = self.get("base_net_total") - flt(
@@ -992,7 +992,9 @@
"account": round_off_account,
"against": self.supplier,
"credit": precision_loss,
- "cost_center": self.cost_center or round_off_cost_center,
+ "cost_center": round_off_cost_center
+ if self.use_company_roundoff_cost_center
+ else self.cost_center or round_off_cost_center,
"remarks": _("Net total calculation precision loss"),
}
)
@@ -1386,7 +1388,7 @@
not self.is_internal_transfer() and self.rounding_adjustment and self.base_rounding_adjustment
):
round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(
- self.company, "Purchase Invoice", self.name
+ self.company, "Purchase Invoice", self.name, self.use_company_roundoff_cost_center
)
gl_entries.append(
@@ -1396,7 +1398,9 @@
"against": self.supplier,
"debit_in_account_currency": self.rounding_adjustment,
"debit": self.base_rounding_adjustment,
- "cost_center": self.cost_center or round_off_cost_center,
+ "cost_center": round_off_cost_center
+ if self.use_company_roundoff_cost_center
+ else (self.cost_center or round_off_cost_center),
},
item=self,
)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index a41e13c..6a65b30 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -79,6 +79,7 @@
"column_break5",
"grand_total",
"rounding_adjustment",
+ "use_company_roundoff_cost_center",
"rounded_total",
"in_words",
"total_advance",
@@ -2135,6 +2136,12 @@
"fieldname": "only_include_allocated_payments",
"fieldtype": "Check",
"label": "Only Include Allocated Payments"
+ },
+ {
+ "default": "0",
+ "fieldname": "use_company_roundoff_cost_center",
+ "fieldtype": "Check",
+ "label": "Use Company default Cost Center for Round off"
}
],
"icon": "fa fa-file-text",
@@ -2147,7 +2154,7 @@
"link_fieldname": "consolidated_invoice"
}
],
- "modified": "2023-04-03 22:55:14.206473",
+ "modified": "2023-04-28 14:15:59.901154",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index db61995..e16b1b1 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -1464,7 +1464,7 @@
and not self.is_internal_transfer()
):
round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(
- self.company, "Sales Invoice", self.name
+ self.company, "Sales Invoice", self.name, self.use_company_roundoff_cost_center
)
gl_entries.append(
@@ -1476,7 +1476,9 @@
self.rounding_adjustment, self.precision("rounding_adjustment")
),
"credit": flt(self.base_rounding_adjustment, self.precision("base_rounding_adjustment")),
- "cost_center": self.cost_center or round_off_cost_center,
+ "cost_center": round_off_cost_center
+ if self.use_company_roundoff_cost_center
+ else (self.cost_center or round_off_cost_center),
},
item=self,
)
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index 6b2546e..a929ff1 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -475,7 +475,9 @@
round_off_gle[dimension] = dimension_values.get(dimension)
-def get_round_off_account_and_cost_center(company, voucher_type, voucher_no):
+def get_round_off_account_and_cost_center(
+ company, voucher_type, voucher_no, use_company_default=False
+):
round_off_account, round_off_cost_center = frappe.get_cached_value(
"Company", company, ["round_off_account", "round_off_cost_center"]
) or [None, None]
@@ -483,7 +485,7 @@
meta = frappe.get_meta(voucher_type)
# Give first preference to parent cost center for round off GLE
- if meta.has_field("cost_center"):
+ if not use_company_default and meta.has_field("cost_center"):
parent_cost_center = frappe.db.get_value(voucher_type, voucher_no, "cost_center")
if parent_cost_center:
round_off_cost_center = parent_cost_center
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index debe655..76a01db 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -538,13 +538,20 @@
query = query.where(gl_entry.cost_center.isin(filters.cost_center))
if filters.get("include_default_book_entries"):
+ company_fb = frappe.get_cached_value("Company", filters.company, "default_finance_book")
+
+ if filters.finance_book and company_fb and cstr(filters.finance_book) != cstr(company_fb):
+ frappe.throw(
+ _("To use a different finance book, please uncheck 'Include Default Book Entries'")
+ )
+
query = query.where(
- (gl_entry.finance_book.isin([cstr(filters.finance_book), cstr(filters.company_fb), ""]))
+ (gl_entry.finance_book.isin([cstr(filters.finance_book), cstr(company_fb)]))
| (gl_entry.finance_book.isnull())
)
else:
query = query.where(
- (gl_entry.finance_book.isin([cstr(filters.company_fb), ""])) | (gl_entry.finance_book.isnull())
+ (gl_entry.finance_book.isin([cstr(filters.finance_book)])) | (gl_entry.finance_book.isnull())
)
if accounting_dimensions:
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index 2100f26..57a9091 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -176,7 +176,8 @@
{
"fieldname": "include_default_book_entries",
"label": __("Include Default Book Entries"),
- "fieldtype": "Check"
+ "fieldtype": "Check",
+ "default": 1
},
{
"fieldname": "show_cancelled_entries",
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 27b84c4..0b05c11 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -244,13 +244,23 @@
if filters.get("project"):
conditions.append("project in %(project)s")
- if filters.get("finance_book"):
- if filters.get("include_default_book_entries"):
- conditions.append(
- "(finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)"
- )
+ if filters.get("include_default_book_entries"):
+ if filters.get("finance_book"):
+ if filters.get("company_fb") and cstr(filters.get("finance_book")) != cstr(
+ filters.get("company_fb")
+ ):
+ frappe.throw(
+ _("To use a different finance book, please uncheck 'Include Default Book Entries'")
+ )
+ else:
+ conditions.append("(finance_book in (%(finance_book)s) OR finance_book IS NULL)")
else:
- conditions.append("finance_book in (%(finance_book)s)")
+ conditions.append("(finance_book in (%(company_fb)s) OR finance_book IS NULL)")
+ else:
+ if filters.get("finance_book"):
+ conditions.append("(finance_book in (%(finance_book)s) OR finance_book IS NULL)")
+ else:
+ conditions.append("(finance_book IS NULL)")
if not filters.get("show_cancelled_entries"):
conditions.append("is_cancelled = 0")
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py
index 53611ab..57dac2a 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.py
+++ b/erpnext/accounts/report/trial_balance/trial_balance.py
@@ -248,13 +248,20 @@
opening_balance = opening_balance.where(closing_balance.project == filters.project)
if filters.get("include_default_book_entries"):
+ company_fb = frappe.get_cached_value("Company", filters.company, "default_finance_book")
+
+ if filters.finance_book and company_fb and cstr(filters.finance_book) != cstr(company_fb):
+ frappe.throw(
+ _("To use a different finance book, please uncheck 'Include Default Book Entries'")
+ )
+
opening_balance = opening_balance.where(
- (closing_balance.finance_book.isin([cstr(filters.finance_book), cstr(filters.company_fb), ""]))
+ (closing_balance.finance_book.isin([cstr(filters.finance_book), cstr(company_fb)]))
| (closing_balance.finance_book.isnull())
)
else:
opening_balance = opening_balance.where(
- (closing_balance.finance_book.isin([cstr(filters.finance_book), ""]))
+ (closing_balance.finance_book.isin([cstr(filters.finance_book)]))
| (closing_balance.finance_book.isnull())
)