diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 0af273c5180..95d49a4421a 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -21,8 +21,8 @@ from erpnext.accounts.general_ledger import get_round_off_account_and_cost_cente from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_disabled from frappe.model.mapper import get_mapped_doc from six import iteritems -from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_invoice,\ - unlink_inter_company_invoice +from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_doc,\ + unlink_inter_company_doc from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details from erpnext.accounts.deferred_revenue import validate_service_stop_date @@ -348,7 +348,7 @@ class PurchaseInvoice(BuyingController): self.make_gl_entries() self.update_project() - update_linked_invoice(self.doctype, self.name, self.inter_company_invoice_reference) + update_linked_doc(self.doctype, self.name, self.inter_company_invoice_reference) def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False): if not self.grand_total: @@ -778,7 +778,7 @@ class PurchaseInvoice(BuyingController): self.update_project() frappe.db.set(self, 'status', 'Cancelled') - unlink_inter_company_invoice(self.doctype, self.name, self.inter_company_invoice_reference) + unlink_inter_company_doc(self.doctype, self.name, self.inter_company_invoice_reference) def update_project(self): project_list = [] @@ -917,5 +917,5 @@ def block_invoice(name, hold_comment): @frappe.whitelist() def make_inter_company_sales_invoice(source_name, target_doc=None): - from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_invoice - return make_inter_company_invoice("Purchase Invoice", source_name, target_doc) + from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_transaction + return make_inter_company_transaction("Purchase Invoice", source_name, target_doc) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 2089f15c7c1..31a9c66f6f2 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -179,7 +179,7 @@ class SalesInvoice(SellingController): if frappe.db.get_single_value('Selling Settings', 'sales_update_frequency') == "Each Transaction": update_company_current_month_sales(self.company) self.update_project() - update_linked_invoice(self.doctype, self.name, self.inter_company_invoice_reference) + update_linked_doc(self.doctype, self.name, self.inter_company_invoice_reference) # create the loyalty point ledger entry if the customer is enrolled in any loyalty program if not self.is_return and self.loyalty_program: @@ -243,7 +243,7 @@ class SalesInvoice(SellingController): against_si_doc.delete_loyalty_point_entry() against_si_doc.make_loyalty_point_entry() - unlink_inter_company_invoice(self.doctype, self.name, self.inter_company_invoice_reference) + unlink_inter_company_doc(self.doctype, self.name, self.inter_company_invoice_reference) # Healthcare Service Invoice. domain_settings = frappe.get_doc('Domain Settings') @@ -1165,21 +1165,29 @@ class SalesInvoice(SellingController): self.set_missing_values(for_validate = True) -def validate_inter_company_party(doctype, party, company, inter_company_invoice_reference): - if doctype == "Sales Invoice": +def validate_inter_company_party(doctype, party, company, inter_company_reference): + if doctype in ["Sales Invoice", "Sales Order"]: partytype, ref_partytype, internal = "Customer", "Supplier", "is_internal_customer" - ref_doc = "Purchase Invoice" + + if doctype == "Sales Invoice": + ref_doc = "Purchase Invoice" + else: + ref_doc = "Purchase Order" else: partytype, ref_partytype, internal = "Supplier", "Customer", "is_internal_supplier" - ref_doc = "Sales Invoice" - if inter_company_invoice_reference: - doc = frappe.get_doc(ref_doc, inter_company_invoice_reference) - ref_party = doc.supplier if doctype == "Sales Invoice" else doc.customer + if doctype == "Purchase Invoice": + ref_doc = "Sales Invoice" + else: + ref_doc = "Sales Order" + + if inter_company_reference: + doc = frappe.get_doc(ref_doc, inter_company_reference) + ref_party = doc.supplier if doctype in ["Sales Invoice", "Sales Order"] else doc.customer if not frappe.db.get_value(partytype, {"represents_company": doc.company}, "name") == party: - frappe.throw(_("Invalid {0} for Inter Company Invoice.").format(partytype)) + frappe.throw(_("Invalid {0} for Inter Company Transaction.").format(partytype)) if not frappe.get_cached_value(ref_partytype, ref_party, "represents_company") == company: - frappe.throw(_("Invalid Company for Inter Company Invoice.")) + frappe.throw(_("Invalid Company for Inter Company Transaction.")) elif frappe.db.get_value(partytype, {"name": party, internal: 1}, "name") == party: companies = frappe.db.sql("""select company from `tabAllowed To Transact With` @@ -1188,18 +1196,29 @@ def validate_inter_company_party(doctype, party, company, inter_company_invoice_ if not company in companies: frappe.throw(_("{0} not allowed to transact with {1}. Please change the Company.").format(partytype, company)) -def update_linked_invoice(doctype, name, inter_company_invoice_reference): - if inter_company_invoice_reference: - frappe.db.set_value(doctype, inter_company_invoice_reference,\ - "inter_company_invoice_reference", name) +def update_linked_doc(doctype, name, inter_company_reference): -def unlink_inter_company_invoice(doctype, name, inter_company_invoice_reference): - ref_doc = "Purchase Invoice" if doctype == "Sales Invoice" else "Sales Invoice" - if inter_company_invoice_reference: - frappe.db.set_value(doctype, name,\ - "inter_company_invoice_reference", "") - frappe.db.set_value(ref_doc, inter_company_invoice_reference,\ - "inter_company_invoice_reference", "") + if doctype in ["Sales Invoice", "Purchase Invoice"]: + ref_field = "inter_company_invoice_reference" + else: + ref_field = "inter_company_order_reference" + + if inter_company_reference: + frappe.db.set_value(doctype, inter_company_reference,\ + ref_field, name) + +def unlink_inter_company_doc(doctype, name, inter_company_reference): + + if doctype in ["Sales Invoice", "Purchase Invoice"]: + ref_doc = "Purchase Invoice" if doctype == "Sales Invoice" else "Sales Invoice" + ref_field = "inter_company_invoice_reference" + else: + ref_doc = "Purchase Order" if doctype == "Sales Order" else "Sales Order" + ref_field = "inter_company_order_reference" + + if inter_company_reference: + frappe.db.set_value(doctype, name, ref_field, "") + frappe.db.set_value(ref_doc, inter_company_reference, ref_field, "") def get_list_context(context=None): from erpnext.controllers.website_list_for_contact import get_list_context @@ -1299,7 +1318,7 @@ def set_account_for_mode_of_payment(self): data.account = get_bank_cash_account(data.mode_of_payment, self.company).get("account") def get_inter_company_details(doc, doctype): - if doctype == "Sales Invoice": + if doctype in ["Sales Invoice", "Sales Order"]: party = frappe.db.get_value("Supplier", {"disabled": 0, "is_internal_supplier": 1, "represents_company": doc.company}, "name") company = frappe.get_cached_value("Customer", doc.customer, "represents_company") else: @@ -1312,21 +1331,21 @@ def get_inter_company_details(doc, doctype): } -def validate_inter_company_invoice(doc, doctype): +def validate_inter_company_transaction(doc, doctype): details = get_inter_company_details(doc, doctype) - price_list = doc.selling_price_list if doctype == "Sales Invoice" else doc.buying_price_list + price_list = doc.selling_price_list if doctype in ["Sales Invoice", "Sales Order"] else doc.buying_price_list valid_price_list = frappe.db.get_value("Price List", {"name": price_list, "buying": 1, "selling": 1}) if not valid_price_list: frappe.throw(_("Selected Price List should have buying and selling fields checked.")) party = details.get("party") if not party: - partytype = "Supplier" if doctype == "Sales Invoice" else "Customer" + partytype = "Supplier" if doctype in ["Sales Invoice", "Sales Order"] else "Customer" frappe.throw(_("No {0} found for Inter Company Transactions.").format(partytype)) company = details.get("company") - default_currency = frappe.get_cached_value('Company', company, "default_currency") + default_currency = frappe.get_cached_value('Company', company, "default_currency") if default_currency != doc.currency: frappe.throw(_("Company currencies of both the companies should match for Inter Company Transactions.")) @@ -1334,17 +1353,17 @@ def validate_inter_company_invoice(doc, doctype): @frappe.whitelist() def make_inter_company_purchase_invoice(source_name, target_doc=None): - return make_inter_company_invoice("Sales Invoice", source_name, target_doc) + return make_inter_company_transaction("Sales Invoice", source_name, target_doc) -def make_inter_company_invoice(doctype, source_name, target_doc=None): - if doctype == "Sales Invoice": - source_doc = frappe.get_doc("Sales Invoice", source_name) - target_doctype = "Purchase Invoice" +def make_inter_company_transaction(doctype, source_name, target_doc=None): + if doctype in ["Sales Invoice", "Sales Order"]: + source_doc = frappe.get_doc(doctype, source_name) + target_doctype = "Purchase Invoice" if doctype == "Sales Invoice" else "Purchase Order" else: - source_doc = frappe.get_doc("Purchase Invoice", source_name) - target_doctype = "Sales Invoice" + source_doc = frappe.get_doc(doctype, source_name) + target_doctype = "Sales Invoice" if doctype == "Purchase Invoice" else "Sales Order" - validate_inter_company_invoice(source_doc, doctype) + validate_inter_company_transaction(source_doc, doctype) details = get_inter_company_details(source_doc, doctype) def set_missing_values(source, target): @@ -1352,7 +1371,7 @@ def make_inter_company_invoice(doctype, source_name, target_doc=None): def update_details(source_doc, target_doc, source_parent): target_doc.inter_company_invoice_reference = source_doc.name - if target_doc.doctype == "Purchase Invoice": + if target_doc.doctype in ["Purchase Invoice", "Purchase Order"]: target_doc.company = details.get("company") target_doc.supplier = details.get("party") target_doc.buying_price_list = source_doc.selling_price_list diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 74c5f0ec1be..47c60839b36 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -18,6 +18,7 @@ from erpnext.accounts.doctype.account.test_account import get_inventory_account, from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data from erpnext.stock.doctype.item.test_item import create_item from six import iteritems +from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_transaction class TestSalesInvoice(unittest.TestCase): def make(self): w = frappe.copy_doc(test_records[0]) @@ -1625,6 +1626,61 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(expected_gle[i][2], gle.credit) self.assertEqual(getdate(expected_gle[i][3]), gle.posting_date) + def test_inter_company_transaction(self): + + if not frappe.db.exists("Customer", "_Test Internal Customer"): + customer = frappe.get_doc({ + "customer_group": "_Test Customer Group", + "customer_name": "_Test Internal Customer", + "customer_type": "Individual", + "doctype": "Customer", + "territory": "_Test Territory", + "is_internal_customer": 1, + "represents_company": "_Test Company 1" + }) + + customer.append("companies", { + "company": "Wind Power LLC" + }) + + customer.insert() + + if not frappe.db.exists("Supplier", "_Test Internal Supplier"): + supplier = frappe.get_doc({ + "supplier_group": "_Test Supplier Group", + "supplier_name": "_Test Internal Supplier", + "doctype": "Supplier", + "is_internal_supplier": 1, + "represents_company": "Wind Power LLC" + }) + + supplier.append("companies", { + "company": "_Test Company 1" + }) + + supplier.insert() + + si = create_sales_invoice( + company = "Wind Power LLC", + customer = "_Test Internal Customer", + debit_to = "Debtors - WP", + warehouse = "Stores - WP", + income_account = "Sales - WP", + expense_account = "Cost of Goods Sold - WP", + cost_center = "Main - WP", + currency = "USD", + do_not_save = 1 + ) + + si.selling_price_list = "_Test Price List Rest of the World" + si.submit() + + target_doc = make_inter_company_transaction("Sales Invoice", si.name) + target_doc.submit() + + self.assertEqual(target_doc.company, "_Test Company 1") + self.assertEqual(target_doc.supplier, "_Test Internal Supplier") + def create_sales_invoice(**args): si = frappe.new_doc("Sales Invoice") args = frappe._dict(args) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index 28ceab59181..e63ef605b0b 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -138,6 +138,20 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( erpnext.utils.make_subscription(doc.doctype, doc.name) }, __('Create')) } + + if (doc.docstatus === 1 && !doc.inter_company_order_reference) { + let me = this; + frappe.model.with_doc("Supplier", me.frm.doc.supplier, () => { + let supplier = frappe.model.get_doc("Supplier", me.frm.doc.supplier); + let internal = supplier.is_internal_supplier; + let disabled = supplier.disabled; + if (internal === 1 && disabled === 0) { + me.frm.add_custom_button("Inter Company Order", function() { + me.make_inter_company_order(me.frm); + }, __('Create')); + } + }); + } } if(flt(doc.per_billed)==0) { this.frm.add_custom_button(__('Payment Request'), @@ -296,6 +310,13 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( }); }, + make_inter_company_order: function(frm) { + frappe.model.open_mapped_doc({ + method: "erpnext.buying.doctype.purchase_order.purchase_order.make_inter_company_sales_order", + frm: frm + }); + }, + make_purchase_receipt: function() { frappe.model.open_mapped_doc({ method: "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_receipt", diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 46f48fb2d7b..13a097a0d7e 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -298,6 +298,7 @@ "collapsible": 0, "columns": 0, "default": "Today", + "fetch_if_empty": 0, "fieldname": "transaction_date", "fieldtype": "Date", "hidden": 0, @@ -332,6 +333,7 @@ "collapsible": 0, "columns": 0, "default": "", + "fetch_if_empty": 0, "fieldname": "schedule_date", "fieldtype": "Date", "hidden": 0, @@ -365,6 +367,7 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:doc.docstatus===1", + "fetch_if_empty": 0, "fieldname": "order_confirmation_no", "fieldtype": "Data", "hidden": 0, @@ -398,6 +401,7 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:doc.order_confirmation_no", + "fetch_if_empty": 0, "fieldname": "order_confirmation_date", "fieldtype": "Date", "hidden": 0, @@ -430,6 +434,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "amended_from", "fieldtype": "Link", "hidden": 0, @@ -465,6 +470,7 @@ "collapsible": 0, "collapsible_depends_on": "", "columns": 0, + "fetch_if_empty": 0, "fieldname": "drop_ship", "fieldtype": "Section Break", "hidden": 0, @@ -498,6 +504,7 @@ "collapsible": 0, "columns": 0, "depends_on": "", + "fetch_if_empty": 0, "fieldname": "customer", "fieldtype": "Link", "hidden": 0, @@ -532,6 +539,7 @@ "collapsible": 0, "columns": 0, "depends_on": "", + "fetch_if_empty": 0, "fieldname": "customer_name", "fieldtype": "Data", "hidden": 0, @@ -564,6 +572,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break_19", "fieldtype": "Column Break", "hidden": 0, @@ -596,6 +605,7 @@ "collapsible": 0, "columns": 0, "depends_on": "", + "fetch_if_empty": 0, "fieldname": "customer_contact_person", "fieldtype": "Link", "hidden": 0, @@ -629,6 +639,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "customer_contact_display", "fieldtype": "Small Text", "hidden": 1, @@ -661,6 +672,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "customer_contact_mobile", "fieldtype": "Small Text", "hidden": 1, @@ -693,6 +705,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "customer_contact_email", "fieldtype": "Code", "hidden": 1, @@ -726,6 +739,7 @@ "bold": 0, "collapsible": 1, "columns": 0, + "fetch_if_empty": 0, "fieldname": "section_addresses", "fieldtype": "Section Break", "hidden": 0, @@ -758,6 +772,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "supplier_address", "fieldtype": "Link", "hidden": 0, @@ -790,6 +805,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "contact_person", "fieldtype": "Link", "hidden": 0, @@ -823,6 +839,7 @@ "collapsible": 0, "columns": 0, "depends_on": "", + "fetch_if_empty": 0, "fieldname": "address_display", "fieldtype": "Small Text", "hidden": 0, @@ -854,6 +871,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "contact_display", "fieldtype": "Small Text", "hidden": 0, @@ -885,6 +903,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "contact_mobile", "fieldtype": "Small Text", "hidden": 0, @@ -916,6 +935,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "contact_email", "fieldtype": "Small Text", "hidden": 0, @@ -947,6 +967,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "col_break_address", "fieldtype": "Column Break", "hidden": 0, @@ -979,6 +1000,7 @@ "collapsible": 0, "columns": 0, "depends_on": "", + "fetch_if_empty": 0, "fieldname": "shipping_address", "fieldtype": "Link", "hidden": 0, @@ -1012,6 +1034,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "shipping_address_display", "fieldtype": "Small Text", "hidden": 0, @@ -1044,6 +1067,7 @@ "bold": 0, "collapsible": 1, "columns": 0, + "fetch_if_empty": 0, "fieldname": "currency_and_price_list", "fieldtype": "Section Break", "hidden": 0, @@ -1076,6 +1100,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "currency", "fieldtype": "Link", "hidden": 0, @@ -1111,6 +1136,7 @@ "collapsible": 0, "columns": 0, "description": "", + "fetch_if_empty": 0, "fieldname": "conversion_rate", "fieldtype": "Float", "hidden": 0, @@ -1145,6 +1171,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "cb_price_list", "fieldtype": "Column Break", "hidden": 0, @@ -1175,6 +1202,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "buying_price_list", "fieldtype": "Link", "hidden": 0, @@ -1207,6 +1235,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "price_list_currency", "fieldtype": "Link", "hidden": 0, @@ -1239,6 +1268,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "plc_conversion_rate", "fieldtype": "Float", "hidden": 0, @@ -1271,6 +1301,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "ignore_pricing_rule", "fieldtype": "Check", "hidden": 0, @@ -1302,6 +1333,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "sec_warehouse", "fieldtype": "Section Break", "hidden": 0, @@ -1333,6 +1365,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "set_warehouse", "fieldtype": "Link", "hidden": 0, @@ -1366,6 +1399,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "col_break_warehouse", "fieldtype": "Column Break", "hidden": 0, @@ -1398,6 +1432,7 @@ "collapsible": 0, "columns": 0, "default": "No", + "fetch_if_empty": 0, "fieldname": "is_subcontracted", "fieldtype": "Select", "hidden": 0, @@ -1431,6 +1466,7 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:doc.is_subcontracted==\"Yes\"", + "fetch_if_empty": 0, "fieldname": "supplier_warehouse", "fieldtype": "Link", "hidden": 0, @@ -1464,6 +1500,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "items_section", "fieldtype": "Section Break", "hidden": 0, @@ -1497,6 +1534,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "scan_barcode", "fieldtype": "Data", "hidden": 0, @@ -1529,6 +1567,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "items", "fieldtype": "Table", "hidden": 0, @@ -1563,6 +1602,7 @@ "bold": 0, "collapsible": 1, "columns": 0, + "fetch_if_empty": 0, "fieldname": "section_break_48", "fieldtype": "Section Break", "hidden": 0, @@ -1596,6 +1636,7 @@ "collapsible": 0, "collapsible_depends_on": "", "columns": 0, + "fetch_if_empty": 0, "fieldname": "pricing_rules", "fieldtype": "Table", "hidden": 0, @@ -1630,6 +1671,7 @@ "collapsible": 0, "collapsible_depends_on": "supplied_items", "columns": 0, + "fetch_if_empty": 0, "fieldname": "raw_material_details", "fieldtype": "Section Break", "hidden": 0, @@ -1663,6 +1705,7 @@ "collapsible": 0, "columns": 0, "depends_on": "", + "fetch_if_empty": 0, "fieldname": "supplied_items", "fieldtype": "Table", "hidden": 0, @@ -1697,6 +1740,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "sb_last_purchase", "fieldtype": "Section Break", "hidden": 0, @@ -1727,6 +1771,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "total_qty", "fieldtype": "Float", "hidden": 0, @@ -1759,6 +1804,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "base_total", "fieldtype": "Currency", "hidden": 0, @@ -1792,6 +1838,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "base_net_total", "fieldtype": "Currency", "hidden": 0, @@ -1826,6 +1873,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break_26", "fieldtype": "Column Break", "hidden": 0, @@ -1856,6 +1904,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "total", "fieldtype": "Currency", "hidden": 0, @@ -1889,6 +1938,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "net_total", "fieldtype": "Currency", "hidden": 0, @@ -1923,6 +1973,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "total_net_weight", "fieldtype": "Float", "hidden": 0, @@ -1955,6 +2006,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "taxes_section", "fieldtype": "Section Break", "hidden": 0, @@ -1989,6 +2041,7 @@ "collapsible": 0, "columns": 0, "description": "", + "fetch_if_empty": 0, "fieldname": "taxes_and_charges", "fieldtype": "Link", "hidden": 0, @@ -2023,6 +2076,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break_50", "fieldtype": "Column Break", "hidden": 0, @@ -2054,6 +2108,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "shipping_rule", "fieldtype": "Link", "hidden": 0, @@ -2087,6 +2142,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "section_break_52", "fieldtype": "Section Break", "hidden": 0, @@ -2118,6 +2174,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "taxes", "fieldtype": "Table", "hidden": 0, @@ -2152,6 +2209,7 @@ "bold": 0, "collapsible": 1, "columns": 0, + "fetch_if_empty": 0, "fieldname": "sec_tax_breakup", "fieldtype": "Section Break", "hidden": 0, @@ -2184,6 +2242,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "other_charges_calculation", "fieldtype": "Text", "hidden": 0, @@ -2216,6 +2275,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "totals", "fieldtype": "Section Break", "hidden": 0, @@ -2249,6 +2309,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "base_taxes_and_charges_added", "fieldtype": "Currency", "hidden": 0, @@ -2283,6 +2344,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "base_taxes_and_charges_deducted", "fieldtype": "Currency", "hidden": 0, @@ -2317,6 +2379,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "base_total_taxes_and_charges", "fieldtype": "Currency", "hidden": 0, @@ -2351,6 +2414,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break_39", "fieldtype": "Column Break", "hidden": 0, @@ -2382,6 +2446,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "taxes_and_charges_added", "fieldtype": "Currency", "hidden": 0, @@ -2416,6 +2481,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "taxes_and_charges_deducted", "fieldtype": "Currency", "hidden": 0, @@ -2450,6 +2516,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "total_taxes_and_charges", "fieldtype": "Currency", "hidden": 0, @@ -2484,6 +2551,7 @@ "collapsible": 1, "collapsible_depends_on": "discount_amount", "columns": 0, + "fetch_if_empty": 0, "fieldname": "discount_section", "fieldtype": "Section Break", "hidden": 0, @@ -2517,6 +2585,7 @@ "collapsible": 0, "columns": 0, "default": "Grand Total", + "fetch_if_empty": 0, "fieldname": "apply_discount_on", "fieldtype": "Select", "hidden": 0, @@ -2550,6 +2619,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "base_discount_amount", "fieldtype": "Currency", "hidden": 0, @@ -2583,6 +2653,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break_45", "fieldtype": "Column Break", "hidden": 0, @@ -2614,6 +2685,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "additional_discount_percentage", "fieldtype": "Float", "hidden": 0, @@ -2646,6 +2718,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "discount_amount", "fieldtype": "Currency", "hidden": 0, @@ -2679,6 +2752,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "totals_section", "fieldtype": "Section Break", "hidden": 0, @@ -2710,6 +2784,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "base_grand_total", "fieldtype": "Currency", "hidden": 0, @@ -2744,6 +2819,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "base_rounding_adjustment", "fieldtype": "Currency", "hidden": 0, @@ -2778,6 +2854,7 @@ "collapsible": 0, "columns": 0, "description": "In Words will be visible once you save the Purchase Order.", + "fetch_if_empty": 0, "fieldname": "base_in_words", "fieldtype": "Data", "hidden": 0, @@ -2811,6 +2888,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "base_rounded_total", "fieldtype": "Currency", "hidden": 0, @@ -2845,6 +2923,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break4", "fieldtype": "Column Break", "hidden": 0, @@ -2876,6 +2955,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "grand_total", "fieldtype": "Currency", "hidden": 0, @@ -2910,6 +2990,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "rounding_adjustment", "fieldtype": "Currency", "hidden": 0, @@ -2943,6 +3024,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "rounded_total", "fieldtype": "Currency", "hidden": 0, @@ -2975,6 +3057,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "disable_rounded_total", "fieldtype": "Check", "hidden": 0, @@ -3007,6 +3090,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "in_words", "fieldtype": "Data", "hidden": 0, @@ -3040,6 +3124,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "advance_paid", "fieldtype": "Currency", "hidden": 0, @@ -3072,6 +3157,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "payment_schedule_section", "fieldtype": "Section Break", "hidden": 0, @@ -3104,6 +3190,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "payment_terms_template", "fieldtype": "Link", "hidden": 0, @@ -3137,6 +3224,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "payment_schedule", "fieldtype": "Table", "hidden": 0, @@ -3171,6 +3259,7 @@ "collapsible": 1, "collapsible_depends_on": "terms", "columns": 0, + "fetch_if_empty": 0, "fieldname": "terms_section_break", "fieldtype": "Section Break", "hidden": 0, @@ -3204,6 +3293,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "tc_name", "fieldtype": "Link", "hidden": 0, @@ -3238,6 +3328,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "terms", "fieldtype": "Text Editor", "hidden": 0, @@ -3271,6 +3362,7 @@ "bold": 0, "collapsible": 1, "columns": 0, + "fetch_if_empty": 0, "fieldname": "more_info", "fieldtype": "Section Break", "hidden": 0, @@ -3304,6 +3396,7 @@ "collapsible": 0, "columns": 0, "default": "Draft", + "fetch_if_empty": 0, "fieldname": "status", "fieldtype": "Select", "hidden": 0, @@ -3338,6 +3431,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "ref_sq", "fieldtype": "Data", "hidden": 1, @@ -3371,6 +3465,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "party_account_currency", "fieldtype": "Link", "hidden": 1, @@ -3404,6 +3499,41 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, + "fieldname": "inter_company_order_reference", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Inter Company Order Reference", + "length": 0, + "no_copy": 0, + "options": "Sales Order", + "permlevel": 0, + "precision": "", + "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, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break_74", "fieldtype": "Column Break", "hidden": 0, @@ -3437,6 +3567,7 @@ "columns": 0, "depends_on": "eval:!doc.__islocal", "description": "", + "fetch_if_empty": 0, "fieldname": "per_received", "fieldtype": "Percent", "hidden": 0, @@ -3472,6 +3603,7 @@ "columns": 0, "depends_on": "eval:!doc.__islocal", "description": "", + "fetch_if_empty": 0, "fieldname": "per_billed", "fieldtype": "Percent", "hidden": 0, @@ -3505,6 +3637,7 @@ "bold": 0, "collapsible": 1, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break5", "fieldtype": "Section Break", "hidden": 0, @@ -3906,17 +4039,15 @@ } ], "has_web_view": 0, - "hide_heading": 0, "hide_toolbar": 0, "icon": "fa fa-file-text", "idx": 105, - "image_view": 0, "in_create": 0, "is_submittable": 1, "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2019-02-14 19:36:49.390935", + "modified": "2019-04-18 19:43:17.239390", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", @@ -4001,7 +4132,6 @@ ], "quick_entry": 0, "read_only": 0, - "read_only_onload": 1, "search_fields": "status, transaction_date, supplier,grand_total", "show_name_in_global_search": 1, "sort_field": "modified", diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 6a4c818b5b8..e5156a32b7f 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -17,6 +17,8 @@ from erpnext.accounts.party import get_party_account_currency from six import string_types from erpnext.stock.doctype.item.item import get_item_defaults from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults +from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_doc,\ + unlink_inter_company_doc form_grid_templates = { "items": "templates/form_grid/item_grid.html" @@ -56,6 +58,7 @@ class PurchaseOrder(BuyingController): self.validate_bom_for_subcontracting_items() self.create_raw_materials_supplied("supplied_items") self.set_received_qty_for_drop_ship_items() + validate_inter_company_party(self.doctype, self.supplier, self.company, self.inter_company_order_reference) def validate_with_previous_doc(self): super(PurchaseOrder, self).validate_with_previous_doc({ @@ -219,6 +222,7 @@ class PurchaseOrder(BuyingController): self.update_blanket_order() + update_linked_doc(self.doctype, self.name, self.inter_company_order_reference) def on_cancel(self): super(PurchaseOrder, self).on_cancel() @@ -244,6 +248,7 @@ class PurchaseOrder(BuyingController): self.update_blanket_order() + unlink_inter_company_doc(self.doctype, self.name, self.inter_company_order_reference) def on_update(self): pass @@ -490,3 +495,9 @@ def update_status(status, name): po = frappe.get_doc("Purchase Order", name) po.update_status(status) po.update_delivered_qty_in_sales_order() + +@frappe.whitelist() +def make_inter_company_sales_order(source_name, target_doc=None): + from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_transaction + return make_inter_company_transaction("Purchase Order", source_name, target_doc) + diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index adb58a1307f..dc22b5b0fee 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -204,6 +204,20 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( erpnext.utils.make_subscription(doc.doctype, doc.name) }, __('Create')) } + + if (doc.docstatus === 1 && !doc.inter_company_order_reference) { + let me = this; + frappe.model.with_doc("Customer", me.frm.doc.customer, () => { + let customer = frappe.model.get_doc("Customer", me.frm.doc.customer); + let internal = customer.is_internal_customer; + let disabled = customer.disabled; + if (internal === 1 && disabled === 0) { + me.frm.add_custom_button("Inter Company Order", function() { + me.make_inter_company_order(); + }, __('Create')); + } + }); + } } // payment request if(flt(doc.per_billed)==0) { @@ -500,6 +514,13 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( }) }, + make_inter_company_order: function() { + frappe.model.open_mapped_doc({ + method: "erpnext.selling.doctype.sales_order.sales_order.make_inter_company_purchase_order", + frm: this.frm + }); + }, + make_maintenance_visit: function() { frappe.model.open_mapped_doc({ method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_visit", diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index 30123db3565..95c803d8f4a 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -1449,6 +1449,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "pricing_rule_details", "fieldtype": "Section Break", "hidden": 0, @@ -1481,6 +1482,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "pricing_rules", "fieldtype": "Table", "hidden": 0, @@ -1514,6 +1516,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "section_break_31", "fieldtype": "Section Break", "hidden": 0, @@ -3230,6 +3233,40 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "inter_company_order_reference", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Inter Company Order Reference", + "length": 0, + "no_copy": 0, + "options": "Purchase Order", + "permlevel": 0, + "precision": "", + "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, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -4292,17 +4329,15 @@ } ], "has_web_view": 0, - "hide_heading": 0, "hide_toolbar": 0, "icon": "fa fa-file-text", "idx": 105, - "image_view": 0, "in_create": 0, "is_submittable": 1, "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2019-02-13 01:02:45.882179", + "modified": "2019-04-18 12:05:23.464968", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", @@ -4425,7 +4460,6 @@ ], "quick_entry": 0, "read_only": 0, - "read_only_onload": 1, "search_fields": "status,transaction_date,customer,customer_name, territory,order_type,company", "show_name_in_global_search": 1, "sort_field": "modified", diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index d09e2811379..fc11e110922 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -19,6 +19,8 @@ from erpnext.selling.doctype.customer.customer import check_credit_limit from erpnext.stock.doctype.item.item import get_item_defaults from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults from erpnext.manufacturing.doctype.production_plan.production_plan import get_items_for_material_requests +from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_doc,\ + unlink_inter_company_doc form_grid_templates = { "items": "templates/form_grid/item_grid.html" @@ -42,6 +44,7 @@ class SalesOrder(SellingController): self.validate_warehouse() self.validate_drop_ship() self.validate_serial_no_based_delivery() + validate_inter_company_party(self.doctype, self.customer, self.company, self.inter_company_order_reference) from erpnext.stock.doctype.packed_item.packed_item import make_packing_list make_packing_list(self) @@ -182,6 +185,8 @@ class SalesOrder(SellingController): self.update_blanket_order() + update_linked_doc(self.doctype, self.name, self.inter_company_order_reference) + def on_cancel(self): super(SalesOrder, self).on_cancel() @@ -198,6 +203,8 @@ class SalesOrder(SellingController): self.update_blanket_order() + unlink_inter_company_doc(self.doctype, self.name, self.inter_company_order_reference) + def update_project(self): if frappe.db.get_single_value('Selling Settings', 'sales_update_frequency') != "Each Transaction": return @@ -764,6 +771,7 @@ def make_purchase_order_for_drop_shipment(source_name, for_supplier=None, target target.apply_discount_on = "" target.additional_discount_percentage = 0.0 target.discount_amount = 0.0 + target.inter_company_order_reference = "" default_price_list = frappe.get_value("Supplier", supplier, "default_price_list") if default_price_list: @@ -970,4 +978,9 @@ def make_raw_material_request(items, company, sales_order, project=None): material_request.flags.ignore_permissions = 1 material_request.run_method("set_missing_values") material_request.submit() - return material_request \ No newline at end of file + return material_request + +@frappe.whitelist() +def make_inter_company_purchase_order(source_name, target_doc=None): + from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_transaction + return make_inter_company_transaction("Sales Order", source_name, target_doc)