From 987ac513c84c1f9db18d758de57a7c99734c62ca Mon Sep 17 00:00:00 2001 From: hamzaali15 Date: Mon, 5 Sep 2022 11:15:43 +0500 Subject: [PATCH 1/6] fix: QR Code multi currency issue When try to scan qr code on app it is showing correct values for multi currencies because it is not getting base amount (cherry picked from commit b10a2b87b65f3c29ed0aae7f30099e9c8ad75377) --- erpnext/regional/saudi_arabia/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/regional/saudi_arabia/utils.py b/erpnext/regional/saudi_arabia/utils.py index b47adc95f72..cac5ec113e8 100644 --- a/erpnext/regional/saudi_arabia/utils.py +++ b/erpnext/regional/saudi_arabia/utils.py @@ -84,7 +84,7 @@ def create_qr_code(doc, method=None): tlv_array.append("".join([tag, length, value])) # Invoice Amount - invoice_amount = str(doc.grand_total) + invoice_amount = str(doc.base_grand_total) tag = bytes([4]).hex() length = bytes([len(invoice_amount)]).hex() value = invoice_amount.encode("utf-8").hex() @@ -144,7 +144,7 @@ def get_vat_amount(doc): for tax in doc.get("taxes"): if tax.account_head in vat_accounts: - vat_amount += tax.tax_amount + vat_amount += tax.base_tax_amount return vat_amount From 506b289b2a3c189a4d0feed0d75d7d9aef6bb122 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 6 Sep 2022 19:03:58 +0530 Subject: [PATCH 2/6] ci: auto create release PRs [skip ci] --- .github/workflows/initiate_release.yml | 32 ++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/workflows/initiate_release.yml diff --git a/.github/workflows/initiate_release.yml b/.github/workflows/initiate_release.yml new file mode 100644 index 00000000000..ef38974ae27 --- /dev/null +++ b/.github/workflows/initiate_release.yml @@ -0,0 +1,32 @@ +# This workflow is agnostic to branches. Only maintain on develop branch. +# To add/remove versions just modify the matrix. + +name: Create weekly release pull requests +on: + schedule: + # 9:30 UTC => 3 PM IST Tuesday + - cron: "30 9 * * 2" + workflow_dispatch: + +jobs: + release: + name: Release + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + version: ["13", "14"] + + steps: + - uses: octokit/request-action@v2.x + with: + route: POST /repos/{owner}/{repo}/pulls + owner: frappe + repo: erpnext + title: |- + "chore: release v${{ matrix.version }}" + body: "Automated weekly release." + base: version-${{ matrix.version }} + head: version-${{ matrix.version }}-hotfix + env: + GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} From 008542b7155791d3f5cbbd4701fde2d953be3802 Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Wed, 7 Sep 2022 10:15:43 +0530 Subject: [PATCH 3/6] fix: AD not getting copied from SCO while creating a Material Transfer (#32106) --- erpnext/controllers/subcontracting_controller.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py index 1372c89d470..21504774f64 100644 --- a/erpnext/controllers/subcontracting_controller.py +++ b/erpnext/controllers/subcontracting_controller.py @@ -7,6 +7,7 @@ from collections import defaultdict import frappe from frappe import _ +from frappe.model.mapper import get_mapped_doc from frappe.utils import cint, cstr, flt, get_link_to_form from erpnext.controllers.stock_controller import StockController @@ -870,7 +871,17 @@ def add_items_in_ste( def make_return_stock_entry_for_subcontract( available_materials, order_doc, rm_details, order_doctype="Subcontracting Order" ): - ste_doc = frappe.new_doc("Stock Entry") + ste_doc = get_mapped_doc( + order_doctype, + order_doc.name, + { + order_doctype: { + "doctype": "Stock Entry", + }, + }, + ignore_child_tables=True, + ) + ste_doc.purpose = "Material Transfer" if order_doctype == "Purchase Order": From b4a102d11994c7e32e5be2707f45f42d039e3986 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 6 Sep 2022 16:22:00 +0530 Subject: [PATCH 4/6] fix: internal transfer flow --- .../doctype/sales_invoice/sales_invoice.py | 38 ++++++++++---- .../sales_invoice_item.json | 32 +++++++++++- .../purchase_order/purchase_order.json | 10 +++- .../purchase_order_dashboard.py | 1 + .../purchase_order/test_purchase_order.py | 52 +++++++++++++++++++ .../purchase_order_item.json | 32 +++++++++--- erpnext/controllers/accounts_controller.py | 2 +- erpnext/controllers/status_updater.py | 14 +++++ .../doctype/sales_order/sales_order.js | 29 +++++++++++ .../sales_order_item/sales_order_item.json | 32 +++++++++++- .../doctype/delivery_note/delivery_note.py | 3 ++ .../delivery_note_item.json | 32 +++++++++++- erpnext/utilities/transaction_base.py | 3 ++ 13 files changed, 257 insertions(+), 23 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 4008863e9ba..1f5879d7bff 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -710,6 +710,7 @@ class SalesInvoice(SellingController): if ( cint(frappe.db.get_single_value("Selling Settings", "maintain_same_sales_rate")) and not self.is_return + and not self.is_internal_customer ): self.validate_rate_with_reference_doc( [["Sales Order", "sales_order", "so_detail"], ["Delivery Note", "delivery_note", "dn_detail"]] @@ -2161,6 +2162,17 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None): def update_item(source, target, source_parent): target.qty = flt(source.qty) - received_items.get(source.name, 0.0) + if source.doctype == "Purchase Order Item" and target.doctype == "Sales Order Item": + target.purchase_order = source.parent + target.purchase_order_item = source.name + + if ( + source.get("purchase_order") + and source.get("purchase_order_item") + and target.doctype == "Purchase Invoice Item" + ): + target.purchase_order = source.purchase_order + target.po_detail = source.purchase_order_item item_field_map = { "doctype": target_doctype + " Item", @@ -2187,6 +2199,12 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None): "serial_no": "serial_no", } ) + elif target_doctype == "Sales Order": + item_field_map["field_map"].update( + { + source_document_warehouse_field: "warehouse", + } + ) doclist = get_mapped_doc( doctype, @@ -2231,6 +2249,7 @@ def get_received_items(reference_name, doctype, reference_fieldname): def set_purchase_references(doc): # add internal PO or PR links if any + if doc.is_internal_transfer(): if doc.doctype == "Purchase Receipt": so_item_map = get_delivery_note_details(doc.inter_company_invoice_reference) @@ -2260,15 +2279,6 @@ def set_purchase_references(doc): warehouse_map, ) - if list(so_item_map.values()): - pd_item_map, parent_child_map, warehouse_map = get_pd_details( - "Purchase Order Item", so_item_map, "sales_order_item" - ) - - update_pi_items( - doc, "po_detail", "purchase_order", so_item_map, pd_item_map, parent_child_map, warehouse_map - ) - def update_pi_items( doc, @@ -2284,13 +2294,19 @@ def update_pi_items( item.set(parent_field, parent_child_map.get(sales_item_map.get(item.sales_invoice_item))) if doc.update_stock: item.warehouse = warehouse_map.get(sales_item_map.get(item.sales_invoice_item)) + if not item.warehouse and item.get("purchase_order") and item.get("purchase_order_item"): + item.warehouse = frappe.db.get_value( + "Purchase Order Item", item.purchase_order_item, "warehouse" + ) def update_pr_items(doc, sales_item_map, purchase_item_map, parent_child_map, warehouse_map): for item in doc.get("items"): - item.purchase_order_item = purchase_item_map.get(sales_item_map.get(item.delivery_note_item)) item.warehouse = warehouse_map.get(sales_item_map.get(item.delivery_note_item)) - item.purchase_order = parent_child_map.get(sales_item_map.get(item.delivery_note_item)) + if not item.warehouse and item.get("purchase_order") and item.get("purchase_order_item"): + item.warehouse = frappe.db.get_value( + "Purchase Order Item", item.purchase_order_item, "warehouse" + ) def get_delivery_note_details(internal_reference): diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index 7cddf123e24..4f97b63789a 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -96,6 +96,10 @@ "delivery_note", "dn_detail", "delivered_qty", + "internal_transfer_section", + "purchase_order", + "column_break_92", + "purchase_order_item", "accounting_dimensions_section", "cost_center", "dimension_col_break", @@ -840,12 +844,38 @@ "fieldtype": "Check", "label": "Grant Commission", "read_only": 1 + }, + { + "collapsible": 1, + "depends_on": "eval:parent.is_internal_customer == 1", + "fieldname": "internal_transfer_section", + "fieldtype": "Section Break", + "label": "Internal Transfer" + }, + { + "fieldname": "purchase_order", + "fieldtype": "Link", + "label": "Purchase Order", + "options": "Purchase Order", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "column_break_92", + "fieldtype": "Column Break" + }, + { + "fieldname": "purchase_order_item", + "fieldtype": "Data", + "label": "Purchase Order Item", + "print_hide": 1, + "read_only": 1 } ], "idx": 1, "istable": 1, "links": [], - "modified": "2022-08-26 12:06:31.205417", + "modified": "2022-09-06 14:17:43.394309", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index aa50487d78e..acca380672d 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -60,6 +60,7 @@ "section_break_45", "before_items_section", "scan_barcode", + "set_from_warehouse", "items_col_break", "set_warehouse", "items_section", @@ -1166,13 +1167,20 @@ "hidden": 1, "label": "Is Old Subcontracting Flow", "read_only": 1 + }, + { + "depends_on": "is_internal_supplier", + "fieldname": "set_from_warehouse", + "fieldtype": "Link", + "label": "Set From Warehouse", + "options": "Warehouse" } ], "icon": "fa fa-file-text", "idx": 105, "is_submittable": 1, "links": [], - "modified": "2022-06-15 15:40:58.527065", + "modified": "2022-09-07 11:06:46.035093", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", diff --git a/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py b/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py index 01b55c00d6b..05b5a8e7b8c 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py @@ -23,5 +23,6 @@ def get_data(): "items": ["Material Request", "Supplier Quotation", "Project", "Auto Repeat"], }, {"label": _("Sub-contracting"), "items": ["Subcontracting Order", "Stock Entry"]}, + {"label": _("Internal"), "items": ["Sales Order"]}, ], } diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index bd7e4e8d865..6029a68824e 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -9,6 +9,7 @@ from frappe.tests.utils import FrappeTestCase from frappe.utils import add_days, flt, getdate, nowdate from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry +from erpnext.buying.doctype.purchase_order.purchase_order import make_inter_company_sales_order from erpnext.buying.doctype.purchase_order.purchase_order import ( make_purchase_invoice as make_pi_from_po, ) @@ -796,6 +797,56 @@ class TestPurchaseOrder(FrappeTestCase): automatically_fetch_payment_terms(enable=0) + def test_internal_transfer_flow(self): + from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note + + prepare_data_for_internal_transfer() + supplier = "_Test Internal Supplier 2" + customer = "_Test Internal Customer 2" + + po = create_purchase_order( + company="_Test Company with perpetual inventory", + supplier=supplier, + warehouse="Stores - TCP1", + from_warehouse="_Test Internal Warehouse New 1 - TCP1", + qty=2, + rate=1, + ) + + so = make_inter_company_sales_order(po.name) + so.submit() + + dn = make_delivery_note(so.name) + + +def prepare_data_for_internal_transfer(): + from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier + from erpnext.selling.doctype.customer.test_customer import create_internal_customer + from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt + from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse + + create_internal_customer( + "_Test Internal Customer 2", + "_Test Company with perpetual inventory", + "_Test Company with perpetual inventory", + ) + + create_internal_supplier( + "_Test Internal Supplier 2", + "_Test Company with perpetual inventory", + "_Test Company with perpetual inventory", + ) + + warehouse = create_warehouse( + "_Test Internal Warehouse New 1", company="_Test Company with perpetual inventory" + ) + + make_purchase_receipt( + company="_Test Company with perpetual inventory", + warehouse=warehouse, + qty=2, + ) + def make_pr_against_po(po, received_qty=0): pr = make_purchase_receipt(po) @@ -847,6 +898,7 @@ def create_purchase_order(**args): { "item_code": args.item or args.item_code or "_Test Item", "warehouse": args.warehouse or "_Test Warehouse - _TC", + "from_warehouse": args.from_warehouse, "qty": args.qty or 10, "rate": args.rate or 500, "schedule_date": add_days(nowdate(), 1), diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json index 1a9845396ff..82e92e87bc9 100644 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json @@ -10,12 +10,14 @@ "item_code", "supplier_part_no", "item_name", + "brand", "product_bundle", "fg_item", "fg_item_qty", "column_break_4", "schedule_date", "expected_delivery_date", + "item_group", "section_break_5", "description", "col_break1", @@ -58,9 +60,12 @@ "base_net_rate", "base_net_amount", "warehouse_and_reference", + "from_warehouse", "warehouse", + "column_break_54", "actual_qty", "company_total_stock", + "references_section", "material_request", "material_request_item", "sales_order", @@ -73,8 +78,6 @@ "against_blanket_order", "blanket_order", "blanket_order_rate", - "item_group", - "brand", "section_break_56", "received_qty", "returned_qty", @@ -442,13 +445,13 @@ { "fieldname": "warehouse_and_reference", "fieldtype": "Section Break", - "label": "Warehouse and Reference" + "label": "Warehouse Settings" }, { "fieldname": "warehouse", "fieldtype": "Link", "in_list_view": 1, - "label": "Warehouse", + "label": "Target Warehouse", "oldfieldname": "warehouse", "oldfieldtype": "Link", "options": "Warehouse", @@ -760,7 +763,7 @@ "allow_on_submit": 1, "fieldname": "actual_qty", "fieldtype": "Float", - "label": "Available Qty at Warehouse", + "label": "Available Qty at Target Warehouse", "print_hide": 1, "read_only": 1 }, @@ -868,13 +871,30 @@ "fieldtype": "Float", "label": "Finished Good Item Qty", "mandatory_depends_on": "eval:parent.is_subcontracted && !parent.is_old_subcontracting_flow" + }, + { + "depends_on": "eval:parent.is_internal_supplier", + "fieldname": "from_warehouse", + "fieldtype": "Link", + "label": "From Warehouse", + "options": "Warehouse" + }, + { + "collapsible": 1, + "fieldname": "references_section", + "fieldtype": "Section Break", + "label": "References" + }, + { + "fieldname": "column_break_54", + "fieldtype": "Column Break" } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2022-06-17 05:29:40.602349", + "modified": "2022-09-07 11:12:38.634976", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order Item", diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index e689d567a17..6f321f47661 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -373,7 +373,7 @@ class AccountsController(TransactionBase): ) def validate_inter_company_reference(self): - if self.doctype not in ("Purchase Invoice", "Purchase Receipt", "Purchase Order"): + if self.doctype not in ("Purchase Invoice", "Purchase Receipt"): return if self.is_internal_transfer(): diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index 197d2ba2dc8..6e7d2b33c28 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -307,6 +307,20 @@ class StatusUpdater(Document): def limits_crossed_error(self, args, item, qty_or_amount): """Raise exception for limits crossed""" + if ( + self.doctype in ["Sales Invoice", "Delivery Note"] + and qty_or_amount == "amount" + and self.is_internal_customer + ): + return + + elif ( + self.doctype in ["Purchase Invoice", "Purchase Receipt"] + and qty_or_amount == "amount" + and self.is_internal_supplier + ): + return + if qty_or_amount == "qty": action_msg = _( 'To allow over receipt / delivery, update "Over Receipt/Delivery Allowance" in Stock Settings or the Item.' diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 6b6ea89b638..386c12b6386 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -59,7 +59,36 @@ frappe.ui.form.on("Sales Order", { }) }); } + + if (frm.doc.docstatus === 0 && frm.doc.is_internal_customer) { + frm.events.get_items_from_internal_purchase_order(frm); + } }, + + get_items_from_internal_purchase_order(frm) { + frm.add_custom_button(__('Purchase Order'), () => { + erpnext.utils.map_current_doc({ + method: 'erpnext.buying.doctype.purchase_order.purchase_order.make_inter_company_sales_order', + source_doctype: 'Purchase Order', + target: frm, + setters: [ + { + label: 'Supplier', + fieldname: 'supplier', + fieldtype: 'Link', + options: 'Supplier' + } + ], + get_query_filters: { + company: frm.doc.company, + is_internal_supplier: 1, + docstatus: 1, + status: ['!=', 'Completed'] + } + }); + }, __('Get Items From')); + }, + onload: function(frm) { if (!frm.doc.transaction_date){ frm.set_value('transaction_date', frappe.datetime.get_today()) diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index 318799907ed..2cf836f9fcc 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -92,7 +92,11 @@ "section_break_63", "page_break", "item_tax_rate", - "transaction_date" + "transaction_date", + "inter_transfer_reference_section", + "purchase_order", + "column_break_89", + "purchase_order_item" ], "fields": [ { @@ -809,12 +813,36 @@ "label": "Picked Qty (in Stock UOM)", "no_copy": 1, "read_only": 1 + }, + { + "fieldname": "inter_transfer_reference_section", + "fieldtype": "Section Break", + "label": "Inter Transfer Reference" + }, + { + "fieldname": "purchase_order", + "fieldtype": "Link", + "label": "Purchase Order", + "options": "Purchase Order", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "column_break_89", + "fieldtype": "Column Break" + }, + { + "fieldname": "purchase_order_item", + "fieldtype": "Data", + "label": "Purchase Order Item", + "print_hide": 1, + "read_only": 1 } ], "idx": 1, "istable": 1, "links": [], - "modified": "2022-06-17 05:27:41.603006", + "modified": "2022-09-06 13:24:18.065312", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 0e68e858065..36d5a6ce0e1 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -178,6 +178,7 @@ class DeliveryNote(SellingController): if ( cint(frappe.db.get_single_value("Selling Settings", "maintain_same_sales_rate")) and not self.is_return + and not self.is_internal_customer ): self.validate_rate_with_reference_doc( [ @@ -896,6 +897,8 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None): "name": "delivery_note_item", "batch_no": "batch_no", "serial_no": "serial_no", + "purchase_order": "purchase_order", + "purchase_order_item": "purchase_order_item", }, "field_no_map": ["warehouse"], }, diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json index 2de4842ebea..0911cdb476c 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -86,6 +86,10 @@ "expense_account", "allow_zero_valuation_rate", "column_break_71", + "internal_transfer_section", + "purchase_order", + "column_break_82", + "purchase_order_item", "accounting_dimensions_section", "cost_center", "dimension_col_break", @@ -777,13 +781,39 @@ "no_copy": 1, "print_hide": 1, "read_only": 1 + }, + { + "collapsible": 1, + "depends_on": "eval:parent.is_internal_customer == 1", + "fieldname": "internal_transfer_section", + "fieldtype": "Section Break", + "label": "Internal Transfer" + }, + { + "fieldname": "purchase_order", + "fieldtype": "Link", + "label": "Purchase Order", + "options": "Purchase Order", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "column_break_82", + "fieldtype": "Column Break" + }, + { + "fieldname": "purchase_order_item", + "fieldtype": "Data", + "label": "Purchase Order Item", + "print_hide": 1, + "read_only": 1 } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2022-06-17 05:25:47.711177", + "modified": "2022-09-06 14:19:42.876357", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py index cd1bf9f321b..21a0a551b62 100644 --- a/erpnext/utilities/transaction_base.py +++ b/erpnext/utilities/transaction_base.py @@ -71,6 +71,9 @@ class TransactionBase(StatusUpdater): self.validate_value(field, condition, prevdoc_values[field], doc) def validate_rate_with_reference_doc(self, ref_details): + if self.get("is_internal_supplier"): + return + buying_doctypes = ["Purchase Order", "Purchase Invoice", "Purchase Receipt"] if self.doctype in buying_doctypes: From aab2c9c682d29234fa3fd3acb840c6b6c1c9d4e4 Mon Sep 17 00:00:00 2001 From: Devin Slauenwhite Date: Wed, 7 Sep 2022 03:29:46 -0400 Subject: [PATCH 5/6] fix: require barcode item barcode. (#31957) * fix: require barcode item barcode. * fix: make supplier mandatory in Item Supplier DocType Co-authored-by: Sagar Sharma --- .../doctype/item_barcode/item_barcode.json | 3 +- .../doctype/item_supplier/item_supplier.json | 124 +++++------------- 2 files changed, 38 insertions(+), 89 deletions(-) diff --git a/erpnext/stock/doctype/item_barcode/item_barcode.json b/erpnext/stock/doctype/item_barcode/item_barcode.json index 56832f32d30..bda1218817c 100644 --- a/erpnext/stock/doctype/item_barcode/item_barcode.json +++ b/erpnext/stock/doctype/item_barcode/item_barcode.json @@ -17,6 +17,7 @@ "in_list_view": 1, "label": "Barcode", "no_copy": 1, + "reqd": 1, "unique": 1 }, { @@ -36,7 +37,7 @@ ], "istable": 1, "links": [], - "modified": "2022-06-01 06:24:33.969534", + "modified": "2022-08-24 19:59:47.871677", "modified_by": "Administrator", "module": "Stock", "name": "Item Barcode", diff --git a/erpnext/stock/doctype/item_supplier/item_supplier.json b/erpnext/stock/doctype/item_supplier/item_supplier.json index 6cff8e0892e..84649a67d00 100644 --- a/erpnext/stock/doctype/item_supplier/item_supplier.json +++ b/erpnext/stock/doctype/item_supplier/item_supplier.json @@ -1,95 +1,43 @@ { - "allow_copy": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2013-02-22 01:28:01", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "creation": "2013-02-22 01:28:01", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "supplier", + "supplier_part_no" + ], "fields": [ { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "supplier", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Supplier", - "length": 0, - "no_copy": 0, - "options": "Supplier", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "supplier", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Supplier", + "options": "Supplier", + "reqd": 1 + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "supplier_part_no", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Supplier Part Number", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "200px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0, + "fieldname": "supplier_part_no", + "fieldtype": "Data", + "in_global_search": 1, + "in_list_view": 1, + "label": "Supplier Part Number", + "print_width": "200px", "width": "200px" } - ], - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 1, - "image_view": 0, - "in_create": 0, - - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2017-02-20 13:29:32.569715", - "modified_by": "Administrator", - "module": "Stock", - "name": "Item Supplier", - "owner": "Administrator", - "permissions": [], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "track_changes": 1, - "track_seen": 0 + ], + "idx": 1, + "istable": 1, + "links": [], + "modified": "2022-09-07 12:33:55.780062", + "modified_by": "Administrator", + "module": "Stock", + "name": "Item Supplier", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "states": [], + "track_changes": 1 } \ No newline at end of file From 9d1be48bd2d4e631a714ae5ae5246ab2b39d557f Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 7 Sep 2022 13:28:10 +0530 Subject: [PATCH 6/6] test: added test case for internal transfer --- .../purchase_order/test_purchase_order.py | 84 +++++++++++++++---- 1 file changed, 70 insertions(+), 14 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index 6029a68824e..6c1bcc7dd49 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -7,6 +7,7 @@ import json import frappe from frappe.tests.utils import FrappeTestCase from frappe.utils import add_days, flt, getdate, nowdate +from frappe.utils.data import today from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry from erpnext.buying.doctype.purchase_order.purchase_order import make_inter_company_sales_order @@ -798,11 +799,20 @@ class TestPurchaseOrder(FrappeTestCase): automatically_fetch_payment_terms(enable=0) def test_internal_transfer_flow(self): - from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note + from erpnext.accounts.doctype.sales_invoice.sales_invoice import ( + make_inter_company_purchase_invoice, + ) + from erpnext.selling.doctype.sales_order.sales_order import ( + make_delivery_note, + make_sales_invoice, + ) + from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_purchase_receipt + + frappe.db.set_value("Selling Settings", None, "maintain_same_sales_rate", 1) + frappe.db.set_value("Buying Settings", None, "maintain_same_rate", 1) prepare_data_for_internal_transfer() supplier = "_Test Internal Supplier 2" - customer = "_Test Internal Customer 2" po = create_purchase_order( company="_Test Company with perpetual inventory", @@ -814,9 +824,41 @@ class TestPurchaseOrder(FrappeTestCase): ) so = make_inter_company_sales_order(po.name) + so.items[0].delivery_date = today() + self.assertEqual(so.items[0].warehouse, "_Test Internal Warehouse New 1 - TCP1") + self.assertTrue(so.items[0].purchase_order) + self.assertTrue(so.items[0].purchase_order_item) so.submit() dn = make_delivery_note(so.name) + dn.items[0].target_warehouse = "_Test Internal Warehouse GIT - TCP1" + self.assertEqual(dn.items[0].warehouse, "_Test Internal Warehouse New 1 - TCP1") + self.assertTrue(dn.items[0].purchase_order) + self.assertTrue(dn.items[0].purchase_order_item) + + self.assertEqual(po.items[0].name, dn.items[0].purchase_order_item) + dn.submit() + + pr = make_inter_company_purchase_receipt(dn.name) + self.assertEqual(pr.items[0].warehouse, "Stores - TCP1") + self.assertTrue(pr.items[0].purchase_order) + self.assertTrue(pr.items[0].purchase_order_item) + self.assertEqual(po.items[0].name, pr.items[0].purchase_order_item) + pr.submit() + + si = make_sales_invoice(so.name) + self.assertEqual(si.items[0].warehouse, "_Test Internal Warehouse New 1 - TCP1") + self.assertTrue(si.items[0].purchase_order) + self.assertTrue(si.items[0].purchase_order_item) + si.submit() + + pi = make_inter_company_purchase_invoice(si.name) + self.assertTrue(pi.items[0].purchase_order) + self.assertTrue(pi.items[0].po_detail) + pi.submit() + + po.load_from_db() + self.assertEqual(po.status, "Completed") def prepare_data_for_internal_transfer(): @@ -825,27 +867,41 @@ def prepare_data_for_internal_transfer(): from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse + company = "_Test Company with perpetual inventory" + create_internal_customer( "_Test Internal Customer 2", - "_Test Company with perpetual inventory", - "_Test Company with perpetual inventory", + company, + company, ) create_internal_supplier( "_Test Internal Supplier 2", - "_Test Company with perpetual inventory", - "_Test Company with perpetual inventory", + company, + company, ) - warehouse = create_warehouse( - "_Test Internal Warehouse New 1", company="_Test Company with perpetual inventory" - ) + warehouse = create_warehouse("_Test Internal Warehouse New 1", company=company) - make_purchase_receipt( - company="_Test Company with perpetual inventory", - warehouse=warehouse, - qty=2, - ) + create_warehouse("_Test Internal Warehouse GIT", company=company) + + make_purchase_receipt(company=company, warehouse=warehouse, qty=2, rate=100) + + if not frappe.db.get_value("Company", company, "unrealized_profit_loss_account"): + account = "Unrealized Profit and Loss - TCP1" + if not frappe.db.exists("Account", account): + frappe.get_doc( + { + "doctype": "Account", + "account_name": "Unrealized Profit and Loss", + "parent_account": "Direct Income - TCP1", + "company": company, + "is_group": 0, + "account_type": "Income Account", + } + ).insert() + + frappe.db.set_value("Company", company, "unrealized_profit_loss_account", account) def make_pr_against_po(po, received_qty=0):