Compare commits

..

9 Commits

Author SHA1 Message Date
Frappe PR Bot
7c7dc5328e chore(release): Bumped to Version 14.47.4
## [14.47.4](https://github.com/frappe/erpnext/compare/v14.47.3...v14.47.4) (2023-11-10)

### Bug Fixes

* new logic for handling revaluation journals ([010ccf8](010ccf80f5))
2023-11-10 07:46:10 +00:00
ruthra kumar
cb655226de Merge pull request #38037 from frappe/mergify/bp/version-14/pr-38004
fix: handling of exchange rate journals in AR/AP (backport #38004)
2023-11-10 13:14:45 +05:30
ruthra kumar
010ccf80f5 fix: new logic for handling revaluation journals
(cherry picked from commit 1d8fcd66e6)
2023-11-10 12:05:46 +05:30
ruthra kumar
89695022c7 Merge pull request #38021 from frappe/mergify/bp/version-14/pr-37860
refactor: ignore disabled account while selecting Income Accounts (backport #37860)
2023-11-09 17:28:14 +05:30
Frappe PR Bot
50627733b4 chore(release): Bumped to Version 14.47.3
## [14.47.3](https://github.com/frappe/erpnext/compare/v14.47.2...v14.47.3) (2023-11-09)

### Bug Fixes

* make adjustment entry using stock reconciliation (backport [#37995](https://github.com/frappe/erpnext/issues/37995)) (backport [#38008](https://github.com/frappe/erpnext/issues/38008)) ([#38018](https://github.com/frappe/erpnext/issues/38018)) ([7942ad4](7942ad488e))
2023-11-09 11:24:29 +00:00
mergify[bot]
7942ad488e fix: make adjustment entry using stock reconciliation (backport #37995) (backport #38008) (#38018)
fix: make adjustment entry using stock reconciliation (backport #37995) (#38008)

* fix: make adjustment entry using stock reconciliation (#37995)

fix: do adjustment entry using stock reconciliation
(cherry picked from commit a8216b9727)

# Conflicts:
#	erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
#	erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py

* chore: fix conflicts

* fix: conflicts

* chore: fix conflicts

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
(cherry picked from commit 984703c3c9)

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-11-09 16:53:14 +05:30
ruthra kumar
c3d7348c73 refactor: ignore disabled account while selecting Income Accounts
(cherry picked from commit 6e3e094c95)
2023-11-09 11:14:38 +00:00
Frappe PR Bot
9a2674ea29 chore(release): Bumped to Version 14.47.2
## [14.47.2](https://github.com/frappe/erpnext/compare/v14.47.1...v14.47.2) (2023-11-09)

### Bug Fixes

* pick serial nos from selected batch only (backport [#37988](https://github.com/frappe/erpnext/issues/37988)) ([#38011](https://github.com/frappe/erpnext/issues/38011)) ([0405aae](0405aae4a0))
2023-11-09 07:28:50 +00:00
mergify[bot]
0405aae4a0 fix: pick serial nos from selected batch only (backport #37988) (#38011)
fix: pick serial nos from selected batch only (#37988)

* fix: pick current serial nos from selected batch only

* test: add test case for current qty and current serial nos

(cherry picked from commit db29180eec)

Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
2023-11-09 12:57:03 +05:30
10 changed files with 149 additions and 26 deletions

View File

@@ -3,7 +3,7 @@ import inspect
import frappe
__version__ = "14.47.1"
__version__ = "14.47.4"
def get_default_company(user=None):

View File

@@ -181,7 +181,6 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e
erpnext.accounts.unreconcile_payments.add_unreconcile_btn(me.frm);
}
make_maintenance_schedule() {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_maintenance_schedule",
@@ -557,15 +556,6 @@ cur_frm.fields_dict.write_off_cost_center.get_query = function(doc) {
}
}
// Income Account in Details Table
// --------------------------------
cur_frm.set_query("income_account", "items", function(doc) {
return{
query: "erpnext.controllers.queries.get_income_account",
filters: {'company': doc.company}
}
});
// Cost Center in Details Table
// -----------------------------
cur_frm.fields_dict["items"].grid.get_field("cost_center").get_query = function(doc) {
@@ -660,6 +650,16 @@ frappe.ui.form.on('Sales Invoice', {
};
});
frm.set_query("income_account", "items", function() {
return{
query: "erpnext.controllers.queries.get_income_account",
filters: {
'company': frm.doc.company,
"disabled": 0
}
}
});
frm.custom_make_buttons = {
'Delivery Note': 'Delivery',
'Sales Invoice': 'Return / Credit Note',

View File

@@ -173,12 +173,18 @@ frappe.query_reports["Accounts Receivable"] = {
"label": __("Show Remarks"),
"fieldtype": "Check",
},
{
"fieldname": "for_revaluation_journals",
"label": __("Revaluation Journals"),
"fieldtype": "Check",
},
{
"fieldname": "ignore_accounts",
"label": __("Group by Voucher"),
"fieldtype": "Check",
}
],
"formatter": function(value, row, column, data, default_formatter) {

View File

@@ -281,11 +281,20 @@ class ReceivablePayableReport(object):
row.invoice_grand_total = row.invoiced
if (abs(row.outstanding) > 1.0 / 10**self.currency_precision) and (
(abs(row.outstanding_in_account_currency) > 1.0 / 10**self.currency_precision)
or (row.voucher_no in self.err_journals)
):
must_consider = False
if self.filters.get("for_revaluation_journals"):
if (abs(row.outstanding) > 1.0 / 10**self.currency_precision) or (
(abs(row.outstanding_in_account_currency) > 1.0 / 10**self.currency_precision)
):
must_consider = True
else:
if (abs(row.outstanding) > 1.0 / 10**self.currency_precision) and (
(abs(row.outstanding_in_account_currency) > 1.0 / 10**self.currency_precision)
or (row.voucher_no in self.err_journals)
):
must_consider = True
if must_consider:
# non-zero oustanding, we must consider this row
if self.is_invoice(row) and self.filters.based_on_payment_terms:

View File

@@ -560,6 +560,8 @@ def get_income_account(doctype, txt, searchfield, start, page_len, filters):
if filters.get("company"):
condition += "and tabAccount.company = %(company)s"
condition += f"and tabAccount.disabled = {filters.get('disabled', 0)}"
return frappe.db.sql(
"""select tabAccount.name from `tabAccount`
where (tabAccount.report_type = "Profit and Loss"

View File

@@ -11,6 +11,7 @@
"warehouse",
"posting_date",
"posting_time",
"is_adjustment_entry",
"column_break_6",
"voucher_type",
"voucher_no",
@@ -309,6 +310,12 @@
"label": "Recalculate Incoming/Outgoing Rate",
"no_copy": 1,
"read_only": 1
},
{
"default": "0",
"fieldname": "is_adjustment_entry",
"fieldtype": "Check",
"label": "Is Adjustment Entry"
}
],
"hide_toolbar": 1,
@@ -317,7 +324,7 @@
"in_create": 1,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-12-21 06:25:30.040801",
"modified": "2023-10-23 18:07:42.063615",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Ledger Entry",
@@ -341,4 +348,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}
}

View File

@@ -269,6 +269,10 @@ class StockReconciliation(StockController):
if item.has_batch_no:
has_batch_no = True
if not row.qty and not row.valuation_rate and not row.current_qty:
self.make_adjustment_entry(row, sl_entries)
continue
if item.has_serial_no or item.has_batch_no:
has_serial_no = True
self.get_sle_for_serialized_items(row, sl_entries, item)
@@ -402,6 +406,21 @@ class StockReconciliation(StockController):
# update valuation rate
self.update_valuation_rate_for_serial_nos(row, serial_nos)
def make_adjustment_entry(self, row, sl_entries):
from erpnext.stock.stock_ledger import get_stock_value_difference
difference_amount = get_stock_value_difference(
row.item_code, row.warehouse, self.posting_date, self.posting_time
)
if not difference_amount:
return
args = self.get_sle_for_items(row)
args.update({"stock_value_difference": -1 * difference_amount, "is_adjustment_entry": 1})
sl_entries.append(args)
def update_valuation_rate_for_serial_no(self):
for d in self.items:
if not d.serial_no:
@@ -890,6 +909,7 @@ def get_stock_balance_for(
with_valuation_rate=with_valuation_rate,
with_serial_no=has_serial_no,
inventory_dimensions_dict=inventory_dimensions_dict,
batch_no=batch_no,
)
if has_serial_no:

View File

@@ -1009,6 +1009,52 @@ class TestStockReconciliation(FrappeTestCase, StockTestMixin):
self.assertEqual(sr2.docstatus, 1)
def test_current_qty_and_current_serial_no_count(self):
# Step - 1: Create a Serial Batch Item
item = self.make_item(
properties={
"is_stock_item": 1,
"has_serial_no": 1,
"serial_no_series": "TEST-SERIAL-.###",
"has_batch_no": 1,
"create_new_batch": 1,
"batch_number_series": "TEST-BATCH-.###",
}
).name
# Step - 2: Inward stock in multiple Batches
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
se1 = make_stock_entry(
item_code=item,
target="_Test Warehouse - _TC",
qty=10,
)
se2 = make_stock_entry(
item_code=item,
target="_Test Warehouse - _TC",
qty=5,
)
# Step - 3: Create Stock Reconciliation
sr = create_stock_reconciliation(
item_code=item,
warehouse="_Test Warehouse - _TC",
qty=0,
batch_no=se1.items[0].batch_no,
do_not_submit=True,
)
# Test - 1: Current Serial No Count should be equal to Current Qty
self.assertEqual(sr.items[0].current_qty, se1.items[0].qty)
self.assertEqual(len(sr.items[0].current_serial_no.split("\n")), sr.items[0].current_qty)
sr.items[0].batch_no = se2.items[0].batch_no
sr.save()
self.assertEqual(sr.items[0].current_qty, se2.items[0].qty)
self.assertEqual(len(sr.items[0].current_serial_no.split("\n")), sr.items[0].current_qty)
def create_batch_item_with_batch(item_name, batch_id):
batch_item_doc = create_item(item_name, is_stock_item=1)

View File

@@ -635,9 +635,11 @@ class update_entries_after(object):
sle.valuation_rate = self.wh_data.valuation_rate
sle.stock_value = self.wh_data.stock_value
sle.stock_queue = json.dumps(self.wh_data.stock_queue)
sle.stock_value_difference = stock_value_difference
sle.doctype = "Stock Ledger Entry"
if not sle.is_adjustment_entry or not self.args.get("sle_id"):
sle.stock_value_difference = stock_value_difference
sle.doctype = "Stock Ledger Entry"
frappe.get_doc(sle).db_update()
if not self.args.get("sle_id"):
@@ -1711,3 +1713,27 @@ def is_internal_transfer(sle):
if data.is_internal_supplier and data.represents_company == data.company:
return True
def get_stock_value_difference(item_code, warehouse, posting_date, posting_time, voucher_no=None):
table = frappe.qb.DocType("Stock Ledger Entry")
query = (
frappe.qb.from_(table)
.select(Sum(table.stock_value_difference).as_("value"))
.where(
(table.is_cancelled == 0)
& (table.item_code == item_code)
& (table.warehouse == warehouse)
& (
(table.posting_date < posting_date)
| ((table.posting_date == posting_date) & (table.posting_time <= posting_time))
)
)
)
if voucher_no:
query = query.where(table.voucher_no != voucher_no)
difference_amount = query.run()
return flt(difference_amount[0][0]) if difference_amount else 0

View File

@@ -95,6 +95,7 @@ def get_stock_balance(
with_valuation_rate=False,
with_serial_no=False,
inventory_dimensions_dict=None,
batch_no=None,
):
"""Returns stock balance quantity at given warehouse on given posting date or current date.
@@ -124,6 +125,9 @@ def get_stock_balance(
if with_valuation_rate:
if with_serial_no:
if batch_no:
args["batch_no"] = batch_no
serial_nos = get_serial_nos_data_after_transactions(args)
return (
@@ -140,27 +144,30 @@ def get_stock_balance(
def get_serial_nos_data_after_transactions(args):
serial_nos = set()
args = frappe._dict(args)
sle = frappe.qb.DocType("Stock Ledger Entry")
stock_ledger_entries = (
sle = frappe.qb.DocType("Stock Ledger Entry")
query = (
frappe.qb.from_(sle)
.select("serial_no", "actual_qty")
.select(sle.serial_no, sle.actual_qty)
.where(
(sle.item_code == args.item_code)
(sle.is_cancelled == 0)
& (sle.item_code == args.item_code)
& (sle.warehouse == args.warehouse)
& (
CombineDatetime(sle.posting_date, sle.posting_time)
< CombineDatetime(args.posting_date, args.posting_time)
)
& (sle.is_cancelled == 0)
)
.orderby(sle.posting_date, sle.posting_time, sle.creation)
.run(as_dict=1)
)
if args.batch_no:
query = query.where(sle.batch_no == args.batch_no)
stock_ledger_entries = query.run(as_dict=True)
for stock_ledger_entry in stock_ledger_entries:
changed_serial_no = get_serial_nos_data(stock_ledger_entry.serial_no)
if stock_ledger_entry.actual_qty > 0: