From 87f2401c1e8c921e1c8afcd371c0b29c32e9e55b Mon Sep 17 00:00:00 2001 From: nabinhait Date: Wed, 16 Jul 2014 19:48:29 +0530 Subject: [PATCH] Landed Cost on_submit and gl entries for PR --- .../purchase_invoice/purchase_invoice.py | 2 +- .../doctype/sales_invoice/sales_invoice.py | 2 +- erpnext/controllers/buying_controller.py | 10 +- erpnext/controllers/stock_controller.py | 2 +- .../doctype/delivery_note/delivery_note.py | 2 +- .../landed_cost_voucher.py | 16 ++- .../purchase_receipt/purchase_receipt.py | 97 +++++++++++++++++-- .../purchase_receipt_item.json | 7 ++ .../stock/doctype/stock_entry/stock_entry.py | 2 +- .../stock_reconciliation.py | 2 +- 10 files changed, 124 insertions(+), 18 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 55e3247636..3b6ad82cdc 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -387,7 +387,7 @@ class PurchaseInvoice(BuyingController): self.update_prevdoc_status() self.update_billing_status_for_zero_amount_refdoc("Purchase Order") - self.make_cancel_gl_entries() + self.make_gl_entries_on_cancel() def on_update(self): pass diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 1205646cbf..481ae098b3 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -121,7 +121,7 @@ class SalesInvoice(SellingController): self.update_prevdoc_status() self.update_billing_status_for_zero_amount_refdoc("Sales Order") - self.make_cancel_gl_entries() + self.make_gl_entries_on_cancel() def update_status_updater_args(self): if cint(self.update_stock): diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 85d7a9ee60..9f2b78e022 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -193,9 +193,13 @@ class BuyingController(StockController): "UOM Conversion Detail", {"parent": item.item_code, "uom": item.uom}, "conversion_factor")) or 1 qty_in_stock_uom = flt(item.qty * item.conversion_factor) - rm_supp_cost = item.rm_supp_cost if self.doctype=="Purchase Receipt" else 0.0 - item.valuation_rate = ((item.base_amount + item.item_tax_amount + rm_supp_cost) - / qty_in_stock_uom) + rm_supp_cost = flt(item.rm_supp_cost) if self.doctype=="Purchase Receipt" else 0.0 + + landed_cost_voucher_amount = flt(item.landed_cost_voucher_amount) \ + if self.doctype == "Purchase Receipt" else 0.0 + + item.valuation_rate = ((item.base_amount + item.item_tax_amount + rm_supp_cost + + landed_cost_voucher_amount) / qty_in_stock_uom) else: item.valuation_rate = 0.0 diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 27437a396a..a1d9a5b00d 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -274,7 +274,7 @@ class StockController(AccountsController): from erpnext.stock.stock_ledger import make_sl_entries make_sl_entries(sl_entries, is_amended) - def make_cancel_gl_entries(self): + def make_gl_entries_on_cancel(self): if frappe.db.sql("""select name from `tabGL Entry` where voucher_type=%s and voucher_no=%s""", (self.doctype, self.name)): self.make_gl_entries() diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index e831c47fe7..864329d3ea 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -196,7 +196,7 @@ class DeliveryNote(SellingController): frappe.db.set(self, 'status', 'Cancelled') self.cancel_packing_slips() - self.make_cancel_gl_entries() + self.make_gl_entries_on_cancel() def validate_packed_qty(self): """ diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py index 79e25b3749..9653242cfa 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -16,7 +16,10 @@ class LandedCostVoucher(Document): for pr in self.get("landed_cost_purchase_receipts"): pr_items = frappe.db.sql("""select pr_tem.item_code, pr_tem.description, pr_tem.qty, pr_tem.rate, pr_tem.amount, pr_tem.name - from `tabPurchase Receipt Item` where parent = %s""", pr.purchase_receipt, as_dict=True) + from `tabPurchase Receipt Item` pr_item where parent = %s + and (select name form tabItem where name = pr_item.item_code and is_stock_item = 'Yes')""", + pr.purchase_receipt, as_dict=True) + for d in pr_items: item = self.append("landed_cost_items") item.item_code = d.item_code @@ -73,7 +76,14 @@ class LandedCostVoucher(Document): def on_submit(self): purchase_receipts = list(set([d.purchase_receipt for d in self.get("landed_cost_items")])) - + self.delete_sle_and_gle(purchase_receipts) for purchase_receipt in purchase_receipts: pr = frappe.get_doc("Purchase Receipt", purchase_receipt) - \ No newline at end of file + pr.update_valuation_rate() + pr.update_stock() + pr.make_gl_entries() + + def delete_sle_and_gle(self, purchase_receipts): + for doctype in ["Stock Ledger Entry", "GL Entry"]: + frappe.db.sql("""delete from `tab%s` where voucher_type='Purchase Receipt' + and voucher_no in (%s)""" % (doctype, ', '.join(['%s']*len(purchase_receipts))), purchase_receipts) \ No newline at end of file diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 5f56149607..d627386e61 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -67,9 +67,16 @@ class PurchaseReceipt(BuyingController): # sub-contracting self.validate_for_subcontracting() self.create_raw_materials_supplied("pr_raw_material_details") - + self.set_landed_cost_voucher_amount() self.update_valuation_rate("purchase_receipt_details") - + + def set_landed_cost_voucher_amount(self, voucher_detail): + for d in self.get("purchase_receipt_details"): + lc_voucher_amount = frappe.db.sql("""select sum(ifnull(applicable_charges)) + from `tabLanded Cost Item` + where docstatus = 1 and pr_item_row_id = %s""", voucher_detail) + d.landed_cost_voucher_amount = lc_voucher_amount[0][0] if lc_voucher_amount else 0.0 + def validate_rejected_warehouse(self): for d in self.get("purchase_receipt_details"): if flt(d.rejected_qty) and not d.rejected_warehouse: @@ -265,7 +272,7 @@ class PurchaseReceipt(BuyingController): self.update_prevdoc_status() pc_obj.update_last_purchase_rate(self, 0) - self.make_cancel_gl_entries() + self.make_gl_entries_on_cancel() def get_current_stock(self): for d in self.get('pr_raw_material_details'): @@ -277,10 +284,88 @@ class PurchaseReceipt(BuyingController): return frappe.get_doc('Purchase Common').get_rate(arg,self) def get_gl_entries(self, warehouse_account=None): - against_stock_account = self.get_company_default("stock_received_but_not_billed") + from erpnext.accounts.general_ledger import process_gl_map + + stock_rbnb = self.get_company_default("stock_received_but_not_billed") + expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation") + default_cost_center = self.get_company_default("cost_center") + against_expense_account = None + + gl_entries = [] + warehouse_with_no_account = [] + stock_items = self.get_stock_items() + for d in self.get("purchase_receipt_details"): + if d.item_code in stock_items and flt(d.valuation_rate): + if warehouse_account.get(d.warehouse) or warehouse_account.get(d.rejected_warehouse): + self.check_expense_account(d) + + # warehouse account + if flt(d.qty): + gl_list.append(self.get_gl_dict({ + "account": warehouse_account[d.warehouse], + "against": against_expense_account, + "cost_center": default_cost_center, + "remarks": self.get("remarks") or "Accounting Entry for Stock", + "debit": flt(d.valuation_rate) * flt(d.qty) * flt(d.conversion_factor) + })) + + # rejected warehouse + if flt(d.rejected_qty): + gl_list.append(self.get_gl_dict({ + "account": warehouse_account[d.rejected_warehouse], + "against": against_expense_account, + "cost_center": default_cost_center, + "remarks": self.get("remarks") or "Accounting Entry for Stock", + "debit": flt(d.valuation_rate) * flt(d.rejected_qty) * flt(d.conversion_factor) + })) - gl_entries = super(PurchaseReceipt, self).get_gl_entries(warehouse_account, against_stock_account) - return gl_entries + # stock received but not billed + gl_list.append(self.get_gl_dict({ + "account": stock_rbnb, + "against": warehouse_account[d.warehouse], + "cost_center": default_cost_center, + "remarks": self.get("remarks") or "Accounting Entry for Stock", + "credit": flt(d.base_amount, 2) + })) + + if flt(d.landed_cost_voucher_amount): + gl_list.append(self.get_gl_dict({ + "account": expenses_included_in_valuation, + "against": warehouse_account[d.warehouse], + "cost_center": default_cost_center, + "remarks": self.get("remarks") or "Accounting Entry for Stock", + "credit": flt(d.landed_cost_voucher_amount) + })) + + elif d.warehouse not in warehouse_with_no_account or \ + d.rejected_warehouse not in warehouse_with_no_account: + warehouse_with_no_account.append(d.warehouse) + + if warehouse_with_no_account: + msgprint(_("No accounting entries for the following warehouses") + ": \n" + + "\n".join(warehouse_with_no_account)) + + valuation_tax = {} + for tax in self.get("other_charges"): + if tax.category in ("Valuation", "Valuation and Total") and flt(tax.tax_amount): + if not tax.cost_center: + frappe.throw(_("Cost Center is required in row {0} in Taxes table for type {1}").format(tax.idx, _(tax.category))) + valuation_tax.setdefault(tax.cost_center, 0) + valuation_tax[tax.cost_center] += \ + (tax.add_deduct_tax == "Add" and 1 or -1) * flt(tax.tax_amount) + + for cost_center, amount in valuation_tax.items(): + gl_entries.append( + self.get_gl_dict({ + "account": expenses_included_in_valuation, + "cost_center": cost_center, + # "against": , + "credit": amount, + "remarks": self.remarks or "Accounting Entry for Stock" + }) + ) + + return process_gl_map(gl_entries) @frappe.whitelist() diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json index 8c5e73297b..76d62945b2 100755 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json @@ -501,6 +501,13 @@ "search_index": 0, "width": "150px" }, + { + "fieldname": "landed_cost_voucher_amount", + "fieldtype": "Currency", + "label": "Landed Cost Voucher Amount", + "permlevel": 0, + "read_only": 1 + }, { "fieldname": "valuation_rate", "fieldtype": "Currency", diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 1da2ad53d0..bdd760ba4a 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -65,7 +65,7 @@ class StockEntry(StockController): def on_cancel(self): self.update_stock_ledger() self.update_production_order() - self.make_cancel_gl_entries() + self.make_gl_entries_on_cancel() def validate_fiscal_year(self): from erpnext.accounts.utils import validate_fiscal_year diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index bb1e3e2873..8b32211177 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -27,7 +27,7 @@ class StockReconciliation(StockController): def on_cancel(self): self.delete_and_repost_sle() - self.make_cancel_gl_entries() + self.make_gl_entries_on_cancel() def validate_data(self): if not self.reconciliation_json: