mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-21 14:09:19 +00:00
Merge branch 'version-15-hotfix' into mergify/bp/version-15-hotfix/pr-45024
This commit is contained in:
@@ -120,6 +120,7 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
|
|||||||
args: {
|
args: {
|
||||||
bank_account: frm.doc.bank_account,
|
bank_account: frm.doc.bank_account,
|
||||||
till_date: frappe.datetime.add_days(frm.doc.bank_statement_from_date, -1),
|
till_date: frappe.datetime.add_days(frm.doc.bank_statement_from_date, -1),
|
||||||
|
company: frm.doc.company,
|
||||||
},
|
},
|
||||||
callback: (response) => {
|
callback: (response) => {
|
||||||
frm.set_value("account_opening_balance", response.message);
|
frm.set_value("account_opening_balance", response.message);
|
||||||
@@ -135,6 +136,7 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
|
|||||||
args: {
|
args: {
|
||||||
bank_account: frm.doc.bank_account,
|
bank_account: frm.doc.bank_account,
|
||||||
till_date: frm.doc.bank_statement_to_date,
|
till_date: frm.doc.bank_statement_to_date,
|
||||||
|
company: frm.doc.company,
|
||||||
},
|
},
|
||||||
callback: (response) => {
|
callback: (response) => {
|
||||||
frm.cleared_balance = response.message;
|
frm.cleared_balance = response.message;
|
||||||
|
|||||||
@@ -79,10 +79,17 @@ def get_bank_transactions(bank_account, from_date=None, to_date=None):
|
|||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_account_balance(bank_account, till_date):
|
def get_account_balance(bank_account, till_date, company):
|
||||||
# returns account balance till the specified date
|
# returns account balance till the specified date
|
||||||
account = frappe.db.get_value("Bank Account", bank_account, "account")
|
account = frappe.db.get_value("Bank Account", bank_account, "account")
|
||||||
filters = frappe._dict({"account": account, "report_date": till_date, "include_pos_transactions": 1})
|
filters = frappe._dict(
|
||||||
|
{
|
||||||
|
"account": account,
|
||||||
|
"report_date": till_date,
|
||||||
|
"include_pos_transactions": 1,
|
||||||
|
"company": company,
|
||||||
|
}
|
||||||
|
)
|
||||||
data = get_entries(filters)
|
data = get_entries(filters)
|
||||||
|
|
||||||
balance_as_per_system = get_balance_on(filters["account"], filters["report_date"])
|
balance_as_per_system = get_balance_on(filters["account"], filters["report_date"])
|
||||||
@@ -94,11 +101,7 @@ def get_account_balance(bank_account, till_date):
|
|||||||
|
|
||||||
amounts_not_reflected_in_system = get_amounts_not_reflected_in_system(filters)
|
amounts_not_reflected_in_system = get_amounts_not_reflected_in_system(filters)
|
||||||
|
|
||||||
bank_bal = (
|
return flt(balance_as_per_system) - flt(total_debit) + flt(total_credit) + amounts_not_reflected_in_system
|
||||||
flt(balance_as_per_system) - flt(total_debit) + flt(total_credit) + amounts_not_reflected_in_system
|
|
||||||
)
|
|
||||||
|
|
||||||
return bank_bal
|
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"actions": [],
|
"actions": [],
|
||||||
"autoname": "format:ACC-PPR-{#####}",
|
"autoname": "format:ACC-PPR-{#####}",
|
||||||
"beta": 1,
|
|
||||||
"creation": "2023-03-30 21:28:39.793927",
|
"creation": "2023-03-30 21:28:39.793927",
|
||||||
"default_view": "List",
|
"default_view": "List",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
@@ -158,7 +157,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2024-08-27 14:48:56.715320",
|
"modified": "2025-01-08 08:22:14.798085",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Process Payment Reconciliation",
|
"name": "Process Payment Reconciliation",
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ def trigger_reconciliation_for_queued_docs():
|
|||||||
unique_filters = set()
|
unique_filters = set()
|
||||||
queue_size = 5
|
queue_size = 5
|
||||||
|
|
||||||
fields = ["company", "party_type", "party", "receivable_payable_account"]
|
fields = ["company", "party_type", "party", "receivable_payable_account", "default_advance_account"]
|
||||||
|
|
||||||
def get_filters_as_tuple(fields, doc):
|
def get_filters_as_tuple(fields, doc):
|
||||||
filters = ()
|
filters = ()
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"actions": [],
|
"actions": [],
|
||||||
"autoname": "format:PPR-LOG-{##}",
|
"autoname": "format:PPR-LOG-{##}",
|
||||||
"beta": 1,
|
|
||||||
"creation": "2023-03-13 15:00:09.149681",
|
"creation": "2023-03-13 15:00:09.149681",
|
||||||
"default_view": "List",
|
"default_view": "List",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
@@ -110,7 +109,7 @@
|
|||||||
"in_create": 1,
|
"in_create": 1,
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-11-02 11:32:12.254018",
|
"modified": "2025-01-08 08:22:19.104975",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Process Payment Reconciliation Log",
|
"name": "Process Payment Reconciliation Log",
|
||||||
|
|||||||
@@ -994,47 +994,51 @@ frappe.ui.form.on("Sales Invoice", {
|
|||||||
|
|
||||||
refresh: function (frm) {
|
refresh: function (frm) {
|
||||||
if (frm.doc.docstatus === 0 && !frm.doc.is_return) {
|
if (frm.doc.docstatus === 0 && !frm.doc.is_return) {
|
||||||
frm.add_custom_button(__("Fetch Timesheet"), function () {
|
frm.add_custom_button(
|
||||||
let d = new frappe.ui.Dialog({
|
__("Timesheet"),
|
||||||
title: __("Fetch Timesheet"),
|
function () {
|
||||||
fields: [
|
let d = new frappe.ui.Dialog({
|
||||||
{
|
title: __("Fetch Timesheet"),
|
||||||
label: __("From"),
|
fields: [
|
||||||
fieldname: "from_time",
|
{
|
||||||
fieldtype: "Date",
|
label: __("From"),
|
||||||
reqd: 1,
|
fieldname: "from_time",
|
||||||
|
fieldtype: "Date",
|
||||||
|
reqd: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldtype: "Column Break",
|
||||||
|
fieldname: "col_break_1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __("To"),
|
||||||
|
fieldname: "to_time",
|
||||||
|
fieldtype: "Date",
|
||||||
|
reqd: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __("Project"),
|
||||||
|
fieldname: "project",
|
||||||
|
fieldtype: "Link",
|
||||||
|
options: "Project",
|
||||||
|
default: frm.doc.project,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
primary_action: function () {
|
||||||
|
const data = d.get_values();
|
||||||
|
frm.events.add_timesheet_data(frm, {
|
||||||
|
from_time: data.from_time,
|
||||||
|
to_time: data.to_time,
|
||||||
|
project: data.project,
|
||||||
|
});
|
||||||
|
d.hide();
|
||||||
},
|
},
|
||||||
{
|
primary_action_label: __("Get Timesheets"),
|
||||||
fieldtype: "Column Break",
|
});
|
||||||
fieldname: "col_break_1",
|
d.show();
|
||||||
},
|
},
|
||||||
{
|
__("Get Items From")
|
||||||
label: __("To"),
|
);
|
||||||
fieldname: "to_time",
|
|
||||||
fieldtype: "Date",
|
|
||||||
reqd: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: __("Project"),
|
|
||||||
fieldname: "project",
|
|
||||||
fieldtype: "Link",
|
|
||||||
options: "Project",
|
|
||||||
default: frm.doc.project,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
primary_action: function () {
|
|
||||||
const data = d.get_values();
|
|
||||||
frm.events.add_timesheet_data(frm, {
|
|
||||||
from_time: data.from_time,
|
|
||||||
to_time: data.to_time,
|
|
||||||
project: data.project,
|
|
||||||
});
|
|
||||||
d.hide();
|
|
||||||
},
|
|
||||||
primary_action_label: __("Get Timesheets"),
|
|
||||||
});
|
|
||||||
d.show();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frm.doc.is_debit_note) {
|
if (frm.doc.is_debit_note) {
|
||||||
|
|||||||
@@ -1257,6 +1257,7 @@ def add_items_in_ste(ste_doc, row, qty, rm_details, rm_detail_field="sco_rm_deta
|
|||||||
"item_code": row.item_details["rm_item_code"],
|
"item_code": row.item_details["rm_item_code"],
|
||||||
"subcontracted_item": row.item_details["main_item_code"],
|
"subcontracted_item": row.item_details["main_item_code"],
|
||||||
"serial_no": "\n".join(row.serial_no) if row.serial_no else "",
|
"serial_no": "\n".join(row.serial_no) if row.serial_no else "",
|
||||||
|
"use_serial_batch_fields": 1,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1297,10 +1298,13 @@ def make_return_stock_entry_for_subcontract(
|
|||||||
if not value.qty:
|
if not value.qty:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if item_details := value.get("item_details"):
|
||||||
|
item_details["serial_and_batch_bundle"] = None
|
||||||
|
|
||||||
if value.batch_no:
|
if value.batch_no:
|
||||||
for batch_no, qty in value.batch_no.items():
|
for batch_no, qty in value.batch_no.items():
|
||||||
if qty > 0:
|
if qty > 0:
|
||||||
add_items_in_ste(ste_doc, value, value.qty, rm_details, rm_detail_field, batch_no)
|
add_items_in_ste(ste_doc, value, qty, rm_details, rm_detail_field, batch_no)
|
||||||
else:
|
else:
|
||||||
add_items_in_ste(ste_doc, value, value.qty, rm_details, rm_detail_field)
|
add_items_in_ste(ste_doc, value, value.qty, rm_details, rm_detail_field)
|
||||||
|
|
||||||
|
|||||||
@@ -282,6 +282,79 @@ class TestSubcontractingController(FrappeTestCase):
|
|||||||
|
|
||||||
frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 1)
|
frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 1)
|
||||||
|
|
||||||
|
def test_return_non_consumed_batch_materials(self):
|
||||||
|
"""
|
||||||
|
- Set backflush based on Material Transfer.
|
||||||
|
- Create SCO for item Subcontracted Item SA2.
|
||||||
|
- Transfer the batched components from Stores to Supplier warehouse with serial nos.
|
||||||
|
- Transfer extra qty of component for the subcontracted item Subcontracted Item SA2.
|
||||||
|
- Create SCR for full qty against the SCO and change the qty of raw material.
|
||||||
|
- After that return the non consumed material back to the store from supplier's warehouse.
|
||||||
|
"""
|
||||||
|
|
||||||
|
frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 0)
|
||||||
|
set_backflush_based_on("Material Transferred for Subcontract")
|
||||||
|
service_item = make_item("Subcontracted Service FG Item A", properties={"is_stock_item": 0}).name
|
||||||
|
fg_item = make_item(
|
||||||
|
"Subcontracted FG Item SA2", properties={"is_stock_item": 1, "is_sub_contracted_item": 1}
|
||||||
|
).name
|
||||||
|
rm_item = make_item(
|
||||||
|
"Subcontracted Batch RM Item SA2",
|
||||||
|
properties={
|
||||||
|
"is_stock_item": 1,
|
||||||
|
"create_new_batch": 1,
|
||||||
|
"has_batch_no": 1,
|
||||||
|
"batch_number_series": "BATCH-RM-IRM-.####",
|
||||||
|
},
|
||||||
|
).name
|
||||||
|
|
||||||
|
make_bom(item=fg_item, raw_materials=[rm_item], rate=100, currency="INR")
|
||||||
|
|
||||||
|
service_items = [
|
||||||
|
{
|
||||||
|
"warehouse": "_Test Warehouse - _TC",
|
||||||
|
"item_code": service_item,
|
||||||
|
"qty": 5,
|
||||||
|
"rate": 100,
|
||||||
|
"fg_item": fg_item,
|
||||||
|
"fg_item_qty": 5,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
sco = get_subcontracting_order(service_items=service_items)
|
||||||
|
rm_items = get_rm_items(sco.supplied_items)
|
||||||
|
rm_items[0]["qty"] += 1
|
||||||
|
itemwise_details = make_stock_in_entry(rm_items=rm_items)
|
||||||
|
|
||||||
|
for item in rm_items:
|
||||||
|
item["sco_rm_detail"] = sco.items[0].name
|
||||||
|
|
||||||
|
make_stock_transfer_entry(
|
||||||
|
sco_no=sco.name,
|
||||||
|
rm_items=rm_items,
|
||||||
|
itemwise_details=copy.deepcopy(itemwise_details),
|
||||||
|
)
|
||||||
|
|
||||||
|
scr1 = make_subcontracting_receipt(sco.name)
|
||||||
|
scr1.save()
|
||||||
|
scr1.supplied_items[0].consumed_qty = 5
|
||||||
|
scr1.submit()
|
||||||
|
|
||||||
|
for key, value in get_supplied_items(scr1).items():
|
||||||
|
transferred_detais = itemwise_details.get(key)
|
||||||
|
self.assertEqual(value.qty, 5)
|
||||||
|
self.assertEqual(sorted(value.serial_no), sorted(transferred_detais.get("serial_no")[0:5]))
|
||||||
|
|
||||||
|
sco.load_from_db()
|
||||||
|
self.assertEqual(sco.supplied_items[0].consumed_qty, 5)
|
||||||
|
doc = get_materials_from_supplier(sco.name, [d.name for d in sco.supplied_items])
|
||||||
|
doc.save()
|
||||||
|
self.assertEqual(doc.items[0].qty, 1)
|
||||||
|
self.assertEqual(doc.items[0].s_warehouse, "_Test Warehouse 1 - _TC")
|
||||||
|
self.assertEqual(doc.items[0].t_warehouse, "_Test Warehouse - _TC")
|
||||||
|
self.assertTrue(doc.items[0].batch_no)
|
||||||
|
self.assertTrue(doc.items[0].use_serial_batch_fields)
|
||||||
|
frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 1)
|
||||||
|
|
||||||
def test_return_non_consumed_materials(self):
|
def test_return_non_consumed_materials(self):
|
||||||
"""
|
"""
|
||||||
- Set backflush based on Material Transfer.
|
- Set backflush based on Material Transfer.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ erpnext.accounts.bank_reconciliation.DataTableManager = class DataTableManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
make_dt() {
|
make_dt() {
|
||||||
var me = this;
|
const me = this;
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_bank_transactions",
|
method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_bank_transactions",
|
||||||
args: {
|
args: {
|
||||||
@@ -193,6 +193,7 @@ erpnext.accounts.bank_reconciliation.DataTableManager = class DataTableManager {
|
|||||||
args: {
|
args: {
|
||||||
bank_account: this.bank_account,
|
bank_account: this.bank_account,
|
||||||
till_date: this.bank_statement_to_date,
|
till_date: this.bank_statement_to_date,
|
||||||
|
company: this.company,
|
||||||
},
|
},
|
||||||
callback: (response) => (this.cleared_balance = response.message),
|
callback: (response) => (this.cleared_balance = response.message),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -303,11 +303,10 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
|
|||||||
}
|
}
|
||||||
|
|
||||||
const me = this;
|
const me = this;
|
||||||
if (!this.frm.is_new() && this.frm.doc.docstatus === 0 && frappe.model.can_create("Quality Inspection")) {
|
if (!this.frm.is_new() && this.frm.doc.docstatus === 0 && frappe.model.can_create("Quality Inspection") && this.frm.doc.update_stock) {
|
||||||
this.frm.add_custom_button(__("Quality Inspection(s)"), () => {
|
this.frm.add_custom_button(__("Quality Inspection(s)"), () => {
|
||||||
me.make_quality_inspection();
|
me.make_quality_inspection();
|
||||||
}, __("Create"));
|
}, __("Create"));
|
||||||
this.frm.page.set_inner_btn_group_as_primary(__('Create'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const inspection_type = ["Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"].includes(this.frm.doc.doctype)
|
const inspection_type = ["Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"].includes(this.frm.doc.doctype)
|
||||||
|
|||||||
@@ -210,10 +210,21 @@ erpnext.PointOfSale.ItemDetails = class {
|
|||||||
|
|
||||||
make_auto_serial_selection_btn(item) {
|
make_auto_serial_selection_btn(item) {
|
||||||
if (item.has_serial_no || item.has_batch_no) {
|
if (item.has_serial_no || item.has_batch_no) {
|
||||||
const label = item.has_serial_no ? __("Select Serial No") : __("Select Batch No");
|
if (item.has_serial_no && item.has_batch_no) {
|
||||||
this.$form_container.append(
|
this.$form_container.append(
|
||||||
`<div class="btn btn-sm btn-secondary auto-fetch-btn">${label}</div>`
|
`<div class="btn btn-sm btn-secondary auto-fetch-btn" style="margin-top: 6px">${__(
|
||||||
);
|
"Select Serial No / Batch No"
|
||||||
|
)}</div>`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const classname = item.has_serial_no ? ".serial_no-control" : ".batch_no-control";
|
||||||
|
const label = item.has_serial_no ? __("Select Serial No") : __("Select Batch No");
|
||||||
|
this.$form_container
|
||||||
|
.find(classname)
|
||||||
|
.append(
|
||||||
|
`<div class="btn btn-sm btn-secondary auto-fetch-btn" style="margin-top: 6px">${label}</div>`
|
||||||
|
);
|
||||||
|
}
|
||||||
this.$form_container.find(".serial_no-control").find("textarea").css("height", "6rem");
|
this.$form_container.find(".serial_no-control").find("textarea").css("height", "6rem");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1557,7 +1557,7 @@ def get_type_of_transaction(parent_doc, child_row):
|
|||||||
elif parent_doc.get("doctype") == "Stock Reconciliation":
|
elif parent_doc.get("doctype") == "Stock Reconciliation":
|
||||||
type_of_transaction = "Inward"
|
type_of_transaction = "Inward"
|
||||||
|
|
||||||
if parent_doc.get("is_return"):
|
if parent_doc.get("is_return") and parent_doc.get("doctype") != "Stock Entry":
|
||||||
type_of_transaction = "Inward"
|
type_of_transaction = "Inward"
|
||||||
if (
|
if (
|
||||||
parent_doc.get("doctype") in ["Purchase Receipt", "Purchase Invoice"]
|
parent_doc.get("doctype") in ["Purchase Receipt", "Purchase Invoice"]
|
||||||
|
|||||||
@@ -317,7 +317,6 @@ class StockBalanceReport:
|
|||||||
.where((sle.docstatus < 2) & (sle.is_cancelled == 0))
|
.where((sle.docstatus < 2) & (sle.is_cancelled == 0))
|
||||||
.orderby(sle.posting_datetime)
|
.orderby(sle.posting_datetime)
|
||||||
.orderby(sle.creation)
|
.orderby(sle.creation)
|
||||||
.orderby(sle.actual_qty)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
query = self.apply_inventory_dimensions_filters(query, sle)
|
query = self.apply_inventory_dimensions_filters(query, sle)
|
||||||
|
|||||||
Reference in New Issue
Block a user