From 0faa7b04326db9f896d647d9dee5fa3b79f4051c Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 28 Jul 2022 11:57:27 +0530 Subject: [PATCH 01/27] fix: posting_date of linked vouchers should not affect outstanding posting_date filter should not be applied for linked vouchers. (cherry picked from commit 5f1562c5b21da32e7f963a8b052e0eb26b7e7684) --- .../accounts/doctype/payment_entry/payment_entry.py | 4 +++- .../payment_reconciliation.py | 12 ++++++++---- erpnext/accounts/utils.py | 13 ++++++++++++- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index af5a5e249d2..48edda90324 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -1184,6 +1184,7 @@ def get_outstanding_reference_documents(args): ple = qb.DocType("Payment Ledger Entry") common_filter = [] + posting_and_due_date = [] # confirm that Supplier is not blocked if args.get("party_type") == "Supplier": @@ -1224,7 +1225,7 @@ def get_outstanding_reference_documents(args): condition += " and {0} between '{1}' and '{2}'".format( fieldname, args.get(date_fields[0]), args.get(date_fields[1]) ) - common_filter.append(ple[fieldname][args.get(date_fields[0]) : args.get(date_fields[1])]) + posting_and_due_date.append(ple[fieldname][args.get(date_fields[0]) : args.get(date_fields[1])]) if args.get("company"): condition += " and company = {0}".format(frappe.db.escape(args.get("company"))) @@ -1235,6 +1236,7 @@ def get_outstanding_reference_documents(args): args.get("party"), args.get("party_account"), common_filter=common_filter, + posting_date=posting_and_due_date, min_outstanding=args.get("outstanding_amt_greater_than"), max_outstanding=args.get("outstanding_amt_less_than"), ) diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py index 5ed34d34a32..601fc87a227 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py @@ -22,6 +22,7 @@ class PaymentReconciliation(Document): def __init__(self, *args, **kwargs): super(PaymentReconciliation, self).__init__(*args, **kwargs) self.common_filter_conditions = [] + self.ple_posting_date_filter = [] @frappe.whitelist() def get_unreconciled_entries(self): @@ -150,6 +151,7 @@ class PaymentReconciliation(Document): return_outstanding = ple_query.get_voucher_outstandings( vouchers=return_invoices, common_filter=self.common_filter_conditions, + posting_date=self.ple_posting_date_filter, min_outstanding=-(self.minimum_payment_amount) if self.minimum_payment_amount else None, max_outstanding=-(self.maximum_payment_amount) if self.maximum_payment_amount else None, get_payments=True, @@ -187,6 +189,7 @@ class PaymentReconciliation(Document): self.party, self.receivable_payable_account, common_filter=self.common_filter_conditions, + posting_date=self.ple_posting_date_filter, min_outstanding=self.minimum_invoice_amount if self.minimum_invoice_amount else None, max_outstanding=self.maximum_invoice_amount if self.maximum_invoice_amount else None, ) @@ -350,6 +353,7 @@ class PaymentReconciliation(Document): def build_qb_filter_conditions(self, get_invoices=False, get_return_invoices=False): self.common_filter_conditions.clear() + self.ple_posting_date_filter.clear() ple = qb.DocType("Payment Ledger Entry") self.common_filter_conditions.append(ple.company == self.company) @@ -359,15 +363,15 @@ class PaymentReconciliation(Document): if get_invoices: if self.from_invoice_date: - self.common_filter_conditions.append(ple.posting_date.gte(self.from_invoice_date)) + self.ple_posting_date_filter.append(ple.posting_date.gte(self.from_invoice_date)) if self.to_invoice_date: - self.common_filter_conditions.append(ple.posting_date.lte(self.to_invoice_date)) + self.ple_posting_date_filter.append(ple.posting_date.lte(self.to_invoice_date)) elif get_return_invoices: if self.from_payment_date: - self.common_filter_conditions.append(ple.posting_date.gte(self.from_payment_date)) + self.ple_posting_date_filter.append(ple.posting_date.gte(self.from_payment_date)) if self.to_payment_date: - self.common_filter_conditions.append(ple.posting_date.lte(self.to_payment_date)) + self.ple_posting_date_filter.append(ple.posting_date.lte(self.to_payment_date)) def get_conditions(self, get_payments=False): condition = " and company = '{0}' ".format(self.company) diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 9dafef74f4a..018e8f9301a 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -823,7 +823,13 @@ def get_held_invoices(party_type, party): def get_outstanding_invoices( - party_type, party, account, common_filter=None, min_outstanding=None, max_outstanding=None + party_type, + party, + account, + common_filter=None, + posting_date=None, + min_outstanding=None, + max_outstanding=None, ): ple = qb.DocType("Payment Ledger Entry") @@ -850,6 +856,7 @@ def get_outstanding_invoices( ple_query = QueryPaymentLedger() invoice_list = ple_query.get_voucher_outstandings( common_filter=common_filter, + posting_date=posting_date, min_outstanding=min_outstanding, max_outstanding=max_outstanding, get_invoices=True, @@ -1501,6 +1508,7 @@ class QueryPaymentLedger(object): # query filters self.vouchers = [] self.common_filter = [] + self.voucher_posting_date = [] self.min_outstanding = None self.max_outstanding = None @@ -1571,6 +1579,7 @@ class QueryPaymentLedger(object): .where(ple.delinked == 0) .where(Criterion.all(filter_on_voucher_no)) .where(Criterion.all(self.common_filter)) + .where(Criterion.all(self.voucher_posting_date)) .groupby(ple.voucher_type, ple.voucher_no, ple.party_type, ple.party) ) @@ -1652,6 +1661,7 @@ class QueryPaymentLedger(object): self, vouchers=None, common_filter=None, + posting_date=None, min_outstanding=None, max_outstanding=None, get_payments=False, @@ -1671,6 +1681,7 @@ class QueryPaymentLedger(object): self.reset() self.vouchers = vouchers self.common_filter = common_filter or [] + self.voucher_posting_date = posting_date or [] self.min_outstanding = min_outstanding self.max_outstanding = max_outstanding self.get_payments = get_payments From 80bf47170f222c852c0efb3131d32bb10520462f Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 29 Jul 2022 15:05:01 +0530 Subject: [PATCH 02/27] test: posting_date should not affect outstanding amount calculation (cherry picked from commit ef312b8fc46355197a9a9502dd2ade697635fe77) --- .../test_payment_reconciliation.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py index 625382a3e94..dae029b4084 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py +++ b/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py @@ -283,6 +283,41 @@ class TestPaymentReconciliation(FrappeTestCase): self.assertEqual(len(pr.get("invoices")), 2) self.assertEqual(len(pr.get("payments")), 2) + def test_filter_posting_date_case2(self): + """ + Posting date should not affect outstanding amount calculation + """ + + from_date = add_days(nowdate(), -30) + to_date = nowdate() + self.create_payment_entry(amount=25, posting_date=from_date).submit() + self.create_sales_invoice(rate=25, qty=1, posting_date=to_date) + + pr = self.create_payment_reconciliation() + pr.from_invoice_date = pr.from_payment_date = from_date + pr.to_invoice_date = pr.to_payment_date = to_date + pr.get_unreconciled_entries() + + self.assertEqual(len(pr.invoices), 1) + self.assertEqual(len(pr.payments), 1) + + invoices = [x.as_dict() for x in pr.invoices] + payments = [x.as_dict() for x in pr.payments] + pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments})) + pr.reconcile() + + pr.get_unreconciled_entries() + + self.assertEqual(len(pr.invoices), 0) + self.assertEqual(len(pr.payments), 0) + + pr.from_invoice_date = pr.from_payment_date = to_date + pr.to_invoice_date = pr.to_payment_date = to_date + + pr.get_unreconciled_entries() + + self.assertEqual(len(pr.invoices), 0) + def test_filter_invoice_limit(self): # check filter condition - invoice limit transaction_date = nowdate() From 82f1dd268d47c5baebc34770e339cdc1f25a9eb2 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sun, 14 Aug 2022 16:00:54 +0530 Subject: [PATCH 03/27] fix: check item_code in all rows of po_items (backport #31741) (#31842) fix: check item_code in all rows of po_items (#31741) fix: check the item code in each row of PO items (cherry picked from commit 0047e18a9b121e45798f7b7a6345feef85ee7c01) Co-authored-by: Sagar Sharma --- .../manufacturing/doctype/production_plan/production_plan.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index 70ccb782785..46e820542b9 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -639,6 +639,9 @@ class ProductionPlan(Document): sub_assembly_items_store = [] # temporary store to process all subassembly items for row in self.po_items: + if not row.item_code: + frappe.throw(_("Row #{0}: Please select Item Code in Assembly Items").format(row.idx)) + bom_data = [] get_sub_assembly_items(row.bom_no, bom_data, row.planned_qty) self.set_sub_assembly_items_based_on_level(row, bom_data, manufacturing_type) From 74664a34c0b24b71aeb9169f51b39f01f1791af2 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 12:19:59 +0530 Subject: [PATCH 04/27] fix: contact search in request for quotation (backport #31828) (#31840) fix: contact search in request for quotation (#31828) (cherry picked from commit e5e88bb9f1728ce85aecda7a305dd70378c5099e) Co-authored-by: Sagar Sharma --- .../request_for_quotation/request_for_quotation.js | 9 ++++++--- .../request_for_quotation/request_for_quotation.py | 12 ------------ 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js index 4e29ee53eaf..31a4837d463 100644 --- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js @@ -15,9 +15,12 @@ frappe.ui.form.on("Request for Quotation",{ frm.fields_dict["suppliers"].grid.get_field("contact").get_query = function(doc, cdt, cdn) { let d = locals[cdt][cdn]; return { - query: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.get_supplier_contacts", - filters: {'supplier': d.supplier} - } + query: "frappe.contacts.doctype.contact.contact.contact_query", + filters: { + link_doctype: "Supplier", + link_name: d.supplier || "" + } + }; } }, diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py index 3ef57bb70ff..ee28eb6ce2d 100644 --- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py @@ -286,18 +286,6 @@ def get_list_context(context=None): return list_context -@frappe.whitelist() -@frappe.validate_and_sanitize_search_inputs -def get_supplier_contacts(doctype, txt, searchfield, start, page_len, filters): - return frappe.db.sql( - """select `tabContact`.name from `tabContact`, `tabDynamic Link` - where `tabDynamic Link`.link_doctype = 'Supplier' and (`tabDynamic Link`.link_name=%(name)s - and `tabDynamic Link`.link_name like %(txt)s) and `tabContact`.name = `tabDynamic Link`.parent - limit %(page_len)s offset %(start)s""", - {"start": start, "page_len": page_len, "txt": "%%%s%%" % txt, "name": filters.get("supplier")}, - ) - - @frappe.whitelist() def make_supplier_quotation_from_rfq(source_name, target_doc=None, for_supplier=None): def postprocess(source, target_doc): From 010a0ca0a9cecae9341b74e8e31dcde151d9aac1 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 17 Aug 2022 13:46:33 +0530 Subject: [PATCH 05/27] fix: incorrect produced-qty in production-plan-item (backport #31706) (#31861) fix: incorrect produced-qty in production-plan-item (#31706) (cherry picked from commit 538cd6fdcf2cc627515b7effd0e98f3538a7a11a) Co-authored-by: Sagar Sharma --- .../production_plan/production_plan.py | 1 - .../production_plan/test_production_plan.py | 60 ++++++++++++++++--- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index 46e820542b9..2cdf8d3ea9f 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -482,7 +482,6 @@ class ProductionPlan(Document): "bom_no", "stock_uom", "bom_level", - "production_plan_item", "schedule_date", ]: if row.get(field): diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index 040e791e00a..e2415ad848e 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -11,8 +11,9 @@ from erpnext.manufacturing.doctype.production_plan.production_plan import ( get_warehouse_list, ) from erpnext.manufacturing.doctype.work_order.work_order import OverProductionError +from erpnext.manufacturing.doctype.work_order.work_order import make_stock_entry as make_se_from_wo from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order -from erpnext.stock.doctype.item.test_item import create_item +from erpnext.stock.doctype.item.test_item import create_item, make_item from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import ( create_stock_reconciliation, @@ -583,9 +584,6 @@ class TestProductionPlan(FrappeTestCase): Test Prod Plan impact via: SO -> Prod Plan -> WO -> SE -> SE (cancel) """ from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record - from erpnext.manufacturing.doctype.work_order.work_order import ( - make_stock_entry as make_se_from_wo, - ) make_stock_entry( item_code="Raw Material Item 1", target="Work In Progress - _TC", qty=2, basic_rate=100 @@ -629,9 +627,6 @@ class TestProductionPlan(FrappeTestCase): def test_production_plan_pending_qty_independent_items(self): "Test Prod Plan impact if items are added independently (no from SO or MR)." from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record - from erpnext.manufacturing.doctype.work_order.work_order import ( - make_stock_entry as make_se_from_wo, - ) make_stock_entry( item_code="Raw Material Item 1", target="Work In Progress - _TC", qty=2, basic_rate=100 @@ -728,6 +723,57 @@ class TestProductionPlan(FrappeTestCase): for po_item, subassy_item in zip(pp.po_items, pp.sub_assembly_items): self.assertEqual(po_item.name, subassy_item.production_plan_item) + def test_produced_qty_for_multi_level_bom_item(self): + # Create Items and BOMs + rm_item = make_item(properties={"is_stock_item": 1}).name + sub_assembly_item = make_item(properties={"is_stock_item": 1}).name + fg_item = make_item(properties={"is_stock_item": 1}).name + + make_stock_entry( + item_code=rm_item, + qty=60, + to_warehouse="Work In Progress - _TC", + rate=99, + purpose="Material Receipt", + ) + + make_bom(item=sub_assembly_item, raw_materials=[rm_item], rm_qty=3) + make_bom(item=fg_item, raw_materials=[sub_assembly_item], rm_qty=4) + + # Step - 1: Create Production Plan + pln = create_production_plan(item_code=fg_item, planned_qty=5, skip_getting_mr_items=1) + pln.get_sub_assembly_items() + + # Step - 2: Create Work Orders + pln.make_work_order() + work_orders = frappe.get_all("Work Order", filters={"production_plan": pln.name}, pluck="name") + sa_wo = fg_wo = None + for work_order in work_orders: + wo_doc = frappe.get_doc("Work Order", work_order) + if wo_doc.production_plan_item: + wo_doc.update( + {"wip_warehouse": "Work In Progress - _TC", "fg_warehouse": "Finished Goods - _TC"} + ) + fg_wo = wo_doc.name + else: + wo_doc.update( + {"wip_warehouse": "Work In Progress - _TC", "fg_warehouse": "Work In Progress - _TC"} + ) + sa_wo = wo_doc.name + wo_doc.submit() + + # Step - 3: Complete Work Orders + se = frappe.get_doc(make_se_from_wo(sa_wo, "Manufacture")) + se.submit() + + se = frappe.get_doc(make_se_from_wo(fg_wo, "Manufacture")) + se.submit() + + # Step - 4: Check Production Plan Item Produced Qty + pln.load_from_db() + self.assertEqual(pln.status, "Completed") + self.assertEqual(pln.po_items[0].produced_qty, 5) + def create_production_plan(**args): """ From abe18945a60594b01f926b2073b736a56ab043fc Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 17 Aug 2022 14:37:40 +0530 Subject: [PATCH 06/27] fix: incorrect rate in BOM exploded items (backport #31513) (#31864) fix: incorrect rate in BOM exploded items (#31513) (cherry picked from commit 313625c3497d7db2d86a2835c458ac1028c27fe8) Co-authored-by: Sagar Sharma --- erpnext/manufacturing/doctype/bom/bom.py | 2 +- erpnext/manufacturing/doctype/bom/test_bom.py | 28 +++++++++++++++++++ .../doctype/bom_item/bom_item.json | 3 +- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index b29f6710e17..70637d3ef20 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -189,8 +189,8 @@ class BOM(WebsiteGenerator): self.validate_transfer_against() self.set_routing_operations() self.validate_operations() - self.update_exploded_items(save=False) self.calculate_cost() + self.update_exploded_items(save=False) self.update_stock_qty() self.update_cost(update_parent=False, from_child_bom=True, update_hour_rate=False, save=False) self.validate_scrap_items() diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py index a190cc7430b..27f3cc905b9 100644 --- a/erpnext/manufacturing/doctype/bom/test_bom.py +++ b/erpnext/manufacturing/doctype/bom/test_bom.py @@ -611,6 +611,34 @@ class TestBOM(FrappeTestCase): bom.reload() self.assertEqual(frappe.get_value("Item", fg_item.item_code, "default_bom"), bom.name) + def test_exploded_items_rate(self): + rm_item = make_item( + properties={"is_stock_item": 1, "valuation_rate": 99, "last_purchase_rate": 89} + ).name + fg_item = make_item(properties={"is_stock_item": 1}).name + + from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom + + bom = make_bom(item=fg_item, raw_materials=[rm_item], do_not_save=True) + + bom.rm_cost_as_per = "Last Purchase Rate" + bom.save() + self.assertEqual(bom.items[0].base_rate, 89) + self.assertEqual(bom.exploded_items[0].rate, bom.items[0].base_rate) + + bom.rm_cost_as_per = "Price List" + bom.save() + self.assertEqual(bom.items[0].base_rate, 0.0) + self.assertEqual(bom.exploded_items[0].rate, bom.items[0].base_rate) + + bom.rm_cost_as_per = "Valuation Rate" + bom.save() + self.assertEqual(bom.items[0].base_rate, 99) + self.assertEqual(bom.exploded_items[0].rate, bom.items[0].base_rate) + + bom.submit() + self.assertEqual(bom.exploded_items[0].rate, bom.items[0].base_rate) + def get_default_bom(item_code="_Test FG Item 2"): return frappe.db.get_value("BOM", {"item": item_code, "is_active": 1, "is_default": 1}) diff --git a/erpnext/manufacturing/doctype/bom_item/bom_item.json b/erpnext/manufacturing/doctype/bom_item/bom_item.json index 0a8ae7b4a73..c5266119dc2 100644 --- a/erpnext/manufacturing/doctype/bom_item/bom_item.json +++ b/erpnext/manufacturing/doctype/bom_item/bom_item.json @@ -184,6 +184,7 @@ "in_list_view": 1, "label": "Rate", "options": "currency", + "read_only": 1, "reqd": 1 }, { @@ -288,7 +289,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2022-05-19 02:32:43.785470", + "modified": "2022-07-28 10:20:51.559010", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM Item", From ce5fc5b457b6168ce6d1c591d808a9d3903e210f Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 17 Aug 2022 13:48:56 +0530 Subject: [PATCH 07/27] fix: not able to issue expired batches (cherry picked from commit 795c94384a5dd8919b0dc989e19d8b9ee81071d4) --- erpnext/controllers/stock_controller.py | 14 +++++++++- erpnext/stock/doctype/batch/test_batch.py | 8 +++++- .../doctype/stock_entry/test_stock_entry.py | 27 ++++++++++++++++++- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index e27718a9b4c..f9fc5f60bbc 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -36,6 +36,10 @@ class QualityInspectionNotSubmittedError(frappe.ValidationError): pass +class BatchExpiredError(frappe.ValidationError): + pass + + class StockController(AccountsController): def validate(self): super(StockController, self).validate() @@ -77,6 +81,10 @@ class StockController(AccountsController): def validate_serialized_batch(self): from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos + is_material_issue = False + if self.doctype == "Stock Entry" and self.purpose == "Material Issue": + is_material_issue = True + for d in self.get("items"): if hasattr(d, "serial_no") and hasattr(d, "batch_no") and d.serial_no and d.batch_no: serial_nos = frappe.get_all( @@ -93,6 +101,9 @@ class StockController(AccountsController): ) ) + if is_material_issue: + continue + if flt(d.qty) > 0.0 and d.get("batch_no") and self.get("posting_date") and self.docstatus < 2: expiry_date = frappe.get_cached_value("Batch", d.get("batch_no"), "expiry_date") @@ -100,7 +111,8 @@ class StockController(AccountsController): frappe.throw( _("Row #{0}: The batch {1} has already expired.").format( d.idx, get_link_to_form("Batch", d.get("batch_no")) - ) + ), + BatchExpiredError, ) def clean_serial_nos(self): diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py index 3e470d4ce4e..271e2e02984 100644 --- a/erpnext/stock/doctype/batch/test_batch.py +++ b/erpnext/stock/doctype/batch/test_batch.py @@ -473,7 +473,13 @@ def make_new_batch(**args): "doctype": "Batch", "batch_id": args.batch_id, "item": args.item_code, + "expiry_date": args.expiry_date, } - ).insert() + ) + + if args.expiry_date: + batch.expiry_date = args.expiry_date + + batch.insert() return batch diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py index a2f99786700..b574b718fe1 100644 --- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py @@ -5,7 +5,7 @@ import frappe from frappe.permissions import add_user_permission, remove_user_permission from frappe.tests.utils import FrappeTestCase, change_settings -from frappe.utils import add_days, flt, nowdate, nowtime +from frappe.utils import add_days, flt, nowdate, nowtime, today from erpnext.accounts.doctype.account.test_account import get_inventory_account from erpnext.stock.doctype.item.test_item import ( @@ -1589,6 +1589,31 @@ class TestStockEntry(FrappeTestCase): self.assertEqual(obj.items[index].basic_rate, 200) self.assertEqual(obj.items[index].basic_amount, 2000) + def test_batch_expiry(self): + from erpnext.controllers.stock_controller import BatchExpiredError + from erpnext.stock.doctype.batch.test_batch import make_new_batch + + item_code = "Test Batch Expiry Test Item - 001" + item_doc = create_item(item_code=item_code, is_stock_item=1, valuation_rate=10) + + item_doc.has_batch_no = 1 + item_doc.save() + + batch = make_new_batch( + batch_id=frappe.generate_hash("", 5), item_code=item_doc.name, expiry_date=add_days(today(), -1) + ) + + se = make_stock_entry( + item_code=item_code, + purpose="Material Receipt", + qty=4, + to_warehouse="_Test Warehouse - _TC", + batch_no=batch.name, + do_not_save=True, + ) + + self.assertRaises(BatchExpiredError, se.save) + def make_serialized_item(**args): args = frappe._dict(args) From 354a9d616960e68d6d79b50568d03f55a1f0d85e Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 17 Aug 2022 11:56:13 +0530 Subject: [PATCH 08/27] fix: delete custom fields on deletion of inventory dimension (cherry picked from commit 0b39a0123e2e696007bbe196dad490d4534be610) --- erpnext/controllers/stock_controller.py | 17 +++- .../inventory_dimension.js | 31 +++++++- .../inventory_dimension.json | 15 +++- .../inventory_dimension.py | 78 ++++++++++++++----- .../test_inventory_dimension.py | 27 +++++++ 5 files changed, 143 insertions(+), 25 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index f9fc5f60bbc..49f85cdba57 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -386,9 +386,24 @@ class StockController(AccountsController): def update_inventory_dimensions(self, row, sl_dict) -> None: dimensions = get_evaluated_inventory_dimension(row, sl_dict, parent_doc=self) for dimension in dimensions: - if dimension and row.get(dimension.source_fieldname): + if not dimension: + continue + + if row.get(dimension.source_fieldname): sl_dict[dimension.target_fieldname] = row.get(dimension.source_fieldname) + if not sl_dict.get(dimension.target_fieldname) and dimension.fetch_from_parent: + sl_dict[dimension.target_fieldname] = self.get(dimension.fetch_from_parent) + + # Get value based on doctype name + if not sl_dict.get(dimension.target_fieldname): + fieldname = frappe.get_cached_value( + "DocField", {"parent": self.doctype, "options": dimension.fetch_from_parent}, "fieldname" + ) + + if fieldname and self.get(fieldname): + sl_dict[dimension.target_fieldname] = self.get(fieldname) + def make_sl_entries(self, sl_entries, allow_negative_stock=False, via_landed_cost_voucher=False): from erpnext.stock.stock_ledger import make_sl_entries diff --git a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.js b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.js index 91a21f4e722..07cb73b1d56 100644 --- a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.js +++ b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.js @@ -35,14 +35,39 @@ frappe.ui.form.on('Inventory Dimension', { refresh(frm) { if (frm.doc.__onload && frm.doc.__onload.has_stock_ledger && frm.doc.__onload.has_stock_ledger.length) { - let msg = __('Stock transactions exists against this dimension, user can not update document.'); - frm.dashboard.add_comment(msg, 'blue', true); + let allow_to_edit_fields = ['disabled', 'fetch_from_parent', + 'type_of_transaction', 'condition']; frm.fields.forEach((field) => { - if (field.df.fieldname !== 'disabled') { + if (!in_list(allow_to_edit_fields, field.df.fieldname)) { frm.set_df_property(field.df.fieldname, "read_only", "1"); } }); } + + if (!frm.is_new()) { + frm.add_custom_button(__('Delete Dimension'), () => { + frm.trigger('delete_dimension'); + }); + } + }, + + delete_dimension(frm) { + let msg = (` + Custom fields related to this dimension will be deleted on deletion of dimension. +
Do you want to delete {0} dimension? + `); + + frappe.confirm(__(msg, [frm.doc.name.bold()]), () => { + frappe.call({ + method: 'erpnext.stock.doctype.inventory_dimension.inventory_dimension.delete_dimension', + args: { + dimension: frm.doc.name + }, + callback: function() { + frappe.set_route('List', 'Inventory Dimension'); + } + }); + }); } }); diff --git a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.json b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.json index 8b334d13d7d..03e7fda8411 100644 --- a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.json +++ b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.json @@ -1,6 +1,5 @@ { "actions": [], - "allow_rename": 1, "autoname": "field:dimension_name", "creation": "2022-06-17 13:04:16.554051", "doctype": "DocType", @@ -22,6 +21,7 @@ "document_type", "istable", "type_of_transaction", + "fetch_from_parent", "column_break_16", "condition", "applicable_condition_example_section", @@ -101,12 +101,14 @@ "fieldname": "target_fieldname", "fieldtype": "Data", "label": "Target Fieldname (Stock Ledger Entry)", + "no_copy": 1, "read_only": 1 }, { "fieldname": "source_fieldname", "fieldtype": "Data", "label": "Source Fieldname", + "no_copy": 1, "read_only": 1 }, { @@ -123,7 +125,7 @@ "fieldname": "type_of_transaction", "fieldtype": "Select", "label": "Type of Transaction", - "options": "\nInward\nOutward" + "options": "\nInward\nOutward\nBoth" }, { "fieldname": "html_19", @@ -140,11 +142,18 @@ { "fieldname": "column_break_4", "fieldtype": "Column Break" + }, + { + "depends_on": "istable", + "description": "Set fieldname or DocType name like Supplier, Customer etc.", + "fieldname": "fetch_from_parent", + "fieldtype": "Data", + "label": "Fetch Value From Parent Form" } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2022-07-19 21:06:11.824976", + "modified": "2022-08-17 11:43:24.722441", "modified_by": "Administrator", "module": "Stock", "name": "Inventory Dimension", diff --git a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py index 5a9541f060a..4ff8f33b409 100644 --- a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py +++ b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py @@ -43,13 +43,37 @@ class InventoryDimension(Document): return old_doc = self._doc_before_save + allow_to_edit_fields = [ + "disabled", + "fetch_from_parent", + "type_of_transaction", + "condition", + ] + for field in frappe.get_meta("Inventory Dimension").fields: - if field.fieldname != "disabled" and old_doc.get(field.fieldname) != self.get(field.fieldname): + if field.fieldname not in allow_to_edit_fields and old_doc.get(field.fieldname) != self.get( + field.fieldname + ): msg = f"""The user can not change value of the field {bold(field.label)} because stock transactions exists against the dimension {bold(self.name)}.""" frappe.throw(_(msg), DoNotChangeError) + def on_trash(self): + self.delete_custom_fields() + + def delete_custom_fields(self): + filters = {"fieldname": self.source_fieldname} + + if self.document_type: + filters["dt"] = self.document_type + + for field in frappe.get_all("Custom Field", filters=filters): + frappe.delete_doc("Custom Field", field.name) + + msg = f"Deleted custom fields related to the dimension {self.name}" + frappe.msgprint(_(msg)) + def reset_value(self): if self.apply_to_all_doctypes: self.istable = 0 @@ -76,30 +100,35 @@ class InventoryDimension(Document): self.add_custom_fields() def add_custom_fields(self): - dimension_field = dict( - fieldname=self.source_fieldname, - fieldtype="Link", - insert_after="warehouse", - options=self.reference_document, - label=self.dimension_name, - ) + dimension_fields = [ + dict( + fieldname="inventory_dimension", + fieldtype="Section Break", + insert_after="warehouse", + label="Inventory Dimension", + collapsible=1, + ), + dict( + fieldname=self.source_fieldname, + fieldtype="Link", + insert_after="inventory_dimension", + options=self.reference_document, + label=self.dimension_name, + ), + ] custom_fields = {} if self.apply_to_all_doctypes: for doctype in get_inventory_documents(): - if not frappe.db.get_value( - "Custom Field", {"dt": doctype[0], "fieldname": self.source_fieldname} - ): - custom_fields.setdefault(doctype[0], dimension_field) - elif not frappe.db.get_value( - "Custom Field", {"dt": self.document_type, "fieldname": self.source_fieldname} - ): - custom_fields.setdefault(self.document_type, dimension_field) + custom_fields.setdefault(doctype[0], dimension_fields) + else: + custom_fields.setdefault(self.document_type, dimension_fields) if not frappe.db.get_value( "Custom Field", {"dt": "Stock Ledger Entry", "fieldname": self.target_fieldname} ): + dimension_field = dimension_fields[1] dimension_field["fieldname"] = self.target_fieldname custom_fields["Stock Ledger Entry"] = dimension_field @@ -143,7 +172,7 @@ def get_evaluated_inventory_dimension(doc, sl_dict, parent_doc=None): elif ( row.type_of_transaction == "Outward" if doc.docstatus == 1 - else row.type_of_transaction != "Inward" + else row.type_of_transaction != "Outward" ) and sl_dict.actual_qty > 0: continue @@ -166,7 +195,14 @@ def get_document_wise_inventory_dimensions(doctype) -> dict: if not frappe.local.document_wise_inventory_dimensions.get(doctype): dimensions = frappe.get_all( "Inventory Dimension", - fields=["name", "source_fieldname", "condition", "target_fieldname", "type_of_transaction"], + fields=[ + "name", + "source_fieldname", + "condition", + "target_fieldname", + "type_of_transaction", + "fetch_from_parent", + ], filters={"disabled": 0}, or_filters={"document_type": doctype, "apply_to_all_doctypes": 1}, ) @@ -194,3 +230,9 @@ def get_inventory_dimensions(): frappe.local.inventory_dimensions = dimensions return frappe.local.inventory_dimensions + + +@frappe.whitelist() +def delete_dimension(dimension): + doc = frappe.get_doc("Inventory Dimension", dimension) + doc.delete() diff --git a/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py b/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py index 998a0e9d6a6..cc90b74ee85 100644 --- a/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py +++ b/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py @@ -8,6 +8,7 @@ from erpnext.stock.doctype.inventory_dimension.inventory_dimension import ( CanNotBeChildDoc, CanNotBeDefaultDimension, DoNotChangeError, + delete_dimension, ) from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse @@ -42,6 +43,32 @@ class TestInventoryDimension(FrappeTestCase): self.assertRaises(CanNotBeDefaultDimension, inv_dim1.insert) + def test_delete_inventory_dimension(self): + inv_dim1 = create_inventory_dimension( + reference_document="Shelf", + type_of_transaction="Outward", + dimension_name="From Shelf", + apply_to_all_doctypes=0, + document_type="Stock Entry Detail", + condition="parent.purpose == 'Material Issue'", + ) + + inv_dim1.save() + + custom_field = frappe.db.get_value( + "Custom Field", {"fieldname": "from_shelf", "dt": "Stock Entry Detail"}, "name" + ) + + self.assertTrue(custom_field) + + delete_dimension(inv_dim1.name) + + custom_field = frappe.db.get_value( + "Custom Field", {"fieldname": "from_shelf", "dt": "Stock Entry Detail"}, "name" + ) + + self.assertFalse(custom_field) + def test_inventory_dimension(self): warehouse = "Shelf Warehouse - _TC" item_code = "_Test Item" From aa5aaa113eaecc7b0ae9df1bb1d4ce20e7ce18a4 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 17 Aug 2022 16:31:18 +0530 Subject: [PATCH 09/27] fix: Make expense account editable in Subcontracting Receipt Item (backport #31848) (#31870) fix: Make expense account editable in Subcontracting Receipt Item (#31848) (cherry picked from commit 2d04e7141271eaded41d53bbc9a22b37fbd5816f) Co-authored-by: Sagar Sharma --- erpnext/controllers/stock_controller.py | 8 +++++++- .../subcontracting_receipt.js | 7 +++++++ .../subcontracting_receipt_item.json | 14 +++++++++----- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index f9fc5f60bbc..900e34e27f9 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -322,7 +322,13 @@ class StockController(AccountsController): ) if ( self.doctype - not in ("Purchase Receipt", "Purchase Invoice", "Stock Reconciliation", "Stock Entry") + not in ( + "Purchase Receipt", + "Purchase Invoice", + "Stock Reconciliation", + "Stock Entry", + "Subcontracting Receipt", + ) and not is_expense_account ): frappe.throw( diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js index b2506cd143d..35fec8bc33c 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js @@ -48,6 +48,13 @@ frappe.ui.form.on('Subcontracting Receipt', { is_group: 0 } })); + + frm.set_query("expense_account", "items", function () { + return { + query: "erpnext.controllers.queries.get_expense_account", + filters: { 'company': frm.doc.company } + }; + }); }, refresh: (frm) => { diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json index e2785ce0cdd..bf15f0f6882 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json +++ b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json @@ -49,11 +49,12 @@ "col_break5", "batch_no", "rejected_serial_no", - "expense_account", "manufacture_details", "manufacturer", "column_break_16", "manufacturer_part_no", + "accounting_details_section", + "expense_account", "accounting_dimensions_section", "project", "dimension_col_break", @@ -363,10 +364,8 @@ { "fieldname": "expense_account", "fieldtype": "Link", - "hidden": 1, "label": "Expense Account", - "options": "Account", - "read_only": 1 + "options": "Account" }, { "collapsible": 1, @@ -456,12 +455,17 @@ "no_copy": 1, "print_hide": 1, "read_only": 1 + }, + { + "fieldname": "accounting_details_section", + "fieldtype": "Section Break", + "label": "Accounting Details" } ], "idx": 1, "istable": 1, "links": [], - "modified": "2022-04-21 12:07:55.899701", + "modified": "2022-08-15 11:34:00.970042", "modified_by": "Administrator", "module": "Subcontracting", "name": "Subcontracting Receipt Item", From 04d3571dd9989d2716da49174a028d2db86cd628 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 17 Aug 2022 17:26:15 +0530 Subject: [PATCH 10/27] fix: Transit filter for Default Target Warehouse in SE (backport #31839) (#31873) fix: Transit filter for Default Target Warehouse in SE (#31839) (cherry picked from commit f1a612245c05aa56f7654694495d4ec5b9d3d8b9) Co-authored-by: Sagar Sharma --- .../stock/doctype/stock_entry/stock_entry.js | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index 1c514a90eee..e3a8438d95c 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -583,18 +583,23 @@ frappe.ui.form.on('Stock Entry', { }, add_to_transit: function(frm) { - if(frm.doc.add_to_transit && frm.doc.purpose=='Material Transfer') { - frm.set_value('to_warehouse', ''); + if(frm.doc.purpose=='Material Transfer') { + var filters = { + 'is_group': 0, + 'company': frm.doc.company + } + + if(frm.doc.add_to_transit){ + filters['warehouse_type'] = 'Transit'; + frm.set_value('to_warehouse', ''); + frm.trigger('set_transit_warehouse'); + } + frm.fields_dict.to_warehouse.get_query = function() { return { - filters:{ - 'warehouse_type' : 'Transit', - 'is_group': 0, - 'company': frm.doc.company - } + filters:filters }; }; - frm.trigger('set_transit_warehouse'); } }, From b637d4d5f167160b30ef3d97fbe8f82787a015f5 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 18 Aug 2022 11:16:15 +0530 Subject: [PATCH 11/27] fix: Make expense account editable in Purchase Receipt Item (backport #31730) (#31878) fix: Make expense account editable in Purchase Receipt Item (#31730) Co-authored-by: Sagar Sharma (cherry picked from commit 1a6508972e3555aabd06d93a46af9cc513e32819) Co-authored-by: Deepesh Garg --- .../purchase_receipt_item/purchase_receipt_item.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json index c97dbee9114..39833b5e910 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json @@ -792,10 +792,8 @@ { "fieldname": "expense_account", "fieldtype": "Link", - "hidden": 1, "label": "Expense Account", - "options": "Account", - "read_only": 1 + "options": "Account" }, { "fieldname": "accounting_dimensions_section", @@ -1001,7 +999,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2022-06-17 05:32:16.483178", + "modified": "2022-07-28 19:27:54.880781", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt Item", From 623f56a95cf7af12621efeba1cfcde9ae6276368 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 17 Aug 2022 18:21:43 +0530 Subject: [PATCH 12/27] fix(projects): Add missing comma Added with https://github.com/frappe/erpnext/pull/31360 (cherry picked from commit d38778e40086d31593d3d34f926d9aa4324c963c) --- erpnext/projects/doctype/project/project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py index e78e4b65778..a2be9367688 100644 --- a/erpnext/projects/doctype/project/project.py +++ b/erpnext/projects/doctype/project/project.py @@ -379,7 +379,7 @@ def get_users_for_project(doctype, txt, searchfield, start, page_len, filters): {fcond} {mcond} order by (case when locate(%(_txt)s, name) > 0 then locate(%(_txt)s, name) else 99999 end), - (case when locate(%(_txt)s, full_name) > 0 then locate(%(_txt)s, full_name) else 99999 end) + (case when locate(%(_txt)s, full_name) > 0 then locate(%(_txt)s, full_name) else 99999 end), idx desc, name, full_name limit %(page_len)s offset %(start)s""".format( From 50ad61245350879b564e203276a8c91a062a19bb Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 18 Aug 2022 12:04:07 +0530 Subject: [PATCH 13/27] fix: Add dimension section in subcontracting doctypes (backport #31849) (#31877) * fix: Add dimension section in subcontracting doctypes (#31849) (cherry picked from commit 8704ca783d3f3280113d11444baa8acfeb78c2a3) # Conflicts: # erpnext/patches.txt * chore: conflicts Co-authored-by: Sagar Sharma --- erpnext/hooks.py | 4 ++ erpnext/patches.txt | 3 +- ...g_dimensions_in_subcontracting_doctypes.py | 47 +++++++++++++++++++ .../subcontracting_order.json | 28 ++++++++++- .../subcontracting_order_item.json | 28 ++++++++++- .../subcontracting_receipt.json | 28 ++++++++++- .../subcontracting_receipt_item.json | 6 +-- 7 files changed, 137 insertions(+), 7 deletions(-) create mode 100644 erpnext/patches/v14_0/create_accounting_dimensions_in_subcontracting_doctypes.py diff --git a/erpnext/hooks.py b/erpnext/hooks.py index c4f0c59c386..a08feb44476 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -520,6 +520,10 @@ accounting_dimension_doctypes = [ "Purchase Order", "Purchase Receipt", "Sales Order", + "Subcontracting Order", + "Subcontracting Order Item", + "Subcontracting Receipt", + "Subcontracting Receipt Item", ] # get matching queries for Bank Reconciliation diff --git a/erpnext/patches.txt b/erpnext/patches.txt index c7dc27e2944..6d1f37a9faf 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -309,4 +309,5 @@ erpnext.patches.v14_0.migrate_gl_to_payment_ledger erpnext.patches.v14_0.crm_ux_cleanup erpnext.patches.v14_0.remove_india_localisation # 14-07-2022 erpnext.patches.v13_0.fix_number_and_frequency_for_monthly_depreciation -erpnext.patches.v14_0.remove_hr_and_payroll_modules # 20-07-2022 \ No newline at end of file +erpnext.patches.v14_0.remove_hr_and_payroll_modules # 20-07-2022 +erpnext.patches.v14_0.create_accounting_dimensions_in_subcontracting_doctypes \ No newline at end of file diff --git a/erpnext/patches/v14_0/create_accounting_dimensions_in_subcontracting_doctypes.py b/erpnext/patches/v14_0/create_accounting_dimensions_in_subcontracting_doctypes.py new file mode 100644 index 00000000000..b349c07f6df --- /dev/null +++ b/erpnext/patches/v14_0/create_accounting_dimensions_in_subcontracting_doctypes.py @@ -0,0 +1,47 @@ +import frappe +from frappe.custom.doctype.custom_field.custom_field import create_custom_field + + +def execute(): + accounting_dimensions = frappe.db.get_all( + "Accounting Dimension", fields=["fieldname", "label", "document_type", "disabled"] + ) + + if not accounting_dimensions: + return + + count = 1 + for d in accounting_dimensions: + + if count % 2 == 0: + insert_after_field = "dimension_col_break" + else: + insert_after_field = "accounting_dimensions_section" + + for doctype in [ + "Subcontracting Order", + "Subcontracting Order Item", + "Subcontracting Receipt", + "Subcontracting Receipt Item", + ]: + + field = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": d.fieldname}) + + if field: + continue + + df = { + "fieldname": d.fieldname, + "label": d.label, + "fieldtype": "Link", + "options": d.document_type, + "insert_after": insert_after_field, + } + + try: + create_custom_field(doctype, df, ignore_validate=True) + frappe.clear_cache(doctype=doctype) + except Exception: + pass + + count += 1 diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json index c6e76c76d76..f98f559d5ca 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json +++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json @@ -19,6 +19,10 @@ "transaction_date", "schedule_date", "amended_from", + "accounting_dimensions_section", + "cost_center", + "dimension_col_break", + "project", "address_and_contact_section", "supplier_address", "address_display", @@ -422,12 +426,34 @@ "fieldtype": "Select", "label": "Distribute Additional Costs Based On ", "options": "Qty\nAmount" + }, + { + "collapsible": 1, + "fieldname": "accounting_dimensions_section", + "fieldtype": "Section Break", + "label": "Accounting Dimensions" + }, + { + "fieldname": "cost_center", + "fieldtype": "Link", + "label": "Cost Center", + "options": "Cost Center" + }, + { + "fieldname": "dimension_col_break", + "fieldtype": "Column Break" + }, + { + "fieldname": "project", + "fieldtype": "Link", + "label": "Project", + "options": "Project" } ], "icon": "fa fa-file-text", "is_submittable": 1, "links": [], - "modified": "2022-04-11 21:02:44.097841", + "modified": "2022-08-15 14:08:49.204218", "modified_by": "Administrator", "module": "Subcontracting", "name": "Subcontracting Order", diff --git a/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json b/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json index 291f47a6340..3675a4ea08a 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json +++ b/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json @@ -40,6 +40,10 @@ "manufacture_section", "manufacturer", "manufacturer_part_no", + "accounting_dimensions_section", + "cost_center", + "dimension_col_break", + "project", "section_break_34", "page_break" ], @@ -304,13 +308,35 @@ "no_copy": 1, "print_hide": 1, "read_only": 1 + }, + { + "collapsible": 1, + "fieldname": "accounting_dimensions_section", + "fieldtype": "Section Break", + "label": "Accounting Dimensions" + }, + { + "fieldname": "cost_center", + "fieldtype": "Link", + "label": "Cost Center", + "options": "Cost Center" + }, + { + "fieldname": "dimension_col_break", + "fieldtype": "Column Break" + }, + { + "fieldname": "project", + "fieldtype": "Link", + "label": "Project", + "options": "Project" } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2022-04-11 21:28:06.585338", + "modified": "2022-08-15 14:25:45.177703", "modified_by": "Administrator", "module": "Subcontracting", "name": "Subcontracting Order Item", diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json index e9638144a79..94304865603 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json @@ -17,6 +17,10 @@ "posting_time", "is_return", "return_against", + "accounting_dimensions_section", + "cost_center", + "dimension_col_break", + "project", "section_addresses", "supplier_address", "contact_person", @@ -569,11 +573,33 @@ { "fieldname": "section_break_47", "fieldtype": "Section Break" + }, + { + "collapsible": 1, + "fieldname": "accounting_dimensions_section", + "fieldtype": "Section Break", + "label": "Accounting Dimensions " + }, + { + "fieldname": "cost_center", + "fieldtype": "Link", + "label": "Cost Center", + "options": "Cost Center" + }, + { + "fieldname": "dimension_col_break", + "fieldtype": "Column Break" + }, + { + "fieldname": "project", + "fieldtype": "Link", + "label": "Project", + "options": "Project" } ], "is_submittable": 1, "links": [], - "modified": "2022-04-18 13:15:12.011682", + "modified": "2022-08-15 14:30:29.447307", "modified_by": "Administrator", "module": "Subcontracting", "name": "Subcontracting Receipt", diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json index bf15f0f6882..437fc41f5e4 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json +++ b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json @@ -56,9 +56,9 @@ "accounting_details_section", "expense_account", "accounting_dimensions_section", - "project", - "dimension_col_break", "cost_center", + "dimension_col_break", + "project", "section_break_80", "page_break" ], @@ -465,7 +465,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2022-08-15 11:34:00.970042", + "modified": "2022-08-15 14:51:10.613347", "modified_by": "Administrator", "module": "Subcontracting", "name": "Subcontracting Receipt Item", From ae5c05081d30277a50723a9c2fb6e24f70341b74 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 18 Aug 2022 17:41:01 +0530 Subject: [PATCH 14/27] chore: remove unwanted field "provisional_expense_account" from SCR (backport #31847) (#31886) chore: remove unwanted field "provisional_expense_account" from SCR (#31847) (cherry picked from commit 7e88eb549f7059e494455c642e966bb72d0dc5e7) Co-authored-by: Sagar Sharma --- .../subcontracting_receipt.json | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json index 94304865603..cb5b8c06ddd 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json @@ -51,8 +51,6 @@ "in_words", "bill_no", "bill_date", - "accounting_details_section", - "provisional_expense_account", "more_info", "status", "column_break_39", @@ -524,19 +522,6 @@ "options": "Company", "read_only": 1 }, - { - "collapsible": 1, - "fieldname": "accounting_details_section", - "fieldtype": "Section Break", - "label": "Accounting Details" - }, - { - "fieldname": "provisional_expense_account", - "fieldtype": "Link", - "hidden": 1, - "label": "Provisional Expense Account", - "options": "Account" - }, { "default": "0", "fieldname": "is_return", @@ -599,7 +584,7 @@ ], "is_submittable": 1, "links": [], - "modified": "2022-08-15 14:30:29.447307", + "modified": "2022-08-16 09:56:41.199435", "modified_by": "Administrator", "module": "Subcontracting", "name": "Subcontracting Receipt", From 6656d23e45261c6a32750aa3652510e3e40a8650 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Thu, 18 Aug 2022 15:31:20 +0000 Subject: [PATCH 15/27] perf: use `create_custom_fields` (#31853) * perf: use `create_custom_fields` * fix: default must be a string (cherry picked from commit aafb7352830342ddef3e0cc8cf520b885957098f) --- .../tally_migration/tally_migration.py | 41 ++++++++------ .../woocommerce_settings.py | 41 +++++++------- erpnext/setup/install.py | 55 +++++++++---------- 3 files changed, 68 insertions(+), 69 deletions(-) diff --git a/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py b/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py index 7d676e42359..cd4aaee2c45 100644 --- a/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py +++ b/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py @@ -12,7 +12,9 @@ from decimal import Decimal import frappe from bs4 import BeautifulSoup as bs from frappe import _ -from frappe.custom.doctype.custom_field.custom_field import create_custom_field +from frappe.custom.doctype.custom_field.custom_field import ( + create_custom_fields as _create_custom_fields, +) from frappe.model.document import Document from frappe.utils.data import format_datetime @@ -577,22 +579,25 @@ class TallyMigration(Document): new_year.save() oldest_year = new_year - def create_custom_fields(doctypes): - tally_guid_df = { - "fieldtype": "Data", - "fieldname": "tally_guid", - "read_only": 1, - "label": "Tally GUID", - } - tally_voucher_no_df = { - "fieldtype": "Data", - "fieldname": "tally_voucher_no", - "read_only": 1, - "label": "Tally Voucher Number", - } - for df in [tally_guid_df, tally_voucher_no_df]: - for doctype in doctypes: - create_custom_field(doctype, df) + def create_custom_fields(): + _create_custom_fields( + { + ("Journal Entry", "Purchase Invoice", "Sales Invoice"): [ + { + "fieldtype": "Data", + "fieldname": "tally_guid", + "read_only": 1, + "label": "Tally GUID", + }, + { + "fieldtype": "Data", + "fieldname": "tally_voucher_no", + "read_only": 1, + "label": "Tally Voucher Number", + }, + ] + } + ) def create_price_list(): frappe.get_doc( @@ -628,7 +633,7 @@ class TallyMigration(Document): create_fiscal_years(vouchers) create_price_list() - create_custom_fields(["Journal Entry", "Purchase Invoice", "Sales Invoice"]) + create_custom_fields() total = len(vouchers) is_last = False diff --git a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py index 2e18776a927..4aa98aab56b 100644 --- a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py +++ b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py @@ -6,7 +6,7 @@ from urllib.parse import urlparse import frappe from frappe import _ -from frappe.custom.doctype.custom_field.custom_field import create_custom_field +from frappe.custom.doctype.custom_field.custom_field import create_custom_fields from frappe.model.document import Document from frappe.utils.nestedset import get_root_of @@ -19,27 +19,24 @@ class WoocommerceSettings(Document): def create_delete_custom_fields(self): if self.enable_sync: - custom_fields = {} - # create - for doctype in ["Customer", "Sales Order", "Item", "Address"]: - df = dict( - fieldname="woocommerce_id", - label="Woocommerce ID", - fieldtype="Data", - read_only=1, - print_hide=1, - ) - create_custom_field(doctype, df) - - for doctype in ["Customer", "Address"]: - df = dict( - fieldname="woocommerce_email", - label="Woocommerce Email", - fieldtype="Data", - read_only=1, - print_hide=1, - ) - create_custom_field(doctype, df) + create_custom_fields( + { + ("Customer", "Sales Order", "Item", "Address"): dict( + fieldname="woocommerce_id", + label="Woocommerce ID", + fieldtype="Data", + read_only=1, + print_hide=1, + ), + ("Customer", "Address"): dict( + fieldname="woocommerce_email", + label="Woocommerce Email", + fieldtype="Data", + read_only=1, + print_hide=1, + ), + } + ) if not frappe.get_value("Item Group", {"name": _("WooCommerce Products")}): item_group = frappe.new_doc("Item Group") diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py index 7d7e6b5e076..2076dde5199 100644 --- a/erpnext/setup/install.py +++ b/erpnext/setup/install.py @@ -4,7 +4,7 @@ import frappe from frappe import _ -from frappe.custom.doctype.custom_field.custom_field import create_custom_field +from frappe.custom.doctype.custom_field.custom_field import create_custom_fields from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to from frappe.utils import cint @@ -83,35 +83,32 @@ def setup_currency_exchange(): def create_print_setting_custom_fields(): - create_custom_field( - "Print Settings", + create_custom_fields( { - "label": _("Compact Item Print"), - "fieldname": "compact_item_print", - "fieldtype": "Check", - "default": 1, - "insert_after": "with_letterhead", - }, - ) - create_custom_field( - "Print Settings", - { - "label": _("Print UOM after Quantity"), - "fieldname": "print_uom_after_quantity", - "fieldtype": "Check", - "default": 0, - "insert_after": "compact_item_print", - }, - ) - create_custom_field( - "Print Settings", - { - "label": _("Print taxes with zero amount"), - "fieldname": "print_taxes_with_zero_amount", - "fieldtype": "Check", - "default": 0, - "insert_after": "allow_print_for_cancelled", - }, + "Print Settings": [ + { + "label": _("Compact Item Print"), + "fieldname": "compact_item_print", + "fieldtype": "Check", + "default": "1", + "insert_after": "with_letterhead", + }, + { + "label": _("Print UOM after Quantity"), + "fieldname": "print_uom_after_quantity", + "fieldtype": "Check", + "default": "0", + "insert_after": "compact_item_print", + }, + { + "label": _("Print taxes with zero amount"), + "fieldname": "print_taxes_with_zero_amount", + "fieldtype": "Check", + "default": "0", + "insert_after": "allow_print_for_cancelled", + }, + ] + } ) From da69cc5477c0648a026f1eef1c2d38d7e0a82a6e Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Thu, 18 Aug 2022 16:45:11 +0530 Subject: [PATCH 16/27] fix: additional-cost in items table (cherry picked from commit d7ed4093d8f494affb9929f7ad86cc954e48a8e1) --- .../subcontracting_order.py | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py index 71cdc94a3ae..1fd07464617 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py +++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py @@ -83,23 +83,23 @@ class SubcontractingOrder(SubcontractingController): self.set_missing_values_in_items() def set_missing_values_in_additional_costs(self): - if self.get("additional_costs"): - self.total_additional_costs = sum(flt(item.amount) for item in self.get("additional_costs")) + self.total_additional_costs = sum(flt(item.amount) for item in self.get("additional_costs")) - if self.total_additional_costs: - if self.distribute_additional_costs_based_on == "Amount": - total_amt = sum(flt(item.amount) for item in self.get("items")) - for item in self.items: - item.additional_cost_per_qty = ( - (item.amount * self.total_additional_costs) / total_amt - ) / item.qty - else: - total_qty = sum(flt(item.qty) for item in self.get("items")) - additional_cost_per_qty = self.total_additional_costs / total_qty - for item in self.items: - item.additional_cost_per_qty = additional_cost_per_qty + if self.total_additional_costs: + if self.distribute_additional_costs_based_on == "Amount": + total_amt = sum(flt(item.amount) for item in self.get("items")) + for item in self.items: + item.additional_cost_per_qty = ( + (item.amount * self.total_additional_costs) / total_amt + ) / item.qty + else: + total_qty = sum(flt(item.qty) for item in self.get("items")) + additional_cost_per_qty = self.total_additional_costs / total_qty + for item in self.items: + item.additional_cost_per_qty = additional_cost_per_qty else: - self.total_additional_costs = 0 + for item in self.items: + item.additional_cost_per_qty = 0 def set_missing_values_in_service_items(self): for idx, item in enumerate(self.get("service_items")): From d48487ada2c733ed9e88900f0244069a4ba8d0ef Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Thu, 18 Aug 2022 17:16:29 +0530 Subject: [PATCH 17/27] fix: base_amount and exchange_rate in additional-cost table (cherry picked from commit eabd3135f0f9d0ca788729c9391fd72ee8a6f871) --- erpnext/stock/landed_taxes_and_charges_common.js | 2 +- .../subcontracting_order/subcontracting_order.js | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/landed_taxes_and_charges_common.js b/erpnext/stock/landed_taxes_and_charges_common.js index ff8a69fb033..78bfd5dd1ac 100644 --- a/erpnext/stock/landed_taxes_and_charges_common.js +++ b/erpnext/stock/landed_taxes_and_charges_common.js @@ -1,4 +1,4 @@ -let document_list = ['Landed Cost Voucher', 'Stock Entry']; +let document_list = ['Landed Cost Voucher', 'Stock Entry', 'Subcontracting Order']; document_list.forEach((doctype) => { frappe.ui.form.on(doctype, { diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js index dbd337afd43..c20f8ab6653 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js +++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js @@ -3,6 +3,8 @@ frappe.provide('erpnext.buying'); +{% include 'erpnext/stock/landed_taxes_and_charges_common.js' %}; + frappe.ui.form.on('Subcontracting Order', { setup: (frm) => { frm.get_field("items").grid.cannot_add_rows = true; @@ -136,6 +138,16 @@ frappe.ui.form.on('Subcontracting Order', { } }); +frappe.ui.form.on('Landed Cost Taxes and Charges', { + amount: function (frm, cdt, cdn) { + frm.events.set_base_amount(frm, cdt, cdn); + }, + + expense_account: function (frm, cdt, cdn) { + frm.events.set_account_currency(frm, cdt, cdn); + } +}); + erpnext.buying.SubcontractingOrderController = class SubcontractingOrderController { setup() { this.frm.custom_make_buttons = { From 7ff54145711a68399f36fdb84aace052c6625db2 Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Thu, 18 Aug 2022 17:20:22 +0530 Subject: [PATCH 18/27] chore: move "set_missing_values_in_additional_costs" from SCO to SC" (cherry picked from commit ea82fe5bc20e4a06c40b9840c2ec536208c3fc3b) --- .../controllers/subcontracting_controller.py | 19 +++++++++++++++++++ .../subcontracting_order.py | 19 ------------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py index 2a2f8f562e7..a944cb8fcf7 100644 --- a/erpnext/controllers/subcontracting_controller.py +++ b/erpnext/controllers/subcontracting_controller.py @@ -720,6 +720,25 @@ class SubcontractingController(StockController): sco_doc = frappe.get_doc("Subcontracting Order", sco) sco_doc.update_status() + def set_missing_values_in_additional_costs(self): + self.total_additional_costs = sum(flt(item.amount) for item in self.get("additional_costs")) + + if self.total_additional_costs: + if self.distribute_additional_costs_based_on == "Amount": + total_amt = sum(flt(item.amount) for item in self.get("items")) + for item in self.items: + item.additional_cost_per_qty = ( + (item.amount * self.total_additional_costs) / total_amt + ) / item.qty + else: + total_qty = sum(flt(item.qty) for item in self.get("items")) + additional_cost_per_qty = self.total_additional_costs / total_qty + for item in self.items: + item.additional_cost_per_qty = additional_cost_per_qty + else: + for item in self.items: + item.additional_cost_per_qty = 0 + @frappe.whitelist() def get_current_stock(self): if self.doctype in ["Purchase Receipt", "Subcontracting Receipt"]: diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py index 1fd07464617..0495fb41749 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py +++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py @@ -82,25 +82,6 @@ class SubcontractingOrder(SubcontractingController): self.set_missing_values_in_supplied_items() self.set_missing_values_in_items() - def set_missing_values_in_additional_costs(self): - self.total_additional_costs = sum(flt(item.amount) for item in self.get("additional_costs")) - - if self.total_additional_costs: - if self.distribute_additional_costs_based_on == "Amount": - total_amt = sum(flt(item.amount) for item in self.get("items")) - for item in self.items: - item.additional_cost_per_qty = ( - (item.amount * self.total_additional_costs) / total_amt - ) / item.qty - else: - total_qty = sum(flt(item.qty) for item in self.get("items")) - additional_cost_per_qty = self.total_additional_costs / total_qty - for item in self.items: - item.additional_cost_per_qty = additional_cost_per_qty - else: - for item in self.items: - item.additional_cost_per_qty = 0 - def set_missing_values_in_service_items(self): for idx, item in enumerate(self.get("service_items")): self.items[idx].service_cost_per_qty = item.amount / self.items[idx].qty From 9e60dd32e863d286b51b144faeb0b55e5c34a9de Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Thu, 18 Aug 2022 19:50:00 +0530 Subject: [PATCH 19/27] fix: recalculate rate of items based on "Recalculate Rate" checkbox (cherry picked from commit 2fc683368403cf6341bf09fcfbd367f9777efa94) --- .../subcontracting_receipt/subcontracting_receipt.py | 2 +- .../subcontracting_receipt_item.json | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py index 0c4ec6fb76f..51007c56358 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py @@ -125,7 +125,7 @@ class SubcontractingReceipt(SubcontractingController): item.rm_cost_per_qty = item.rm_supp_cost / item.qty rm_supp_cost.pop(item.name) - if self.is_new() and item.rm_supp_cost > 0: + if item.recalculate_rate: item.rate = ( item.rm_cost_per_qty + (item.service_cost_per_qty or 0) + item.additional_cost_per_qty ) diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json index 437fc41f5e4..dcde6359929 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json +++ b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json @@ -29,6 +29,7 @@ "rate_and_amount", "rate", "amount", + "recalculate_rate", "column_break_19", "rm_cost_per_qty", "service_cost_per_qty", @@ -460,12 +461,18 @@ "fieldname": "accounting_details_section", "fieldtype": "Section Break", "label": "Accounting Details" + }, + { + "default": "1", + "fieldname": "recalculate_rate", + "fieldtype": "Check", + "label": "Recalculate Rate" } ], "idx": 1, "istable": 1, "links": [], - "modified": "2022-08-15 14:51:10.613347", + "modified": "2022-08-18 19:42:24.313449", "modified_by": "Administrator", "module": "Subcontracting", "name": "Subcontracting Receipt Item", From 3b222339b84ba9d8e0d1f4ea8798ea419f623d71 Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Thu, 18 Aug 2022 20:26:34 +0530 Subject: [PATCH 20/27] chore: add additional-cost table in SCR (cherry picked from commit 256b4245d51d28cccbca2d0c0037961b0a16112f) # Conflicts: # erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json --- .../stock/landed_taxes_and_charges_common.js | 2 +- .../subcontracting_receipt.js | 12 +++++++ .../subcontracting_receipt.json | 36 +++++++++++++++++++ .../subcontracting_receipt.py | 1 + 4 files changed, 50 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/landed_taxes_and_charges_common.js b/erpnext/stock/landed_taxes_and_charges_common.js index 78bfd5dd1ac..1d76a3d95a1 100644 --- a/erpnext/stock/landed_taxes_and_charges_common.js +++ b/erpnext/stock/landed_taxes_and_charges_common.js @@ -1,4 +1,4 @@ -let document_list = ['Landed Cost Voucher', 'Stock Entry', 'Subcontracting Order']; +let document_list = ['Landed Cost Voucher', 'Stock Entry', 'Subcontracting Order', 'Subcontracting Receipt']; document_list.forEach((doctype) => { frappe.ui.form.on(doctype, { diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js index 35fec8bc33c..aff76eb50fa 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js @@ -3,6 +3,8 @@ frappe.provide('erpnext.buying'); +{% include 'erpnext/stock/landed_taxes_and_charges_common.js' %}; + frappe.ui.form.on('Subcontracting Receipt', { setup: (frm) => { frm.get_field('supplied_items').grid.cannot_add_rows = true; @@ -128,6 +130,16 @@ frappe.ui.form.on('Subcontracting Receipt', { }, }); +frappe.ui.form.on('Landed Cost Taxes and Charges', { + amount: function (frm, cdt, cdn) { + frm.events.set_base_amount(frm, cdt, cdn); + }, + + expense_account: function (frm, cdt, cdn) { + frm.events.set_account_currency(frm, cdt, cdn); + } +}); + frappe.ui.form.on('Subcontracting Receipt Item', { item_code(frm) { set_missing_values(frm); diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json index cb5b8c06ddd..ee96c50ba14 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json @@ -47,6 +47,10 @@ "raw_material_details", "get_current_stock", "supplied_items", + "additional_costs_section", + "distribute_additional_costs_based_on", + "additional_costs", + "total_additional_costs", "section_break_46", "in_words", "bill_no", @@ -580,11 +584,43 @@ "fieldtype": "Link", "label": "Project", "options": "Project" + }, + { + "collapsible": 1, + "collapsible_depends_on": "total_additional_costs", + "depends_on": "eval:(doc.docstatus == 0 || doc.total_additional_costs)", + "fieldname": "additional_costs_section", + "fieldtype": "Section Break", + "label": "Additional Costs" + }, + { + "default": "Qty", + "fieldname": "distribute_additional_costs_based_on", + "fieldtype": "Select", + "label": "Distribute Additional Costs Based On ", + "options": "Qty\nAmount" + }, + { + "fieldname": "additional_costs", + "fieldtype": "Table", + "label": "Additional Costs", + "options": "Landed Cost Taxes and Charges" + }, + { + "fieldname": "total_additional_costs", + "fieldtype": "Currency", + "label": "Total Additional Costs", + "print_hide_if_no_value": 1, + "read_only": 1 } ], "is_submittable": 1, "links": [], +<<<<<<< HEAD "modified": "2022-08-16 09:56:41.199435", +======= + "modified": "2022-08-18 15:48:57.419191", +>>>>>>> 256b4245d5 (chore: add additional-cost table in SCR) "modified_by": "Administrator", "module": "Subcontracting", "name": "Subcontracting Receipt", diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py index 51007c56358..f8b71ea0283 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py @@ -103,6 +103,7 @@ class SubcontractingReceipt(SubcontractingController): @frappe.whitelist() def set_missing_values(self): + self.set_missing_values_in_additional_costs() self.set_missing_values_in_supplied_items() self.set_missing_values_in_items() From e099e10c8eef3c497be2298ff087c315fee393a2 Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Fri, 19 Aug 2022 11:46:27 +0530 Subject: [PATCH 21/27] fix: test "test_pending_and_received_qty" (cherry picked from commit addd7347d888701f5ff9031a37aeaa25c97dda14) --- .../test_subcontracted_item_to_be_received.py | 25 ++++++++++++------- .../controllers/subcontracting_controller.py | 4 +-- .../subcontracting_order.py | 6 ++--- .../subcontracting_receipt.py | 6 ++--- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py b/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py index c772c1a1b17..d13d9701f31 100644 --- a/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py +++ b/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py @@ -4,6 +4,8 @@ # Decompiled by https://python-decompiler.com +import copy + import frappe from frappe.tests.utils import FrappeTestCase @@ -11,10 +13,12 @@ from erpnext.buying.report.subcontracted_item_to_be_received.subcontracted_item_ execute, ) from erpnext.controllers.tests.test_subcontracting_controller import ( + get_rm_items, get_subcontracting_order, make_service_item, + make_stock_in_entry, + make_stock_transfer_entry, ) -from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import ( make_subcontracting_receipt, ) @@ -36,15 +40,18 @@ class TestSubcontractedItemToBeReceived(FrappeTestCase): sco = get_subcontracting_order( service_items=service_items, supplier_warehouse="_Test Warehouse 1 - _TC" ) - make_stock_entry( - item_code="_Test Item", target="_Test Warehouse 1 - _TC", qty=100, basic_rate=100 - ) - make_stock_entry( - item_code="_Test Item Home Desktop 100", - target="_Test Warehouse 1 - _TC", - qty=100, - basic_rate=100, + rm_items = get_rm_items(sco.supplied_items) + 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), ) + make_subcontracting_receipt_against_sco(sco.name) sco.reload() col, data = execute( diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py index a944cb8fcf7..1372c89d470 100644 --- a/erpnext/controllers/subcontracting_controller.py +++ b/erpnext/controllers/subcontracting_controller.py @@ -490,7 +490,7 @@ class SubcontractingController(StockController): row.item_code, row.get(self.subcontract_data.order_field), ) and transfer_item.qty > 0: - qty = self.__get_qty_based_on_material_transfer(row, transfer_item) or 0 + qty = flt(self.__get_qty_based_on_material_transfer(row, transfer_item)) transfer_item.qty -= qty self.__add_supplied_item(row, transfer_item.get("item_details"), qty) @@ -749,7 +749,7 @@ class SubcontractingController(StockController): {"item_code": item.rm_item_code, "warehouse": self.supplier_warehouse}, "actual_qty", ) - item.current_stock = flt(actual_qty) or 0 + item.current_stock = flt(actual_qty) @property def sub_contracted_items(self): diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py index 0495fb41749..156f027617f 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py +++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py @@ -95,9 +95,7 @@ class SubcontractingOrder(SubcontractingController): def set_missing_values_in_items(self): total_qty = total = 0 for item in self.items: - item.rate = ( - item.rm_cost_per_qty + item.service_cost_per_qty + (item.additional_cost_per_qty or 0) - ) + item.rate = item.rm_cost_per_qty + item.service_cost_per_qty + flt(item.additional_cost_per_qty) item.amount = item.qty * item.rate total_qty += flt(item.qty) total += flt(item.amount) @@ -168,7 +166,7 @@ class SubcontractingOrder(SubcontractingController): total_required_qty = total_supplied_qty = 0 for item in self.supplied_items: total_required_qty += item.required_qty - total_supplied_qty += item.supplied_qty or 0 + total_supplied_qty += flt(item.supplied_qty) if total_supplied_qty: status = "Partial Material Transferred" if total_supplied_qty >= total_required_qty: diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py index f8b71ea0283..021d9aa8547 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py @@ -3,7 +3,7 @@ import frappe from frappe import _ -from frappe.utils import cint, getdate, nowdate +from frappe.utils import cint, flt, getdate, nowdate from erpnext.controllers.subcontracting_controller import SubcontractingController @@ -128,10 +128,10 @@ class SubcontractingReceipt(SubcontractingController): if item.recalculate_rate: item.rate = ( - item.rm_cost_per_qty + (item.service_cost_per_qty or 0) + item.additional_cost_per_qty + flt(item.rm_cost_per_qty) + flt(item.service_cost_per_qty) + flt(item.additional_cost_per_qty) ) - item.received_qty = item.qty + (item.rejected_qty or 0) + item.received_qty = item.qty + flt(item.rejected_qty) item.amount = item.qty * item.rate total_qty += item.qty total_amount += item.amount From 9a29e3c9f2f97b9e422538a3c9ae44b88e98e31e Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Fri, 19 Aug 2022 11:10:00 +0530 Subject: [PATCH 22/27] chore: add test for additional-cost (cherry picked from commit c247cf728c6aaaa55a47c8148df807944a515a6e) --- .../tests/test_subcontracting_controller.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/erpnext/controllers/tests/test_subcontracting_controller.py b/erpnext/controllers/tests/test_subcontracting_controller.py index 4fab8058b86..bc503f5440a 100644 --- a/erpnext/controllers/tests/test_subcontracting_controller.py +++ b/erpnext/controllers/tests/test_subcontracting_controller.py @@ -36,6 +36,36 @@ class TestSubcontractingController(FrappeTestCase): sco.remove_empty_rows() self.assertEqual((len_before - 1), len(sco.service_items)) + def test_set_missing_values_in_additional_costs(self): + sco = get_subcontracting_order(do_not_submit=1) + + rate_without_additional_cost = sco.items[0].rate + amount_without_additional_cost = sco.items[0].amount + + additional_amount = 120 + sco.append( + "additional_costs", + { + "expense_account": "Cost of Goods Sold - _TC", + "description": "Test", + "amount": additional_amount, + }, + ) + sco.save() + + additional_cost_per_qty = additional_amount / sco.items[0].qty + + self.assertEqual(sco.items[0].additional_cost_per_qty, additional_cost_per_qty) + self.assertEqual(rate_without_additional_cost + additional_cost_per_qty, sco.items[0].rate) + self.assertEqual(amount_without_additional_cost + additional_amount, sco.items[0].amount) + + sco.additional_costs = [] + sco.save() + + self.assertEqual(sco.items[0].additional_cost_per_qty, 0) + self.assertEqual(rate_without_additional_cost, sco.items[0].rate) + self.assertEqual(amount_without_additional_cost, sco.items[0].amount) + def test_create_raw_materials_supplied(self): sco = get_subcontracting_order() sco.supplied_items = None From 376293326b49d7c9daeb7007f72b13dfaf265797 Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Fri, 19 Aug 2022 15:30:50 +0530 Subject: [PATCH 23/27] chore: conflicts --- .../subcontracting_receipt/subcontracting_receipt.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json index ee96c50ba14..3aa8e61ae09 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json @@ -616,11 +616,7 @@ ], "is_submittable": 1, "links": [], -<<<<<<< HEAD - "modified": "2022-08-16 09:56:41.199435", -======= "modified": "2022-08-18 15:48:57.419191", ->>>>>>> 256b4245d5 (chore: add additional-cost table in SCR) "modified_by": "Administrator", "module": "Subcontracting", "name": "Subcontracting Receipt", From 200a971743066450d95509a8deb3af1d601a557e Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 19 Aug 2022 17:11:13 +0530 Subject: [PATCH 24/27] fix(pos): edge case while closing pos (#31892) --- .../doctype/pos_closing_entry/pos_closing_entry.js | 9 +++++++++ .../pos_closing_entry/pos_closing_entry.json | 13 +++++++++++-- .../doctype/pos_closing_entry/pos_closing_entry.py | 3 +++ .../pos_invoice_merge_log.json | 11 ++++++++++- .../pos_invoice_merge_log/pos_invoice_merge_log.py | 7 ++++++- 5 files changed, 39 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js index 98f3420d87e..1d596c1bfbb 100644 --- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js +++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js @@ -36,6 +36,15 @@ frappe.ui.form.on('POS Closing Entry', { }); set_html_data(frm); + + if (frm.doc.docstatus == 1) { + if (!frm.doc.posting_date) { + frm.set_value("posting_date", frappe.datetime.nowdate()); + } + if (!frm.doc.posting_time) { + frm.set_value("posting_time", frappe.datetime.now_time()); + } + } }, refresh: function(frm) { diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json index d6e35c6a50d..9d15e6cf357 100644 --- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json +++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json @@ -11,6 +11,7 @@ "period_end_date", "column_break_3", "posting_date", + "posting_time", "pos_opening_entry", "status", "section_break_5", @@ -51,7 +52,6 @@ "fieldtype": "Datetime", "in_list_view": 1, "label": "Period End Date", - "read_only": 1, "reqd": 1 }, { @@ -219,6 +219,13 @@ "fieldtype": "Small Text", "label": "Error", "read_only": 1 + }, + { + "fieldname": "posting_time", + "fieldtype": "Time", + "label": "Posting Time", + "no_copy": 1, + "reqd": 1 } ], "is_submittable": 1, @@ -228,10 +235,11 @@ "link_fieldname": "pos_closing_entry" } ], - "modified": "2021-10-20 16:19:25.340565", + "modified": "2022-08-01 11:37:14.991228", "modified_by": "Administrator", "module": "Accounts", "name": "POS Closing Entry", + "naming_rule": "Expression (old style)", "owner": "Administrator", "permissions": [ { @@ -278,5 +286,6 @@ ], "sort_field": "modified", "sort_order": "DESC", + "states": [], "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py index 49aab0d0bbf..655c4ec0035 100644 --- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py +++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py @@ -15,6 +15,9 @@ from erpnext.controllers.status_updater import StatusUpdater class POSClosingEntry(StatusUpdater): def validate(self): + self.posting_date = self.posting_date or frappe.utils.nowdate() + self.posting_time = self.posting_time or frappe.utils.nowtime() + if frappe.db.get_value("POS Opening Entry", self.pos_opening_entry, "status") != "Open": frappe.throw(_("Selected POS Opening Entry should be open."), title=_("Invalid Opening Entry")) diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.json b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.json index d7620870780..a0594556474 100644 --- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.json +++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.json @@ -6,6 +6,7 @@ "engine": "InnoDB", "field_order": [ "posting_date", + "posting_time", "merge_invoices_based_on", "column_break_3", "pos_closing_entry", @@ -105,12 +106,19 @@ "label": "Customer Group", "mandatory_depends_on": "eval:doc.merge_invoices_based_on == 'Customer Group'", "options": "Customer Group" + }, + { + "fieldname": "posting_time", + "fieldtype": "Time", + "label": "Posting Time", + "no_copy": 1, + "reqd": 1 } ], "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2021-09-14 11:17:19.001142", + "modified": "2022-08-01 11:36:42.456429", "modified_by": "Administrator", "module": "Accounts", "name": "POS Invoice Merge Log", @@ -173,5 +181,6 @@ ], "sort_field": "modified", "sort_order": "DESC", + "states": [], "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py index 5003a1d6a81..81a234a20a7 100644 --- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py +++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py @@ -9,7 +9,7 @@ from frappe import _ from frappe.core.page.background_jobs.background_jobs import get_info from frappe.model.document import Document from frappe.model.mapper import map_child_doc, map_doc -from frappe.utils import cint, flt, getdate, nowdate +from frappe.utils import cint, flt, get_time, getdate, nowdate, nowtime from frappe.utils.background_jobs import enqueue from frappe.utils.scheduler import is_scheduler_inactive @@ -99,6 +99,7 @@ class POSInvoiceMergeLog(Document): sales_invoice.is_consolidated = 1 sales_invoice.set_posting_time = 1 sales_invoice.posting_date = getdate(self.posting_date) + sales_invoice.posting_time = get_time(self.posting_time) sales_invoice.save() sales_invoice.submit() @@ -115,6 +116,7 @@ class POSInvoiceMergeLog(Document): credit_note.is_consolidated = 1 credit_note.set_posting_time = 1 credit_note.posting_date = getdate(self.posting_date) + credit_note.posting_time = get_time(self.posting_time) # TODO: return could be against multiple sales invoice which could also have been consolidated? # credit_note.return_against = self.consolidated_invoice credit_note.save() @@ -402,6 +404,9 @@ def create_merge_logs(invoice_by_customer, closing_entry=None): merge_log.posting_date = ( getdate(closing_entry.get("posting_date")) if closing_entry else nowdate() ) + merge_log.posting_time = ( + get_time(closing_entry.get("posting_time")) if closing_entry else nowtime() + ) merge_log.customer = customer merge_log.pos_closing_entry = closing_entry.get("name") if closing_entry else None From 0db912998a8a971fdc010bc9f7017658e0d88db4 Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Fri, 19 Aug 2022 20:44:13 +0530 Subject: [PATCH 25/27] chore: allow subcontracting receipt backdated entry (cherry picked from commit f8c11847bbff996d20cc6385d61fe5df3fe75019) --- .../subcontracting_receipt.json | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json index 3aa8e61ae09..872d18e15ea 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json @@ -15,6 +15,7 @@ "company", "posting_date", "posting_time", + "set_posting_time", "is_return", "return_against", "accounting_dimensions_section", @@ -138,6 +139,7 @@ "label": "Date", "no_copy": 1, "print_width": "100px", + "read_only_depends_on": "eval: !doc.set_posting_time", "reqd": 1, "search_index": 1, "width": "100px" @@ -150,6 +152,7 @@ "no_copy": 1, "print_hide": 1, "print_width": "100px", + "read_only_depends_on": "eval: !doc.set_posting_time", "reqd": 1, "width": "100px" }, @@ -612,11 +615,19 @@ "label": "Total Additional Costs", "print_hide_if_no_value": 1, "read_only": 1 + }, + { + "default": "0", + "depends_on": "eval:doc.docstatus==0", + "fieldname": "set_posting_time", + "fieldtype": "Check", + "label": "Edit Posting Date and Time", + "print_hide": 1 } ], "is_submittable": 1, "links": [], - "modified": "2022-08-18 15:48:57.419191", + "modified": "2022-08-19 19:50:16.935124", "modified_by": "Administrator", "module": "Subcontracting", "name": "Subcontracting Receipt", From 19d29d186135bb0f9bd2111a6294a2d98547808c Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Fri, 19 Aug 2022 20:52:26 +0530 Subject: [PATCH 26/27] chore: add option for "Subcontracting Receipt" in "Voucher Type" (cherry picked from commit f92f3e0208cdfd6812c32a5820f7b08791f64e3c) --- .../doctype/repost_item_valuation/repost_item_valuation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js index 4cd40bf38ec..d6e00eada72 100644 --- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js +++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js @@ -15,7 +15,7 @@ frappe.ui.form.on('Repost Item Valuation', { return { filters: { name: ['in', ['Purchase Receipt', 'Purchase Invoice', 'Delivery Note', - 'Sales Invoice', 'Stock Entry', 'Stock Reconciliation']] + 'Sales Invoice', 'Stock Entry', 'Stock Reconciliation', 'Subcontracting Receipt']] } }; }); From 6be77d5729906c6e43c7744b07289b490e05c891 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sat, 20 Aug 2022 19:28:21 +0530 Subject: [PATCH 27/27] fix: make rate field read-only in subcontracting receipt item (backport #31905) (#31906) fix: make rate field read-only in subcontracting receipt item (#31905) (cherry picked from commit 588ca68171ed8c8f65d9a6c27323e29a2ac30e94) Co-authored-by: Sagar Sharma --- .../subcontracting_receipt_item.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json index dcde6359929..fd86895b9e3 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json +++ b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json @@ -194,6 +194,8 @@ "label": "Rate", "options": "currency", "print_width": "100px", + "read_only": 1, + "read_only_depends_on": "eval: doc.recalculate_rate", "width": "100px" }, { @@ -472,7 +474,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2022-08-18 19:42:24.313449", + "modified": "2022-08-20 17:16:48.269164", "modified_by": "Administrator", "module": "Subcontracting", "name": "Subcontracting Receipt Item",