mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-03 13:38:27 +00:00
Merge pull request #33164 from frappe/version-13-hotfix
chore: release v13
This commit is contained in:
@@ -298,20 +298,22 @@ def make_round_off_gle(gl_map, debit_credit_diff, precision):
|
||||
round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(
|
||||
gl_map[0].company, gl_map[0].voucher_type, gl_map[0].voucher_no
|
||||
)
|
||||
round_off_account_exists = False
|
||||
round_off_gle = frappe._dict()
|
||||
for d in gl_map:
|
||||
if d.account == round_off_account:
|
||||
round_off_gle = d
|
||||
if d.debit:
|
||||
debit_credit_diff -= flt(d.debit)
|
||||
else:
|
||||
debit_credit_diff += flt(d.credit)
|
||||
round_off_account_exists = True
|
||||
round_off_account_exists = False
|
||||
|
||||
if round_off_account_exists and abs(debit_credit_diff) < (1.0 / (10**precision)):
|
||||
gl_map.remove(round_off_gle)
|
||||
return
|
||||
if gl_map[0].voucher_type != "Period Closing Voucher":
|
||||
for d in gl_map:
|
||||
if d.account == round_off_account:
|
||||
round_off_gle = d
|
||||
if d.debit:
|
||||
debit_credit_diff -= flt(d.debit) - flt(d.credit)
|
||||
else:
|
||||
debit_credit_diff += flt(d.credit)
|
||||
round_off_account_exists = True
|
||||
|
||||
if round_off_account_exists and abs(debit_credit_diff) < (1.0 / (10**precision)):
|
||||
gl_map.remove(round_off_gle)
|
||||
return
|
||||
|
||||
if not round_off_gle:
|
||||
for k in ["voucher_type", "voucher_no", "company", "posting_date", "remarks"]:
|
||||
@@ -334,7 +336,6 @@ def make_round_off_gle(gl_map, debit_credit_diff, precision):
|
||||
)
|
||||
|
||||
update_accounting_dimensions(round_off_gle)
|
||||
|
||||
if not round_off_account_exists:
|
||||
gl_map.append(round_off_gle)
|
||||
|
||||
|
||||
@@ -685,10 +685,10 @@ class ReceivablePayableReport(object):
|
||||
|
||||
if self.filters.get(scrub(self.party_type)):
|
||||
select_fields = "debit_in_account_currency as debit, credit_in_account_currency as credit"
|
||||
doc_currency_fields = "debit as debit_in_account_currency, credit as credit_in_account_currency"
|
||||
else:
|
||||
select_fields = "debit, credit"
|
||||
|
||||
doc_currency_fields = "debit_in_account_currency, credit_in_account_currency"
|
||||
doc_currency_fields = "debit_in_account_currency, credit_in_account_currency"
|
||||
|
||||
remarks = ", remarks" if self.filters.get("show_remarks") else ""
|
||||
|
||||
|
||||
@@ -825,7 +825,9 @@ def update_maintenance_status():
|
||||
|
||||
for asset in assets:
|
||||
asset = frappe.get_doc("Asset", asset.name)
|
||||
if frappe.db.exists("Asset Repair", {"asset_name": asset.name, "repair_status": "Pending"}):
|
||||
if frappe.db.exists(
|
||||
"Asset Repair", {"asset_name": asset.name, "repair_status": "Pending", "docstatus": 0}
|
||||
):
|
||||
asset.set_status("Out of Order")
|
||||
elif frappe.db.exists(
|
||||
"Asset Maintenance Task", {"parent": asset.name, "next_due_date": today()}
|
||||
|
||||
@@ -578,6 +578,7 @@ class SellingController(StockController):
|
||||
"customer_address": "address_display",
|
||||
"shipping_address_name": "shipping_address",
|
||||
"company_address": "company_address_display",
|
||||
"dispatch_address_name": "dispatch_address",
|
||||
}
|
||||
|
||||
for address_field, address_display_field in address_dict.items():
|
||||
|
||||
@@ -191,7 +191,9 @@ def get_total_pledged_security_value(loan):
|
||||
|
||||
for security, qty in pledged_securities.items():
|
||||
after_haircut_percentage = 100 - hair_cut_map.get(security)
|
||||
security_value += (loan_security_price_map.get(security) * qty * after_haircut_percentage) / 100
|
||||
security_value += (
|
||||
loan_security_price_map.get(security, 0) * qty * after_haircut_percentage
|
||||
) / 100
|
||||
|
||||
return security_value
|
||||
|
||||
|
||||
@@ -54,11 +54,11 @@ frappe.query_reports["Job Card Summary"] = {
|
||||
options: ["", "Open", "Work In Progress", "Completed", "On Hold"]
|
||||
},
|
||||
{
|
||||
label: __("Sales Orders"),
|
||||
fieldname: "sales_order",
|
||||
label: __("Work Orders"),
|
||||
fieldname: "work_order",
|
||||
fieldtype: "MultiSelectList",
|
||||
get_data: function(txt) {
|
||||
return frappe.db.get_link_options('Sales Order', txt);
|
||||
return frappe.db.get_link_options('Work Order', txt);
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -36,10 +36,14 @@ def get_data(filters):
|
||||
"total_time_in_mins",
|
||||
]
|
||||
|
||||
for field in ["work_order", "workstation", "operation", "company"]:
|
||||
for field in ["work_order", "production_item"]:
|
||||
if filters.get(field):
|
||||
query_filters[field] = ("in", filters.get(field))
|
||||
|
||||
for field in ["workstation", "operation", "status", "company"]:
|
||||
if filters.get(field):
|
||||
query_filters[field] = filters.get(field)
|
||||
|
||||
data = frappe.get_all("Job Card", fields=fields, filters=query_filters)
|
||||
|
||||
if not data:
|
||||
|
||||
@@ -39,10 +39,14 @@ def get_data(filters):
|
||||
"lead_time",
|
||||
]
|
||||
|
||||
for field in ["sales_order", "production_item", "status", "company"]:
|
||||
for field in ["sales_order", "production_item"]:
|
||||
if filters.get(field):
|
||||
query_filters[field] = ("in", filters.get(field))
|
||||
|
||||
for field in ["status", "company"]:
|
||||
if filters.get(field):
|
||||
query_filters[field] = filters.get(field)
|
||||
|
||||
query_filters["planned_start_date"] = (">=", filters.get("from_date"))
|
||||
query_filters["planned_end_date"] = ("<=", filters.get("to_date"))
|
||||
|
||||
|
||||
@@ -346,6 +346,8 @@ class PayrollEntry(Document):
|
||||
"credit_in_account_currency": flt(payable_amt, precision),
|
||||
"exchange_rate": flt(exchange_rate),
|
||||
"cost_center": self.cost_center,
|
||||
"reference_type": self.doctype,
|
||||
"reference_name": self.name,
|
||||
},
|
||||
accounting_dimensions,
|
||||
)
|
||||
@@ -720,12 +722,21 @@ def get_month_details(year, month):
|
||||
|
||||
def get_payroll_entry_bank_entries(payroll_entry_name):
|
||||
journal_entries = frappe.db.sql(
|
||||
"select name from `tabJournal Entry Account` "
|
||||
'where reference_type="Payroll Entry" '
|
||||
"and reference_name=%s and docstatus=1",
|
||||
"""
|
||||
select
|
||||
je.name
|
||||
from
|
||||
`tabJournal Entry` je,
|
||||
`tabJournal Entry Account` jea
|
||||
where
|
||||
je.name = jea.parent
|
||||
and je.voucher_type = 'Bank Entry'
|
||||
and jea.reference_type = 'Payroll Entry'
|
||||
and jea.reference_name = %s
|
||||
""",
|
||||
payroll_entry_name,
|
||||
as_dict=1,
|
||||
)
|
||||
as_dict=True,
|
||||
) # nosemgrep
|
||||
|
||||
return journal_entries
|
||||
|
||||
|
||||
@@ -133,9 +133,17 @@ class TestPayrollEntry(FrappeTestCase):
|
||||
|
||||
payment_entry = frappe.db.sql(
|
||||
"""
|
||||
Select ifnull(sum(je.total_debit),0) as total_debit, ifnull(sum(je.total_credit),0) as total_credit from `tabJournal Entry` je, `tabJournal Entry Account` jea
|
||||
Where je.name = jea.parent
|
||||
And jea.reference_name = %s
|
||||
select
|
||||
ifnull(sum(je.total_debit),0) as total_debit,
|
||||
ifnull(sum(je.total_credit),0) as total_credit
|
||||
from
|
||||
`tabJournal Entry` je,
|
||||
`tabJournal Entry Account` jea
|
||||
Where
|
||||
je.name = jea.parent
|
||||
and je.voucher_type = 'Bank Entry'
|
||||
and jea.reference_type = 'Payroll Entry'
|
||||
and jea.reference_name = %s
|
||||
""",
|
||||
(payroll_entry.name),
|
||||
as_dict=1,
|
||||
|
||||
@@ -10,3 +10,8 @@ class EInvoiceSettings(Document):
|
||||
def validate(self):
|
||||
if self.enable and not self.credentials:
|
||||
frappe.throw(_("You must add atleast one credentials to be able to use E Invoicing."))
|
||||
|
||||
prev_doc = self.get_doc_before_save()
|
||||
if prev_doc.client_secret != self.client_secret or prev_doc.client_id != self.client_id:
|
||||
self.auth_token = None
|
||||
self.token_expiry = None
|
||||
|
||||
@@ -370,9 +370,6 @@ frappe.ui.form.on("Material Request Item", {
|
||||
if (flt(d.qty) < flt(d.min_order_qty)) {
|
||||
frappe.msgprint(__("Warning: Material Requested Qty is less than Minimum Order Qty"));
|
||||
}
|
||||
|
||||
const item = locals[doctype][name];
|
||||
frm.events.get_item_data(frm, item, false);
|
||||
},
|
||||
|
||||
from_warehouse: function(frm, doctype, name) {
|
||||
|
||||
@@ -34,6 +34,22 @@ frappe.ui.form.on('Repost Item Valuation', {
|
||||
frm.trigger('setup_realtime_progress');
|
||||
},
|
||||
|
||||
based_on: function(frm) {
|
||||
var fields_to_reset = [];
|
||||
|
||||
if (frm.doc.based_on == 'Transaction') {
|
||||
fields_to_reset = ['item_code', 'warehouse'];
|
||||
} else if (frm.doc.based_on == 'Item and Warehouse') {
|
||||
fields_to_reset = ['voucher_type', 'voucher_no'];
|
||||
}
|
||||
|
||||
if (fields_to_reset) {
|
||||
fields_to_reset.forEach(field => {
|
||||
frm.set_value(field, undefined);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
setup_realtime_progress: function(frm) {
|
||||
frappe.realtime.on('item_reposting_progress', data => {
|
||||
if (frm.doc.name !== data.name) {
|
||||
|
||||
@@ -50,13 +50,15 @@
|
||||
"fieldname": "posting_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Posting Date",
|
||||
"read_only_depends_on": "eval: doc.based_on == \"Transaction\"",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "voucher_no.posting_time",
|
||||
"fieldname": "posting_time",
|
||||
"fieldtype": "Time",
|
||||
"label": "Posting Time"
|
||||
"label": "Posting Time",
|
||||
"read_only_depends_on": "eval: doc.based_on == \"Transaction\""
|
||||
},
|
||||
{
|
||||
"default": "Queued",
|
||||
@@ -195,7 +197,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-06-13 12:20:22.182322",
|
||||
"modified": "2022-11-28 16:00:05.637440",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Repost Item Valuation",
|
||||
|
||||
@@ -1050,7 +1050,8 @@ erpnext.stock.select_batch_and_serial_no = (frm, item) => {
|
||||
if (frm.doc.purpose === 'Material Receipt') return;
|
||||
|
||||
frappe.require("assets/erpnext/js/utils/serial_no_batch_selector.js", function() {
|
||||
new erpnext.SerialNoBatchSelector({
|
||||
if (frm.batch_selector?.dialog?.display) return;
|
||||
frm.batch_selector = new erpnext.SerialNoBatchSelector({
|
||||
frm: frm,
|
||||
item: item,
|
||||
warehouse_details: get_warehouse_type_and_name(item),
|
||||
|
||||
@@ -229,7 +229,7 @@ class StockReconciliation(StockController):
|
||||
|
||||
if item.has_serial_no or item.has_batch_no:
|
||||
has_serial_no = True
|
||||
self.get_sle_for_serialized_items(row, sl_entries)
|
||||
self.get_sle_for_serialized_items(row, sl_entries, item)
|
||||
else:
|
||||
if row.serial_no or row.batch_no:
|
||||
frappe.throw(
|
||||
@@ -281,7 +281,7 @@ class StockReconciliation(StockController):
|
||||
if has_serial_no and sl_entries:
|
||||
self.update_valuation_rate_for_serial_no()
|
||||
|
||||
def get_sle_for_serialized_items(self, row, sl_entries):
|
||||
def get_sle_for_serialized_items(self, row, sl_entries, item):
|
||||
from erpnext.stock.stock_ledger import get_previous_sle
|
||||
|
||||
serial_nos = get_serial_nos(row.serial_no)
|
||||
@@ -347,6 +347,9 @@ class StockReconciliation(StockController):
|
||||
if row.qty:
|
||||
args = self.get_sle_for_items(row)
|
||||
|
||||
if item.has_serial_no and item.has_batch_no:
|
||||
args["qty_after_transaction"] = row.qty
|
||||
|
||||
args.update(
|
||||
{
|
||||
"actual_qty": row.qty,
|
||||
|
||||
@@ -643,6 +643,38 @@ class TestStockReconciliation(FrappeTestCase, StockTestMixin):
|
||||
)
|
||||
self.assertEqual(len(active_sr_no), 0)
|
||||
|
||||
def test_serial_no_batch_no_item(self):
|
||||
item = self.make_item(
|
||||
"Test Serial No Batch No Item",
|
||||
{
|
||||
"is_stock_item": 1,
|
||||
"has_serial_no": 1,
|
||||
"has_batch_no": 1,
|
||||
"serial_no_series": "SRS9.####",
|
||||
"batch_number_series": "BNS9.####",
|
||||
"create_new_batch": 1,
|
||||
},
|
||||
)
|
||||
|
||||
warehouse = "_Test Warehouse - _TC"
|
||||
|
||||
sr = create_stock_reconciliation(
|
||||
item_code=item.name,
|
||||
warehouse=warehouse,
|
||||
qty=1,
|
||||
rate=100,
|
||||
)
|
||||
|
||||
sl_entry = frappe.db.get_value(
|
||||
"Stock Ledger Entry",
|
||||
{"voucher_type": "Stock Reconciliation", "voucher_no": sr.name},
|
||||
["actual_qty", "qty_after_transaction"],
|
||||
as_dict=1,
|
||||
)
|
||||
|
||||
self.assertEqual(flt(sl_entry.actual_qty), 1.0)
|
||||
self.assertEqual(flt(sl_entry.qty_after_transaction), 1.0)
|
||||
|
||||
|
||||
def create_batch_item_with_batch(item_name, batch_id):
|
||||
batch_item_doc = create_item(item_name, is_stock_item=1)
|
||||
|
||||
Reference in New Issue
Block a user