diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 9e9d18ddd86..cf78e000eac 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -375,12 +375,17 @@ class PurchaseInvoice(BuyingController): def set_inter_company_account(self): """ Set intercompany account for inter warehouse transactions - This account will be used in case billing company and internal supplier's + This account will be used in case billing company and internal customer's representation company is same """ if self.is_internal_transfer() and not self.inter_company_account: - self.inter_company_account = frappe.get_cached_value('Company', self.company, 'default_inter_company_account') + inter_company_account = frappe.get_cached_value('Company', self.company, 'default_inter_company_account') + + if not inter_company_account: + msg = _("Please select inter-company account or add default inter-company account for company {0}").format( + frappe.bold(self.company)) + frappe.throw(msg) def is_internal_transfer(self): """ @@ -474,7 +479,6 @@ class PurchaseInvoice(BuyingController): self.make_payment_gl_entries(gl_entries) self.make_write_off_gl_entry(gl_entries) self.make_gle_for_rounding_adjustment(gl_entries) - return gl_entries def check_asset_cwip_enabled(self): @@ -514,55 +518,55 @@ class PurchaseInvoice(BuyingController): def make_item_gl_entries(self, gl_entries): # item gl entries - if not self.is_internal_transfer(): - stock_items = self.get_stock_items() - if self.update_stock and self.auto_accounting_for_stock: - warehouse_account = get_warehouse_account_map(self.company) + stock_items = self.get_stock_items() + if self.update_stock and self.auto_accounting_for_stock: + warehouse_account = get_warehouse_account_map(self.company) - landed_cost_entries = get_item_account_wise_additional_cost(self.name) + landed_cost_entries = get_item_account_wise_additional_cost(self.name) - voucher_wise_stock_value = {} - if self.update_stock: - for d in frappe.get_all('Stock Ledger Entry', - fields = ["voucher_detail_no", "stock_value_difference"], filters={'voucher_no': self.name}): - voucher_wise_stock_value.setdefault(d.voucher_detail_no, d.stock_value_difference) + voucher_wise_stock_value = {} + if self.update_stock: + for d in frappe.get_all('Stock Ledger Entry', + fields = ["voucher_detail_no", "stock_value_difference"], filters={'voucher_no': self.name}): + voucher_wise_stock_value.setdefault(d.voucher_detail_no, d.stock_value_difference) - valuation_tax_accounts = [d.account_head for d in self.get("taxes") - if d.category in ('Valuation', 'Total and Valuation') - and flt(d.base_tax_amount_after_discount_amount)] + valuation_tax_accounts = [d.account_head for d in self.get("taxes") + if d.category in ('Valuation', 'Total and Valuation') + and flt(d.base_tax_amount_after_discount_amount)] - for item in self.get("items"): - if flt(item.base_net_amount): - account_currency = get_account_currency(item.expense_account) - if item.item_code: - asset_category = frappe.get_cached_value("Item", item.item_code, "asset_category") + for item in self.get("items"): + if flt(item.base_net_amount): + account_currency = get_account_currency(item.expense_account) + if item.item_code: + asset_category = frappe.get_cached_value("Item", item.item_code, "asset_category") - if self.update_stock and self.auto_accounting_for_stock and item.item_code in stock_items: - # warehouse account - warehouse_debit_amount = self.make_stock_adjustment_entry(gl_entries, - item, voucher_wise_stock_value, account_currency) + if self.update_stock and self.auto_accounting_for_stock and item.item_code in stock_items: + # warehouse account + warehouse_debit_amount = self.make_stock_adjustment_entry(gl_entries, + item, voucher_wise_stock_value, account_currency) - if item.from_warehouse: + if item.from_warehouse: + gl_entries.append(self.get_gl_dict({ + "account": warehouse_account[item.warehouse]['account'], + "against": warehouse_account[item.from_warehouse]["account"], + "cost_center": item.cost_center, + "project": item.project or self.project, + "remarks": self.get("remarks") or _("Accounting Entry for Stock"), + "debit": warehouse_debit_amount, + }, warehouse_account[item.warehouse]["account_currency"], item=item)) - gl_entries.append(self.get_gl_dict({ - "account": warehouse_account[item.warehouse]['account'], - "against": warehouse_account[item.from_warehouse]["account"], - "cost_center": item.cost_center, - "project": item.project or self.project, - "remarks": self.get("remarks") or _("Accounting Entry for Stock"), - "debit": warehouse_debit_amount, - }, warehouse_account[item.warehouse]["account_currency"], item=item)) - - # Intentionally passed negative debit amount to avoid incorrect GL Entry validation - gl_entries.append(self.get_gl_dict({ - "account": warehouse_account[item.from_warehouse]['account'], - "against": warehouse_account[item.warehouse]["account"], - "cost_center": item.cost_center, - "project": item.project or self.project, - "remarks": self.get("remarks") or _("Accounting Entry for Stock"), - "debit": -1 * flt(item.base_net_amount, item.precision("base_net_amount")), - }, warehouse_account[item.from_warehouse]["account_currency"], item=item)) + # Intentionally passed negative debit amount to avoid incorrect GL Entry validation + gl_entries.append(self.get_gl_dict({ + "account": warehouse_account[item.from_warehouse]['account'], + "against": warehouse_account[item.warehouse]["account"], + "cost_center": item.cost_center, + "project": item.project or self.project, + "remarks": self.get("remarks") or _("Accounting Entry for Stock"), + "debit": -1 * flt(item.base_net_amount, item.precision("base_net_amount")), + }, warehouse_account[item.from_warehouse]["account_currency"], item=item)) + # Do not book expense for transfer within same company transfer + if not self.is_internal_transfer(): gl_entries.append( self.get_gl_dict({ "account": item.expense_account, @@ -574,128 +578,128 @@ class PurchaseInvoice(BuyingController): }, account_currency, item=item) ) - else: - gl_entries.append( - self.get_gl_dict({ - "account": item.expense_account, - "against": self.supplier, - "debit": warehouse_debit_amount, - "remarks": self.get("remarks") or _("Accounting Entry for Stock"), - "cost_center": item.cost_center, - "project": item.project or self.project - }, account_currency, item=item) - ) + else: + gl_entries.append( + self.get_gl_dict({ + "account": item.expense_account, + "against": self.supplier, + "debit": warehouse_debit_amount, + "remarks": self.get("remarks") or _("Accounting Entry for Stock"), + "cost_center": item.cost_center, + "project": item.project or self.project + }, account_currency, item=item) + ) - # Amount added through landed-cost-voucher - if landed_cost_entries: - for account, amount in iteritems(landed_cost_entries[(item.item_code, item.name)]): - gl_entries.append(self.get_gl_dict({ - "account": account, - "against": item.expense_account, - "cost_center": item.cost_center, - "remarks": self.get("remarks") or _("Accounting Entry for Stock"), - "credit": flt(amount), - "project": item.project or self.project - }, item=item)) - - # sub-contracting warehouse - if flt(item.rm_supp_cost): - supplier_warehouse_account = warehouse_account[self.supplier_warehouse]["account"] - if not supplier_warehouse_account: - frappe.throw(_("Please set account in Warehouse {0}") - .format(self.supplier_warehouse)) + # Amount added through landed-cost-voucher + if landed_cost_entries: + for account, amount in iteritems(landed_cost_entries[(item.item_code, item.name)]): gl_entries.append(self.get_gl_dict({ - "account": supplier_warehouse_account, + "account": account, "against": item.expense_account, "cost_center": item.cost_center, - "project": item.project or self.project, "remarks": self.get("remarks") or _("Accounting Entry for Stock"), - "credit": flt(item.rm_supp_cost) - }, warehouse_account[self.supplier_warehouse]["account_currency"], item=item)) + "credit": flt(amount), + "project": item.project or self.project + }, item=item)) - elif not item.is_fixed_asset or (item.is_fixed_asset and not is_cwip_accounting_enabled(asset_category)): - expense_account = (item.expense_account - if (not item.enable_deferred_expense or self.is_return) else item.deferred_expense_account) + # sub-contracting warehouse + if flt(item.rm_supp_cost): + supplier_warehouse_account = warehouse_account[self.supplier_warehouse]["account"] + if not supplier_warehouse_account: + frappe.throw(_("Please set account in Warehouse {0}") + .format(self.supplier_warehouse)) + gl_entries.append(self.get_gl_dict({ + "account": supplier_warehouse_account, + "against": item.expense_account, + "cost_center": item.cost_center, + "project": item.project or self.project, + "remarks": self.get("remarks") or _("Accounting Entry for Stock"), + "credit": flt(item.rm_supp_cost) + }, warehouse_account[self.supplier_warehouse]["account_currency"], item=item)) - if not item.is_fixed_asset: - amount = flt(item.base_net_amount, item.precision("base_net_amount")) - else: - amount = flt(item.base_net_amount + item.item_tax_amount, item.precision("base_net_amount")) + elif not item.is_fixed_asset or (item.is_fixed_asset and not is_cwip_accounting_enabled(asset_category)): + expense_account = (item.expense_account + if (not item.enable_deferred_expense or self.is_return) else item.deferred_expense_account) - auto_accounting_for_non_stock_items = cint(frappe.db.get_value('Company', self.company, 'enable_perpetual_inventory_for_non_stock_items')) + if not item.is_fixed_asset: + amount = flt(item.base_net_amount, item.precision("base_net_amount")) + else: + amount = flt(item.base_net_amount + item.item_tax_amount, item.precision("base_net_amount")) - if auto_accounting_for_non_stock_items: - service_received_but_not_billed_account = self.get_company_default("service_received_but_not_billed") + auto_accounting_for_non_stock_items = cint(frappe.db.get_value('Company', self.company, 'enable_perpetual_inventory_for_non_stock_items')) - if item.purchase_receipt: - # Post reverse entry for Stock-Received-But-Not-Billed if it is booked in Purchase Receipt - expense_booked_in_pr = frappe.db.get_value('GL Entry', {'is_cancelled': 0, - 'voucher_type': 'Purchase Receipt', 'voucher_no': item.purchase_receipt, 'voucher_detail_no': item.pr_detail, - 'account':service_received_but_not_billed_account}, ['name']) + if auto_accounting_for_non_stock_items: + service_received_but_not_billed_account = self.get_company_default("service_received_but_not_billed") - if expense_booked_in_pr: - expense_account = service_received_but_not_billed_account + if item.purchase_receipt: + # Post reverse entry for Stock-Received-But-Not-Billed if it is booked in Purchase Receipt + expense_booked_in_pr = frappe.db.get_value('GL Entry', {'is_cancelled': 0, + 'voucher_type': 'Purchase Receipt', 'voucher_no': item.purchase_receipt, 'voucher_detail_no': item.pr_detail, + 'account':service_received_but_not_billed_account}, ['name']) + + if expense_booked_in_pr: + expense_account = service_received_but_not_billed_account + + gl_entries.append(self.get_gl_dict({ + "account": expense_account, + "against": self.supplier, + "debit": amount, + "cost_center": item.cost_center, + "project": item.project or self.project + }, account_currency, item=item)) + + # If asset is bought through this document and not linked to PR + if self.update_stock and item.landed_cost_voucher_amount: + expenses_included_in_asset_valuation = self.get_company_default("expenses_included_in_asset_valuation") + # Amount added through landed-cost-voucher + gl_entries.append(self.get_gl_dict({ + "account": expenses_included_in_asset_valuation, + "against": expense_account, + "cost_center": item.cost_center, + "remarks": self.get("remarks") or _("Accounting Entry for Stock"), + "credit": flt(item.landed_cost_voucher_amount), + "project": item.project or self.project + }, item=item)) gl_entries.append(self.get_gl_dict({ - "account": expense_account, - "against": self.supplier, - "debit": amount, - "cost_center": item.cost_center, - "project": item.project or self.project - }, account_currency, item=item)) + "account": expense_account, + "against": expenses_included_in_asset_valuation, + "cost_center": item.cost_center, + "remarks": self.get("remarks") or _("Accounting Entry for Stock"), + "debit": flt(item.landed_cost_voucher_amount), + "project": item.project or self.project + }, item=item)) - # If asset is bought through this document and not linked to PR - if self.update_stock and item.landed_cost_voucher_amount: - expenses_included_in_asset_valuation = self.get_company_default("expenses_included_in_asset_valuation") - # Amount added through landed-cost-voucher - gl_entries.append(self.get_gl_dict({ - "account": expenses_included_in_asset_valuation, - "against": expense_account, - "cost_center": item.cost_center, - "remarks": self.get("remarks") or _("Accounting Entry for Stock"), - "credit": flt(item.landed_cost_voucher_amount), - "project": item.project or self.project - }, item=item)) + # update gross amount of asset bought through this document + assets = frappe.db.get_all('Asset', + filters={ 'purchase_invoice': self.name, 'item_code': item.item_code } + ) + for asset in assets: + frappe.db.set_value("Asset", asset.name, "gross_purchase_amount", flt(item.valuation_rate)) + frappe.db.set_value("Asset", asset.name, "purchase_receipt_amount", flt(item.valuation_rate)) - gl_entries.append(self.get_gl_dict({ - "account": expense_account, - "against": expenses_included_in_asset_valuation, - "cost_center": item.cost_center, - "remarks": self.get("remarks") or _("Accounting Entry for Stock"), - "debit": flt(item.landed_cost_voucher_amount), - "project": item.project or self.project - }, item=item)) + if self.auto_accounting_for_stock and self.is_opening == "No" and \ + item.item_code in stock_items and item.item_tax_amount: + # Post reverse entry for Stock-Received-But-Not-Billed if it is booked in Purchase Receipt + if item.purchase_receipt and valuation_tax_accounts: + negative_expense_booked_in_pr = frappe.db.sql("""select name from `tabGL Entry` + where voucher_type='Purchase Receipt' and voucher_no=%s and account in %s""", + (item.purchase_receipt, valuation_tax_accounts)) - # update gross amount of asset bought through this document - assets = frappe.db.get_all('Asset', - filters={ 'purchase_invoice': self.name, 'item_code': item.item_code } + if not negative_expense_booked_in_pr: + gl_entries.append( + self.get_gl_dict({ + "account": self.stock_received_but_not_billed, + "against": self.supplier, + "debit": flt(item.item_tax_amount, item.precision("item_tax_amount")), + "remarks": self.remarks or "Accounting Entry for Stock", + "cost_center": self.cost_center, + "project": item.project or self.project + }, item=item) ) - for asset in assets: - frappe.db.set_value("Asset", asset.name, "gross_purchase_amount", flt(item.valuation_rate)) - frappe.db.set_value("Asset", asset.name, "purchase_receipt_amount", flt(item.valuation_rate)) - if self.auto_accounting_for_stock and self.is_opening == "No" and \ - item.item_code in stock_items and item.item_tax_amount: - # Post reverse entry for Stock-Received-But-Not-Billed if it is booked in Purchase Receipt - if item.purchase_receipt and valuation_tax_accounts: - negative_expense_booked_in_pr = frappe.db.sql("""select name from `tabGL Entry` - where voucher_type='Purchase Receipt' and voucher_no=%s and account in %s""", - (item.purchase_receipt, valuation_tax_accounts)) - - if not negative_expense_booked_in_pr: - gl_entries.append( - self.get_gl_dict({ - "account": self.stock_received_but_not_billed, - "against": self.supplier, - "debit": flt(item.item_tax_amount, item.precision("item_tax_amount")), - "remarks": self.remarks or "Accounting Entry for Stock", - "cost_center": self.cost_center, - "project": item.project or self.project - }, item=item) - ) - - self.negative_expense_to_be_booked += flt(item.item_tax_amount, \ - item.precision("item_tax_amount")) + self.negative_expense_to_be_booked += flt(item.item_tax_amount, \ + item.precision("item_tax_amount")) def get_asset_gl_entry(self, gl_entries): arbnb_account = self.get_company_default("asset_received_but_not_billed") diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 8b912d04c31..0aaf78aeedc 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -579,7 +579,12 @@ class SalesInvoice(SellingController): """ if self.is_internal_transfer() and not self.inter_company_account: - self.inter_company_account = frappe.get_cached_value('Company', self.company, 'default_inter_company_account') + inter_company_account = frappe.get_cached_value('Company', self.company, 'default_inter_company_account') + + if not inter_company_account: + msg = _("Please select inter-company account or add default inter-company account for company {0}").format( + frappe.bold(self.company)) + frappe.throw(msg) def is_internal_transfer(self): """ @@ -845,27 +850,28 @@ class SalesInvoice(SellingController): def make_item_gl_entries(self, gl_entries): # income account gl entries - if not self.is_internal_transfer(): - for item in self.get("items"): - if flt(item.base_net_amount, item.precision("base_net_amount")): - if item.is_fixed_asset: - asset = frappe.get_doc("Asset", item.asset) + for item in self.get("items"): + if flt(item.base_net_amount, item.precision("base_net_amount")): + if item.is_fixed_asset: + asset = frappe.get_doc("Asset", item.asset) - if (len(asset.finance_books) > 1 and not item.finance_book - and asset.finance_books[0].finance_book): - frappe.throw(_("Select finance book for the item {0} at row {1}") - .format(item.item_code, item.idx)) + if (len(asset.finance_books) > 1 and not item.finance_book + and asset.finance_books[0].finance_book): + frappe.throw(_("Select finance book for the item {0} at row {1}") + .format(item.item_code, item.idx)) - fixed_asset_gl_entries = get_gl_entries_on_asset_disposal(asset, - item.base_net_amount, item.finance_book) + fixed_asset_gl_entries = get_gl_entries_on_asset_disposal(asset, + item.base_net_amount, item.finance_book) - for gle in fixed_asset_gl_entries: - gle["against"] = self.customer - gl_entries.append(self.get_gl_dict(gle, item=item)) + for gle in fixed_asset_gl_entries: + gle["against"] = self.customer + gl_entries.append(self.get_gl_dict(gle, item=item)) - asset.db_set("disposal_date", self.posting_date) - asset.set_status("Sold" if self.docstatus==1 else None) - else: + asset.db_set("disposal_date", self.posting_date) + asset.set_status("Sold" if self.docstatus==1 else None) + else: + # Do not book income for transfer within same company + if not self.is_internal_transfer(): income_account = (item.income_account if (not item.enable_deferred_revenue or self.is_return) else item.deferred_revenue_account) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 05268e5e31c..e992d58e24e 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -103,8 +103,8 @@ class StockController(AccountsController): }, warehouse_account[sle.warehouse]["account_currency"], item=item_row)) # expense account/ target_warehouse / source_warehouse - if item_row.get('target_warehouse') or item_row.get('from_warehouse'): - warehouse = item_row.get('target_warehouse') or item_row.get('from_warehouse') + if item_row.get('target_warehouse'): + warehouse = item_row.get('target_warehouse') expense_account = warehouse_account[warehouse]["account"] else: expense_account = item_row.expense_account