Merge pull request #39163 from nabinhait/asset-fix1
fix: Purchase information is not required for creating a composite asset
diff --git a/erpnext/accounts/doctype/account/account_tree.js b/erpnext/accounts/doctype/account/account_tree.js
index f240aa6..0b29769 100644
--- a/erpnext/accounts/doctype/account/account_tree.js
+++ b/erpnext/accounts/doctype/account/account_tree.js
@@ -77,7 +77,7 @@
// show Dr if positive since balance is calculated as debit - credit else show Cr
const balance = account.balance_in_account_currency || account.balance;
- const dr_or_cr = balance > 0 ? "Dr": "Cr";
+ const dr_or_cr = balance > 0 ? __("Dr"): __("Cr");
const format = (value, currency) => format_currency(Math.abs(value), currency);
if (account.balance!==undefined) {
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
index 629ed1c..57f7c0e 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
@@ -366,15 +366,17 @@
and len(get_reconciled_bank_transactions(doctype, docname)) < 2
):
return
- frappe.db.set_value(doctype, docname, "clearance_date", clearance_date)
- elif doctype == "Sales Invoice":
- frappe.db.set_value(
- "Sales Invoice Payment",
- dict(parenttype=doctype, parent=docname),
- "clearance_date",
- clearance_date,
- )
+ if doctype == "Sales Invoice":
+ frappe.db.set_value(
+ "Sales Invoice Payment",
+ dict(parenttype=doctype, parent=docname),
+ "clearance_date",
+ clearance_date,
+ )
+ return
+
+ frappe.db.set_value(doctype, docname, "clearance_date", clearance_date)
elif doctype == "Bank Transaction":
# For when a second bank transaction has fixed another, e.g. refund
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index 2611240..81ffee3 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -747,6 +747,10 @@
args["get_orders_to_be_billed"] = true;
}
+ if (frm.doc.book_advance_payments_in_separate_party_account) {
+ args["book_advance_payments_in_separate_party_account"] = true;
+ }
+
frappe.flags.allocate_payment_amount = filters['allocate_payment_amount'];
return frappe.call({
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 11c7c17..052eff3 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -256,6 +256,7 @@
"get_outstanding_invoices": True,
"get_orders_to_be_billed": True,
"vouchers": vouchers,
+ "book_advance_payments_in_separate_party_account": self.book_advance_payments_in_separate_party_account,
},
validate=True,
)
@@ -1628,11 +1629,16 @@
outstanding_invoices = []
negative_outstanding_invoices = []
+ if args.get("book_advance_payments_in_separate_party_account"):
+ party_account = get_party_account(args.get("party_type"), args.get("party"), args.get("company"))
+ else:
+ party_account = args.get("party_account")
+
if args.get("get_outstanding_invoices"):
outstanding_invoices = get_outstanding_invoices(
args.get("party_type"),
args.get("party"),
- get_party_account(args.get("party_type"), args.get("party"), args.get("company")),
+ party_account,
common_filter=common_filter,
posting_date=posting_and_due_date,
min_outstanding=args.get("outstanding_amt_greater_than"),
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 919e459..22b0d08 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -432,6 +432,9 @@
items = self.get("items") + (self.get("packed_items") or [])
for d in items:
+ if not frappe.get_cached_value("Item", d.item_code, "is_stock_item"):
+ continue
+
if not self.get("return_against") or (
get_valuation_method(d.item_code) == "Moving Average" and self.get("is_return")
):
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 0f80d5e..6efb893 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -489,6 +489,7 @@
"Payment Entry",
"Journal Entry",
"Purchase Invoice",
+ "Sales Invoice",
]
accounting_dimension_doctypes = [
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
index 6100756..ceb4406 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
+++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
@@ -117,7 +117,7 @@
self.update_amc_date(serial_nos, d.end_date)
no_email_sp = []
- if d.sales_person not in email_map:
+ if d.sales_person and d.sales_person not in email_map:
sp = frappe.get_doc("Sales Person", d.sales_person)
try:
email_map[d.sales_person] = sp.get_email_id()
@@ -131,12 +131,11 @@
).format(self.owner, "<br>" + "<br>".join(no_email_sp))
)
- scheduled_date = frappe.db.sql(
- """select scheduled_date from
- `tabMaintenance Schedule Detail` where sales_person=%s and item_code=%s and
- parent=%s""",
- (d.sales_person, d.item_code, self.name),
- as_dict=1,
+ scheduled_date = frappe.db.get_all(
+ "Maintenance Schedule Detail",
+ {"parent": self.name, "item_code": d.item_code},
+ ["scheduled_date"],
+ as_list=False,
)
for key in scheduled_date:
@@ -232,8 +231,6 @@
throw(_("Please select Start Date and End Date for Item {0}").format(d.item_code))
elif not d.no_of_visits:
throw(_("Please mention no of visits required"))
- elif not d.sales_person:
- throw(_("Please select a Sales Person for item: {0}").format(d.item_name))
if getdate(d.start_date) >= getdate(d.end_date):
throw(_("Start date should be less than end date for Item {0}").format(d.item_code))
@@ -452,20 +449,28 @@
def make_maintenance_visit(source_name, target_doc=None, item_name=None, s_id=None):
from frappe.model.mapper import get_mapped_doc
+ def condition(doc):
+ if s_id:
+ return doc.name == s_id
+ elif item_name:
+ return doc.item_name == item_name
+
+ return True
+
def update_status_and_detail(source, target, parent):
target.maintenance_type = "Scheduled"
- target.maintenance_schedule_detail = s_id
def update_serial(source, target, parent):
- if source.serial_and_batch_bundle:
- serial_nos = frappe.get_doc(
- "Serial and Batch Bundle", source.serial_and_batch_bundle
- ).get_serial_nos()
+ if source.item_reference:
+ if sbb := frappe.db.get_value(
+ "Maintenance Schedule Item", source.item_reference, "serial_and_batch_bundle"
+ ):
+ serial_nos = frappe.get_doc("Serial and Batch Bundle", sbb).get_serial_nos()
- if len(serial_nos) == 1:
- target.serial_no = serial_nos[0]
- else:
- target.serial_no = ""
+ if len(serial_nos) == 1:
+ target.serial_no = serial_nos[0]
+ else:
+ target.serial_no = ""
doclist = get_mapped_doc(
"Maintenance Schedule",
@@ -477,10 +482,13 @@
"validation": {"docstatus": ["=", 1]},
"postprocess": update_status_and_detail,
},
- "Maintenance Schedule Item": {
+ "Maintenance Schedule Detail": {
"doctype": "Maintenance Visit Purpose",
- "condition": lambda doc: doc.item_name == item_name if item_name else True,
- "field_map": {"sales_person": "service_person"},
+ "condition": condition,
+ "field_map": {
+ "sales_person": "service_person",
+ "name": "maintenance_schedule_detail",
+ },
"postprocess": update_serial,
},
},
diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py
index e7df484..d2511b8 100644
--- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py
+++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py
@@ -56,20 +56,39 @@
frappe.throw(_("Add Items in the Purpose Table"), title=_("Purposes Required"))
def validate_maintenance_date(self):
- if self.maintenance_type == "Scheduled" and self.maintenance_schedule_detail:
- item_ref = frappe.db.get_value(
- "Maintenance Schedule Detail", self.maintenance_schedule_detail, "item_reference"
- )
- if item_ref:
- start_date, end_date = frappe.db.get_value(
- "Maintenance Schedule Item", item_ref, ["start_date", "end_date"]
+ if self.maintenance_type == "Scheduled":
+ if self.maintenance_schedule_detail:
+ item_ref = frappe.db.get_value(
+ "Maintenance Schedule Detail", self.maintenance_schedule_detail, "item_reference"
)
- if get_datetime(self.mntc_date) < get_datetime(start_date) or get_datetime(
- self.mntc_date
- ) > get_datetime(end_date):
- frappe.throw(
- _("Date must be between {0} and {1}").format(format_date(start_date), format_date(end_date))
+ if item_ref:
+ start_date, end_date = frappe.db.get_value(
+ "Maintenance Schedule Item", item_ref, ["start_date", "end_date"]
)
+ if get_datetime(self.mntc_date) < get_datetime(start_date) or get_datetime(
+ self.mntc_date
+ ) > get_datetime(end_date):
+ frappe.throw(
+ _("Date must be between {0} and {1}").format(format_date(start_date), format_date(end_date))
+ )
+ else:
+ for purpose in self.purposes:
+ if purpose.maintenance_schedule_detail:
+ item_ref = frappe.db.get_value(
+ "Maintenance Schedule Detail", purpose.maintenance_schedule_detail, "item_reference"
+ )
+ if item_ref:
+ start_date, end_date = frappe.db.get_value(
+ "Maintenance Schedule Item", item_ref, ["start_date", "end_date"]
+ )
+ if get_datetime(self.mntc_date) < get_datetime(start_date) or get_datetime(
+ self.mntc_date
+ ) > get_datetime(end_date):
+ frappe.throw(
+ _("Date must be between {0} and {1}").format(
+ format_date(start_date), format_date(end_date)
+ )
+ )
def validate(self):
self.validate_serial_no()
@@ -82,6 +101,7 @@
if not cancel:
status = self.completion_status
actual_date = self.mntc_date
+
if self.maintenance_schedule_detail:
frappe.db.set_value(
"Maintenance Schedule Detail", self.maintenance_schedule_detail, "completion_status", status
@@ -89,6 +109,21 @@
frappe.db.set_value(
"Maintenance Schedule Detail", self.maintenance_schedule_detail, "actual_date", actual_date
)
+ else:
+ for purpose in self.purposes:
+ if purpose.maintenance_schedule_detail:
+ frappe.db.set_value(
+ "Maintenance Schedule Detail",
+ purpose.maintenance_schedule_detail,
+ "completion_status",
+ status,
+ )
+ frappe.db.set_value(
+ "Maintenance Schedule Detail",
+ purpose.maintenance_schedule_detail,
+ "actual_date",
+ actual_date,
+ )
def update_customer_issue(self, flag):
if not self.maintenance_schedule:
diff --git a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json
index ba05355..a5a63c4 100644
--- a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json
+++ b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json
@@ -17,7 +17,8 @@
"work_details",
"work_done",
"prevdoc_doctype",
- "prevdoc_docname"
+ "prevdoc_docname",
+ "maintenance_schedule_detail"
],
"fields": [
{
@@ -49,6 +50,8 @@
"options": "Serial No"
},
{
+ "fetch_from": "item_code.description",
+ "fetch_if_empty": 1,
"fieldname": "description",
"fieldtype": "Text Editor",
"in_list_view": 1,
@@ -56,7 +59,6 @@
"oldfieldname": "description",
"oldfieldtype": "Small Text",
"print_width": "300px",
- "reqd": 1,
"width": "300px"
},
{
@@ -103,12 +105,19 @@
{
"fieldname": "section_break_6",
"fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "maintenance_schedule_detail",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Maintenance Schedule Detail",
+ "options": "Maintenance Schedule Detail"
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2023-02-27 11:09:33.114458",
+ "modified": "2024-01-05 21:46:53.239830",
"modified_by": "Administrator",
"module": "Maintenance",
"name": "Maintenance Visit Purpose",
diff --git a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.py b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.py
index 3686941..1d4dab2 100644
--- a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.py
+++ b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.py
@@ -14,9 +14,10 @@
if TYPE_CHECKING:
from frappe.types import DF
- description: DF.TextEditor
+ description: DF.TextEditor | None
item_code: DF.Link | None
item_name: DF.Data | None
+ maintenance_schedule_detail: DF.Data | None
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index 3abd1d9..dae4289 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -1518,6 +1518,25 @@
"Stock Settings", "auto_create_serial_and_batch_bundle_for_outward", 0
)
+ def test_internal_transfer_for_non_stock_item(self):
+ from erpnext.selling.doctype.customer.test_customer import create_internal_customer
+ from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note
+
+ item = make_item(properties={"is_stock_item": 0}).name
+ warehouse = "_Test Warehouse - _TC"
+ target = "Stores - _TC"
+ company = "_Test Company"
+ customer = create_internal_customer(represents_company=company)
+ rate = 100
+
+ so = make_sales_order(item_code=item, qty=1, rate=rate, customer=customer, warehouse=warehouse)
+ dn = make_delivery_note(so.name)
+ dn.items[0].target_warehouse = target
+ dn.save().submit()
+
+ self.assertEqual(so.items[0].rate, rate)
+ self.assertEqual(dn.items[0].rate, so.items[0].rate)
+
def create_delivery_note(**args):
dn = frappe.new_doc("Delivery Note")
diff --git a/erpnext/translations/de.csv b/erpnext/translations/de.csv
index d05d0d9..84c71ba 100644
--- a/erpnext/translations/de.csv
+++ b/erpnext/translations/de.csv
@@ -600,7 +600,7 @@
Course Enrollment {0} does not exists,Die Kursanmeldung {0} existiert nicht,
Course Schedule,Kurstermine,
Course: ,Kurs:,
-Cr,Haben,
+Cr,H,
Create,Erstellen,
Create BOM,Stückliste anlegen,
Create Delivery Trip,Erstelle Auslieferungsfahrt,
@@ -3401,7 +3401,7 @@
Doctype,DocType,
Document {0} successfully uncleared,Dokument {0} wurde nicht erfolgreich gelöscht,
Download Template,Vorlage herunterladen,
-Dr,Soll,
+Dr,S,
Due Date,Fälligkeitsdatum,
Duplicate,Duplizieren,
Duplicate Project with Tasks,Projekt mit Aufgaben duplizieren,
@@ -7370,6 +7370,7 @@
Sample Retention Warehouse,Beispiel Retention Warehouse,
Default Valuation Method,Standard-Bewertungsmethode,
Show Barcode Field,Anzeigen Barcode-Feld,
+Show Balances in Chart Of Accounts,Saldo in Kontenplan anzeigen,
Convert Item Description to Clean HTML,Elementbeschreibung in HTML bereinigen,
Allow Negative Stock,Negativen Lagerbestand zulassen,
Automatically Set Serial Nos based on FIFO,Automatisch Seriennummern auf Basis FIFO einstellen,
@@ -8812,7 +8813,6 @@
Field Mapping,Feldzuordnung,
Not Specified,Keine Angabe,
Update Type,Aktualisierungsart,
-Dr,Soll,
End Time,Endzeit,
Fetching...,Abrufen ...,
"It seems that there is an issue with the server's stripe configuration. In case of failure, the amount will get refunded to your account.","Es scheint, dass ein Problem mit der Stripe-Konfiguration des Servers vorliegt. Im Falle eines Fehlers wird der Betrag Ihrem Konto gutgeschrieben.",
diff --git a/erpnext/utilities/bulk_transaction.py b/erpnext/utilities/bulk_transaction.py
index 679d5bd..9678488 100644
--- a/erpnext/utilities/bulk_transaction.py
+++ b/erpnext/utilities/bulk_transaction.py
@@ -15,18 +15,15 @@
length_of_data = len(deserialized_data)
- if length_of_data > 10:
- frappe.msgprint(
- _("Started a background job to create {1} {0}").format(to_doctype, length_of_data)
- )
- frappe.enqueue(
- job,
- deserialized_data=deserialized_data,
- from_doctype=from_doctype,
- to_doctype=to_doctype,
- )
- else:
- job(deserialized_data, from_doctype, to_doctype)
+ frappe.msgprint(
+ _("Started a background job to create {1} {0}").format(to_doctype, length_of_data)
+ )
+ frappe.enqueue(
+ job,
+ deserialized_data=deserialized_data,
+ from_doctype=from_doctype,
+ to_doctype=to_doctype,
+ )
@frappe.whitelist()