From fc155c7712974434af2a60e035f7b8a97691866b Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 24 Jul 2015 17:50:40 +0530 Subject: [PATCH 1/6] Added tax table in stock entry --- erpnext/accounts/general_ledger.py | 3 +- .../stock/doctype/stock_entry/stock_entry.py | 29 ++++++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index 17fe922a1c26..8081459f2e36 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -11,8 +11,7 @@ class StockAccountInvalidTransaction(frappe.ValidationError): pass -def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, - update_outstanding='Yes'): +def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, update_outstanding='Yes'): if gl_map: if not cancel: gl_map = process_gl_map(gl_map, merge_entries) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 051d9fcbd885..61ef4cdefc91 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -367,6 +367,8 @@ def validate_finished_goods(self): def update_stock_ledger(self): sl_entries = [] for d in self.get('items'): + tax_amount_per_qty = flt(flt(d.tax_amount) / flt(d.qty), d.precision("tax_amount")) + if cstr(d.s_warehouse) and self.docstatus == 1: sl_entries.append(self.get_sl_entries(d, { "warehouse": cstr(d.s_warehouse), @@ -378,7 +380,7 @@ def update_stock_ledger(self): sl_entries.append(self.get_sl_entries(d, { "warehouse": cstr(d.t_warehouse), "actual_qty": flt(d.transfer_qty), - "incoming_rate": flt(d.incoming_rate) + "incoming_rate": flt(d.incoming_rate) + tax_amount_per_qty })) # On cancellation, make stock ledger entry for @@ -392,6 +394,31 @@ def update_stock_ledger(self): })) self.make_sl_entries(sl_entries, self.amended_from and 'Yes' or 'No') + + def get_gl_entries(self, warehouse_account): + expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation") + + gl_entries = super(StockEntry, self).get_gl_entries(warehouse_account) + + for d in self.get("items"): + tax_amount = flt(d.tax_amount, d.precision("tax_amount")) + gl_entries.append(self.get_gl_dict({ + "account": d.expense_account, + "against": expenses_included_in_valuation, + "cost_center": d.cost_center, + "remarks": self.get("remarks") or _("Accounting Entry for Stock"), + "debit": tax_amount + })) + + gl_entries.append(self.get_gl_dict({ + "account": expenses_included_in_valuation, + "against": warehouse_account[d.warehouse], + "cost_center": d.cost_center, + "remarks": self.get("remarks") or _("Accounting Entry for Stock"), + "credit": tax_amount + })) + + return gl_entries def update_production_order(self): def _validate_production_order(pro_doc): From aa879311725303ac18b95bba78211b7326e78472 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 27 Jul 2015 11:40:54 +0530 Subject: [PATCH 2/6] Show only active BOM in stock entry --- erpnext/stock/doctype/stock_entry/stock_entry.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index 04ef935732ca..22652e6820a3 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -10,7 +10,10 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ this.frm.fields_dict.bom_no.get_query = function() { return { - filters:{ 'docstatus': 1 } + filters:{ + "docstatus": 1, + "is_active": 1 + } }; }; From f6aad5ed2d0a492f968269a0948ddb782e400c8e Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 27 Jul 2015 16:00:39 +0530 Subject: [PATCH 3/6] Distribute tax amount between items in stock entry --- .../doctype/stock_entry/stock_entry.json | 29 ++++++++++- .../stock/doctype/stock_entry/stock_entry.py | 48 +++++++++++-------- .../stock_entry_detail.json | 9 +++- 3 files changed, 64 insertions(+), 22 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json index 3c39d42ff6aa..f2ea6d4dc277 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.json +++ b/erpnext/stock/doctype/stock_entry/stock_entry.json @@ -369,6 +369,7 @@ "fieldname": "total_incoming_value", "fieldtype": "Currency", "label": "Total Incoming Value", + "options": "Company:company:default_currency", "permlevel": 0, "precision": "", "read_only": 1 @@ -383,6 +384,7 @@ "fieldname": "total_outgoing_value", "fieldtype": "Currency", "label": "Total Outgoing Value", + "options": "Company:company:default_currency", "permlevel": 0, "precision": "", "read_only": 1 @@ -391,6 +393,7 @@ "fieldname": "value_difference", "fieldtype": "Currency", "label": "Total Value Difference (Out - In)", + "options": "Company:company:default_currency", "permlevel": 0, "precision": "", "read_only": 1 @@ -404,6 +407,30 @@ "permlevel": 0, "precision": "" }, + { + "fieldname": "taxes_section", + "fieldtype": "Section Break", + "label": "Taxes and Charges", + "permlevel": 0, + "precision": "" + }, + { + "fieldname": "taxes", + "fieldtype": "Table", + "label": "Taxes and Charges", + "options": "Landed Cost Taxes and Charges", + "permlevel": 0, + "precision": "" + }, + { + "fieldname": "total_taxes_and_charges", + "fieldtype": "Currency", + "label": "Total Taxes and Charges", + "options": "Company:company:default_currency", + "permlevel": 0, + "precision": "", + "read_only": 1 + }, { "fieldname": "fold", "fieldtype": "Fold", @@ -678,7 +705,7 @@ "is_submittable": 1, "issingle": 0, "max_attachments": 0, - "modified": "2015-07-22 18:47:20.328749", + "modified": "2015-07-24 18:47:55.902154", "modified_by": "Administrator", "module": "Stock", "name": "Stock Entry", diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 61ef4cdefc91..06249edbc1f3 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -50,6 +50,7 @@ def validate(self): self.validate_bom() self.validate_finished_goods() self.validate_with_material_request() + self.distribute_taxes() self.validate_valuation_rate() self.set_total_incoming_outgoing_value() self.set_total_amount() @@ -221,7 +222,7 @@ def validate_valuation_rate(self): if d.s_warehouse and not d.t_warehouse: valuation_at_source += flt(d.amount) if d.t_warehouse and not d.s_warehouse: - valuation_at_target += flt(d.amount) + valuation_at_target += flt(d.amount) + flt(d.tax_amount) if valuation_at_target + 0.001 < valuation_at_source: frappe.throw(_("Total valuation ({0}) for manufactured or repacked item(s) can not be less than total valuation of raw materials ({1})").format(valuation_at_target, @@ -230,10 +231,10 @@ def validate_valuation_rate(self): def set_total_incoming_outgoing_value(self): self.total_incoming_value = self.total_outgoing_value = 0.0 for d in self.get("items"): - if d.s_warehouse: - self.total_incoming_value += flt(d.amount) if d.t_warehouse: - self.total_outgoing_value += flt(d.amount) + self.total_incoming_value += flt(d.amount) + if d.s_warehouse: + self.total_outgoing_value += flt(d.amount) + flt(d.tax_amount) self.value_difference = self.total_outgoing_value - self.total_incoming_value @@ -316,7 +317,7 @@ def get_operation_cost_per_unit(self, bom_no, qty): bom = frappe.db.get_value("BOM", bom_no, ["operating_cost", "quantity"], as_dict=1) operation_cost_per_unit = flt(bom.operating_cost) / flt(bom.quantity) - return operation_cost_per_unit + (flt(self.additional_operating_cost) / flt(qty)) + return operation_cost_per_unit def validate_purchase_order(self): """Throw exception if more raw material is transferred against Purchase Order than in @@ -402,22 +403,23 @@ def get_gl_entries(self, warehouse_account): for d in self.get("items"): tax_amount = flt(d.tax_amount, d.precision("tax_amount")) - gl_entries.append(self.get_gl_dict({ - "account": d.expense_account, - "against": expenses_included_in_valuation, - "cost_center": d.cost_center, - "remarks": self.get("remarks") or _("Accounting Entry for Stock"), - "debit": tax_amount - })) - - gl_entries.append(self.get_gl_dict({ - "account": expenses_included_in_valuation, - "against": warehouse_account[d.warehouse], - "cost_center": d.cost_center, - "remarks": self.get("remarks") or _("Accounting Entry for Stock"), - "credit": tax_amount - })) + if tax_amount: + gl_entries.append(self.get_gl_dict({ + "account": expenses_included_in_valuation, + "against": d.expense_account, + "cost_center": d.cost_center, + "remarks": self.get("remarks") or _("Accounting Entry for Stock"), + "credit": tax_amount + })) + gl_entries.append(self.get_gl_dict({ + "account": d.expense_account, + "against": expenses_included_in_valuation, + "cost_center": d.cost_center, + "remarks": self.get("remarks") or _("Accounting Entry for Stock"), + "credit": -1 * tax_amount + })) + return gl_entries def update_production_order(self): @@ -693,6 +695,12 @@ def validate_batch(self): if expiry_date: if getdate(self.posting_date) > getdate(expiry_date): frappe.throw(_("Batch {0} of Item {1} has expired.").format(item.batch_no, item.item_code)) + + def distribute_taxes(self): + self.total_taxes_and_charges = sum([flt(t.amount) for t in self.get("taxes")]) + for d in self.get("items"): + if d.t_warehouse and self.total_incoming_value: + d.tax_amount = (flt(d.amount) / flt(self.total_incoming_value)) * self.total_taxes_and_charges @frappe.whitelist() diff --git a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json index a373185c2384..dcd46bd51fe2 100644 --- a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json +++ b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json @@ -160,6 +160,13 @@ "permlevel": 0, "read_only": 1 }, + { + "fieldname": "tax_amount", + "fieldtype": "Currency", + "label": "Tax Amount", + "permlevel": 0, + "precision": "" + }, { "fieldname": "col_break3", "fieldtype": "Column Break", @@ -344,7 +351,7 @@ ], "idx": 1, "istable": 1, - "modified": "2015-07-02 05:32:56.511570", + "modified": "2015-07-24 17:03:44.214018", "modified_by": "Administrator", "module": "Stock", "name": "Stock Entry Detail", From 246e47e76e76b5b68a859c4a3bc7f8a42f8d8fc5 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 7 Aug 2015 17:12:39 +0530 Subject: [PATCH 4/6] [fix] Dashboard in customer / supplier --- erpnext/buying/doctype/supplier/supplier.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/buying/doctype/supplier/supplier.js b/erpnext/buying/doctype/supplier/supplier.js index 19050a419f32..b6b6ce58120c 100644 --- a/erpnext/buying/doctype/supplier/supplier.js +++ b/erpnext/buying/doctype/supplier/supplier.js @@ -46,6 +46,8 @@ cur_frm.cscript.make_dashboard = function(doc) { + ' / ' + __("Total Unpaid") + ": " + format_currency(r.message.total_unpaid, r.message.company_currency[0]) + ''); + } else { + cur_frm.dashboard.set_headline(""); } } cur_frm.dashboard.set_badge_count(r.message); From 3c3a3ecea8eaac1678e6a0becd0d90e0e1f6a41d Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 7 Aug 2015 17:17:03 +0530 Subject: [PATCH 5/6] Additional Costs in Stock Entry --- .../sales_invoice/test_sales_invoice.py | 2 +- .../production_order/production_order.py | 9 +- .../production_order/test_production_order.py | 8 +- erpnext/patches.txt | 1 + .../v5_4/stock_entry_additional_costs.py | 42 ++ .../delivery_note/test_delivery_note.py | 12 +- erpnext/stock/doctype/item/test_item.py | 2 +- .../material_request/material_request.py | 2 +- .../material_request/test_material_request.py | 16 +- .../purchase_receipt/test_purchase_receipt.py | 4 +- .../stock/doctype/stock_entry/stock_entry.js | 62 +- .../doctype/stock_entry/stock_entry.json | 639 ++++++++++++++++-- .../stock/doctype/stock_entry/stock_entry.py | 257 ++++--- .../doctype/stock_entry/test_records.json | 10 +- .../doctype/stock_entry/test_stock_entry.py | 63 +- .../stock_entry_detail.json | 583 ++++++++++++++-- .../test_stock_reconciliation.py | 4 +- .../templates/form_grid/stock_entry_grid.html | 4 +- erpnext/utilities/repost_stock.py | 2 +- 19 files changed, 1398 insertions(+), 324 deletions(-) create mode 100644 erpnext/patches/v5_4/stock_entry_additional_costs.py diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 6c6737913ec5..67f4a8e716be 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -746,7 +746,7 @@ def test_invoice_due_date_against_customers_credit_days(self): def test_return_sales_invoice(self): set_perpetual_inventory() - make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, incoming_rate=100) + make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100) actual_qty_0 = get_qty_after_transaction() diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py index b79f8b624a12..023c43eac495 100644 --- a/erpnext/manufacturing/doctype/production_order/production_order.py +++ b/erpnext/manufacturing/doctype/production_order/production_order.py @@ -10,6 +10,9 @@ from erpnext.manufacturing.doctype.bom.bom import validate_bom_no from dateutil.relativedelta import relativedelta from erpnext.stock.doctype.item.item import validate_end_of_life +from erpnext.manufacturing.doctype.workstation.workstation import WorkstationHolidayError, NotInWorkingHoursError +from erpnext.projects.doctype.time_log.time_log import OverlapError +from erpnext.stock.doctype.stock_entry.stock_entry import get_additional_costs class OverProductionError(frappe.ValidationError): pass class StockOverProductionError(frappe.ValidationError): pass @@ -17,9 +20,6 @@ class OperationTooLongError(frappe.ValidationError): pass class ProductionNotApplicableError(frappe.ValidationError): pass class ItemHasVariantError(frappe.ValidationError): pass -from erpnext.manufacturing.doctype.workstation.workstation import WorkstationHolidayError, NotInWorkingHoursError -from erpnext.projects.doctype.time_log.time_log import OverlapError - form_grid_templates = { "operations": "templates/form_grid/production_order_grid.html" } @@ -356,7 +356,6 @@ def make_stock_entry(production_order_id, purpose, qty=None): stock_entry.company = production_order.company stock_entry.from_bom = 1 stock_entry.bom_no = production_order.bom_no - stock_entry.additional_operating_cost = production_order.additional_operating_cost stock_entry.use_multi_level_bom = production_order.use_multi_level_bom stock_entry.fg_completed_qty = qty or (flt(production_order.qty) - flt(production_order.produced_qty)) @@ -365,6 +364,8 @@ def make_stock_entry(production_order_id, purpose, qty=None): else: stock_entry.from_warehouse = production_order.wip_warehouse stock_entry.to_warehouse = production_order.fg_warehouse + additional_costs = get_additional_costs(production_order, fg_qty=stock_entry.fg_completed_qty) + stock_entry.set("additional_costs", additional_costs) stock_entry.get_items() return stock_entry.as_dict() diff --git a/erpnext/manufacturing/doctype/production_order/test_production_order.py b/erpnext/manufacturing/doctype/production_order/test_production_order.py index 4d653375cbd0..eb26d29896ed 100644 --- a/erpnext/manufacturing/doctype/production_order/test_production_order.py +++ b/erpnext/manufacturing/doctype/production_order/test_production_order.py @@ -28,9 +28,9 @@ def check_planned_qty(self): # add raw materials to stores test_stock_entry.make_stock_entry(item_code="_Test Item", - target="Stores - _TC", qty=100, incoming_rate=100) + target="Stores - _TC", qty=100, basic_rate=100) test_stock_entry.make_stock_entry(item_code="_Test Item Home Desktop 100", - target="Stores - _TC", qty=100, incoming_rate=100) + target="Stores - _TC", qty=100, basic_rate=100) # from stores to wip s = frappe.get_doc(make_stock_entry(pro_order.name, "Material Transfer for Manufacture", 4)) @@ -58,9 +58,9 @@ def test_over_production(self): pro_doc = self.check_planned_qty() test_stock_entry.make_stock_entry(item_code="_Test Item", - target="_Test Warehouse - _TC", qty=100, incoming_rate=100) + target="_Test Warehouse - _TC", qty=100, basic_rate=100) test_stock_entry.make_stock_entry(item_code="_Test Item Home Desktop 100", - target="_Test Warehouse - _TC", qty=100, incoming_rate=100) + target="_Test Warehouse - _TC", qty=100, basic_rate=100) s = frappe.get_doc(make_stock_entry(pro_doc.name, "Manufacture", 7)) s.insert() diff --git a/erpnext/patches.txt b/erpnext/patches.txt index e4eefcec21f4..d12154b32b02 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -189,3 +189,4 @@ erpnext.patches.v5_4.notify_system_managers_regarding_wrong_tax_calculation erpnext.patches.v5_4.fix_invoice_outstanding execute:frappe.db.sql("update `tabStock Ledger Entry` set stock_queue = '[]' where voucher_type = 'Stock Reconciliation' and ifnull(qty_after_transaction, 0) = 0") erpnext.patches.v5_4.fix_missing_item_images +erpnext.patches.v5_4.stock_entry_additional_costs diff --git a/erpnext/patches/v5_4/stock_entry_additional_costs.py b/erpnext/patches/v5_4/stock_entry_additional_costs.py new file mode 100644 index 000000000000..e064690c18b9 --- /dev/null +++ b/erpnext/patches/v5_4/stock_entry_additional_costs.py @@ -0,0 +1,42 @@ +# Copyright (c) 2015, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe.utils import flt + +def execute(): + frappe.reload_doctype("Stock Entry") + frappe.reload_doctype("Stock Entry Detail") + frappe.reload_doctype("Landed Cost Taxes and Charges") + + frappe.db.sql("""update `tabStock Entry Detail` sed, `tabStock Entry` se + set sed.valuation_rate=sed.incoming_rate, sed.basic_rate=sed.incoming_rate, sed.basic_amount=sed.amount + where sed.parent = se.name + and (se.purpose not in ('Manufacture', 'Repack') or ifnull(additional_operating_cost, 0)=0) + """) + + stock_entries = frappe.db.sql_list("""select name from `tabStock Entry` + where purpose in ('Manufacture', 'Repack') and ifnull(additional_operating_cost, 0)!=0""") + + for d in stock_entries: + stock_entry = frappe.get_doc("Stock Entry", d) + stock_entry.append("additional_costs", { + "description": "Additional Operating Cost", + "amount": stock_entry.additional_operating_cost + }) + + number_of_fg_items = len([t.t_warehouse for t in stock_entry.get("items") if t.t_warehouse]) + + for d in stock_entry.get("items"): + d.valuation_rate = d.incoming_rate + + if d.bom_no or (d.t_warehouse and number_of_fg_items == 1): + d.additional_cost = stock_entry.additional_operating_cost + + d.basic_rate = flt(d.valuation_rate) - flt(d.additional_cost) + d.basic_amount = flt(flt(d.basic_rate) *flt(d.transfer_qty), d.precision("basic_amount")) + + stock_entry.flags.ignore_validate = True + stock_entry.flags.ignore_validate_update_after_submit = True + stock_entry.save() \ No newline at end of file diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py index eb80014e5991..e41aab7324ac 100644 --- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py @@ -37,7 +37,7 @@ def test_delivery_note_no_gl_entry(self): set_perpetual_inventory(0) self.assertEqual(cint(frappe.defaults.get_global_default("auto_accounting_for_stock")), 0) - make_stock_entry(target="_Test Warehouse - _TC", qty=5, incoming_rate=100) + make_stock_entry(target="_Test Warehouse - _TC", qty=5, basic_rate=100) stock_queue = json.loads(get_previous_sle({ "item_code": "_Test Item", @@ -59,7 +59,7 @@ def test_delivery_note_gl_entry(self): self.assertEqual(cint(frappe.defaults.get_global_default("auto_accounting_for_stock")), 1) frappe.db.set_value("Item", "_Test Item", "valuation_method", "FIFO") - make_stock_entry(target="_Test Warehouse - _TC", qty=5, incoming_rate=100) + make_stock_entry(target="_Test Warehouse - _TC", qty=5, basic_rate=100) stock_in_hand_account = frappe.db.get_value("Account", {"warehouse": "_Test Warehouse - _TC"}) prev_bal = get_balance_on(stock_in_hand_account) @@ -85,7 +85,7 @@ def test_delivery_note_gl_entry(self): # back dated incoming entry make_stock_entry(posting_date=add_days(nowdate(), -2), target="_Test Warehouse - _TC", - qty=5, incoming_rate=100) + qty=5, basic_rate=100) gl_entries = get_gl_entries("Delivery Note", dn.name) self.assertTrue(gl_entries) @@ -107,9 +107,9 @@ def test_delivery_note_gl_entry(self): def test_delivery_note_gl_entry_packing_item(self): set_perpetual_inventory() - make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=10, incoming_rate=100) + make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=10, basic_rate=100) make_stock_entry(item_code="_Test Item Home Desktop 100", - target="_Test Warehouse - _TC", qty=10, incoming_rate=100) + target="_Test Warehouse - _TC", qty=10, basic_rate=100) stock_in_hand_account = frappe.db.get_value("Account", {"warehouse": "_Test Warehouse - _TC"}) prev_bal = get_balance_on(stock_in_hand_account) @@ -184,7 +184,7 @@ def check_serial_no_values(self, serial_no, field_values): def test_sales_return_for_non_bundled_items(self): set_perpetual_inventory() - make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, incoming_rate=100) + make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100) actual_qty_0 = get_qty_after_transaction() diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index 510c0d1b4831..9235becba1bf 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -47,7 +47,7 @@ def get_item(self, idx): def test_template_cannot_have_stock(self): item = self.get_item(10) - make_stock_entry(item_code=item.name, target="Stores - _TC", qty=1, incoming_rate=1) + make_stock_entry(item_code=item.name, target="Stores - _TC", qty=1, basic_rate=1) item.has_variants = 1 self.assertRaises(ItemTemplateCannotHaveStock, item.save) diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index 04330368c6df..fd6f943a954f 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -305,7 +305,7 @@ def update_item(obj, target, source_parent): def set_missing_values(source, target): target.purpose = source.material_request_type - target.run_method("get_stock_and_rate") + target.run_method("calculate_rate_and_amount") doclist = get_mapped_doc("Material Request", source_name, { "Material Request": { diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py index dcca3ce2901c..99815ddc262c 100644 --- a/erpnext/stock/doctype/material_request/test_material_request.py +++ b/erpnext/stock/doctype/material_request/test_material_request.py @@ -72,7 +72,7 @@ def _insert_stock_entry(self, qty1, qty2, warehouse = None ): "doctype": "Stock Entry Detail", "item_code": "_Test Item Home Desktop 100", "parentfield": "items", - "incoming_rate": 100, + "basic_rate": 100, "qty": qty1, "stock_uom": "_Test UOM 1", "transfer_qty": qty1, @@ -84,7 +84,7 @@ def _insert_stock_entry(self, qty1, qty2, warehouse = None ): "doctype": "Stock Entry Detail", "item_code": "_Test Item Home Desktop 200", "parentfield": "items", - "incoming_rate": 100, + "basic_rate": 100, "qty": qty2, "stock_uom": "_Test UOM 1", "transfer_qty": qty2, @@ -196,13 +196,13 @@ def test_completed_qty_for_transfer(self): "qty": 27.0, "transfer_qty": 27.0, "s_warehouse": "_Test Warehouse 1 - _TC", - "incoming_rate": 1.0 + "basic_rate": 1.0 }) se_doc.get("items")[1].update({ "qty": 1.5, "transfer_qty": 1.5, "s_warehouse": "_Test Warehouse 1 - _TC", - "incoming_rate": 1.0 + "basic_rate": 1.0 }) # make available the qty in _Test Warehouse 1 before transfer @@ -279,13 +279,13 @@ def test_completed_qty_for_over_transfer(self): "qty": 60.0, "transfer_qty": 60.0, "s_warehouse": "_Test Warehouse 1 - _TC", - "incoming_rate": 1.0 + "basic_rate": 1.0 }) se_doc.get("items")[1].update({ "qty": 3.0, "transfer_qty": 3.0, "s_warehouse": "_Test Warehouse 1 - _TC", - "incoming_rate": 1.0 + "basic_rate": 1.0 }) # make available the qty in _Test Warehouse 1 before transfer @@ -350,13 +350,13 @@ def test_incorrect_mapping_of_stock_entry(self): "transfer_qty": 60.0, "s_warehouse": "_Test Warehouse - _TC", "t_warehouse": "_Test Warehouse 1 - _TC", - "incoming_rate": 1.0 + "basic_rate": 1.0 }) se_doc.get("items")[1].update({ "qty": 3.0, "transfer_qty": 3.0, "s_warehouse": "_Test Warehouse 1 - _TC", - "incoming_rate": 1.0 + "basic_rate": 1.0 }) # check for stopped status of Material Request diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 343d51acc756..50179646cbdd 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -80,9 +80,9 @@ def test_purchase_receipt_gl_entry(self): def test_subcontracting(self): from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry - make_stock_entry(item_code="_Test Item", target="_Test Warehouse 1 - _TC", qty=100, incoming_rate=100) + make_stock_entry(item_code="_Test Item", target="_Test Warehouse 1 - _TC", qty=100, basic_rate=100) make_stock_entry(item_code="_Test Item Home Desktop 100", target="_Test Warehouse 1 - _TC", - qty=100, incoming_rate=100) + qty=100, basic_rate=100) pr = make_purchase_receipt(item_code="_Test FG Item", qty=10, rate=500, is_subcontracted="Yes") self.assertEquals(len(pr.get("supplied_items")), 2) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index 22652e6820a3..e9fc134152a9 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -25,7 +25,8 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ return { "filters": { "docstatus": 1, - "is_subcontracted": "Yes" + "is_subcontracted": "Yes", + "company": me.frm.doc.company } }; }); @@ -41,6 +42,14 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ } } } + this.frm.set_query("difference_account", function() { + return { + "filters": { + "company": me.frm.doc.company, + "is_group": 0 + } + }; + }); } }, @@ -125,11 +134,6 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ var d = locals[cdt][cdn]; d.transfer_qty = flt(d.qty) * flt(d.conversion_factor); refresh_field('items'); - calculate_total(doc, cdt, cdn); - }, - - incoming_rate: function(doc, cdt, cdn) { - calculate_total(doc, cdt, cdn); }, production_order: function() { @@ -138,13 +142,29 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ return frappe.call({ method: "erpnext.stock.doctype.stock_entry.stock_entry.get_production_order_details", - args: {production_order: this.frm.doc.production_order}, + args: {production_order: me.frm.doc.production_order}, callback: function(r) { if (!r.exc) { - me.frm.set_value(r.message); + $.each(["from_bom", "bom_no", "fg_completed_qty", "use_multi_level_bom"], function(i, field) { + me.frm.set_value(field, r.message[field]); + }) + if (me.frm.doc.purpose == "Material Transfer for Manufacture" && !me.frm.doc.to_warehouse) me.frm.set_value("to_warehouse", r.message["wip_warehouse"]); - me.frm.set_value("from_bom", 1); + + + if (me.frm.doc.purpose == "Manufacture") { + if(r.message["additional_costs"].length) { + $.each(r.message["additional_costs"], function(i, row) { + me.frm.add_child("additional_costs", row); + }) + refresh_field("additional_costs"); + } + + if (!me.frm.doc.from_warehouse) me.frm.set_value("from_warehouse", r.message["wip_warehouse"]); + if (!me.frm.doc.to_warehouse) me.frm.set_value("to_warehouse", r.message["fg_warehouse"]); + } + me.get_items() } } }); @@ -232,13 +252,20 @@ cur_frm.cscript.toggle_related_fields = function(doc) { if(doc.purpose == "Material Receipt") { cur_frm.set_value("from_bom", 0); } + + // Addition costs based on purpose + cur_frm.toggle_display(["additional_costs", "total_additional_costs", "additional_costs_section"], + doc.purpose!='Material Issue'); + + cur_frm.fields_dict["items"].grid.set_column_disp("additional_cost", doc.purpose!='Material Issue'); } cur_frm.fields_dict['production_order'].get_query = function(doc) { return { filters: [ ['Production Order', 'docstatus', '=', 1], - ['Production Order', 'qty', '>','`tabProduction Order`.produced_qty'] + ['Production Order', 'qty', '>','`tabProduction Order`.produced_qty'], + ['Production Order', 'company', '=', cur_frm.doc.company] ] } } @@ -378,17 +405,4 @@ cur_frm.cscript.company = function(doc, cdt, cdn) { cur_frm.cscript.posting_date = function(doc, cdt, cdn){ erpnext.get_fiscal_year(doc.company, doc.posting_date); -} - -var calculate_total = function(doc, cdt, cdn){ - var d = locals[cdt][cdn]; - amount = flt(d.incoming_rate) * flt(d.transfer_qty) - frappe.model.set_value(cdt, cdn, 'amount', amount); - var total_amount = 0.0; - var items = doc.items || []; - for(var i=0;i= qty: frappe.throw(_("Stock Entries already created for Production Order ") + self.production_order + ":" + ", ".join(other_ste), DuplicateEntryForProductionOrderError) - - def validate_valuation_rate(self): - if self.purpose in ["Manufacture", "Repack"]: - valuation_at_source, valuation_at_target = 0, 0 - for d in self.get("items"): - if d.s_warehouse and not d.t_warehouse: - valuation_at_source += flt(d.amount) - if d.t_warehouse and not d.s_warehouse: - valuation_at_target += flt(d.amount) + flt(d.tax_amount) - - if valuation_at_target + 0.001 < valuation_at_source: - frappe.throw(_("Total valuation ({0}) for manufactured or repacked item(s) can not be less than total valuation of raw materials ({1})").format(valuation_at_target, - valuation_at_source)) - - def set_total_incoming_outgoing_value(self): - self.total_incoming_value = self.total_outgoing_value = 0.0 - for d in self.get("items"): - if d.t_warehouse: - self.total_incoming_value += flt(d.amount) - if d.s_warehouse: - self.total_outgoing_value += flt(d.amount) + flt(d.tax_amount) - - self.value_difference = self.total_outgoing_value - self.total_incoming_value - - def set_total_amount(self): - self.total_amount = sum([flt(item.amount) for item in self.get("items")]) - - def get_stock_and_rate(self, force=False): - """get stock and incoming rate on posting date""" - - raw_material_cost = 0.0 - - if not self.posting_date or not self.posting_time: - frappe.throw(_("Posting date and posting time is mandatory")) - + + def set_actual_qty(self): allow_negative_stock = cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock")) - + for d in self.get('items'): - d.transfer_qty = flt(d.transfer_qty) - - args = frappe._dict({ + previous_sle = get_previous_sle({ "item_code": d.item_code, "warehouse": d.s_warehouse or d.t_warehouse, "posting_date": self.posting_date, - "posting_time": self.posting_time, - "qty": d.s_warehouse and -1*d.transfer_qty or d.transfer_qty, - "serial_no": d.serial_no, + "posting_time": self.posting_time }) # get actual stock at source warehouse - d.actual_qty = get_previous_sle(args).get("qty_after_transaction") or 0 + d.actual_qty = previous_sle.get("qty_after_transaction") or 0 # validate qty during submit if d.docstatus==1 and d.s_warehouse and not allow_negative_stock and d.actual_qty < d.transfer_qty: @@ -272,52 +232,93 @@ def get_stock_and_rate(self, force=False): Available Qty: {4}, Transfer Qty: {5}""").format(d.idx, d.s_warehouse, self.posting_date, self.posting_time, d.actual_qty, d.transfer_qty), NegativeStockError) - # get incoming rate - if not d.bom_no: - if not flt(d.incoming_rate) or d.s_warehouse or force: - incoming_rate = flt(get_incoming_rate(args), self.precision("incoming_rate", d)) - if incoming_rate > 0: - d.incoming_rate = incoming_rate - - d.amount = flt(flt(d.transfer_qty) * flt(d.incoming_rate), d.precision("amount")) - if not d.t_warehouse: - raw_material_cost += flt(d.amount) + def calculate_rate_and_amount(self, force=False): + self.set_basic_rate(force) + self.distribute_additional_costs() + self.update_valuation_rate() + self.validate_valuation_rate() + self.set_total_incoming_outgoing_value() + self.set_total_amount() + + def set_basic_rate(self, force=False): + """get stock and incoming rate on posting date""" + raw_material_cost = 0.0 + for d in self.get('items'): + args = frappe._dict({ + "item_code": d.item_code, + "warehouse": d.s_warehouse or d.t_warehouse, + "posting_date": self.posting_date, + "posting_time": self.posting_time, + "qty": d.s_warehouse and -1*flt(d.transfer_qty) or flt(d.transfer_qty), + "serial_no": d.serial_no, + }) - self.add_operation_cost(raw_material_cost, force) + # get basic rate + if not d.bom_no: + if not flt(d.basic_rate) or d.s_warehouse or force: + basic_rate = flt(get_incoming_rate(args), self.precision("basic_rate", d)) + if basic_rate > 0: + d.basic_rate = basic_rate - def add_operation_cost(self, raw_material_cost, force): - """Adds operating cost if Production Order is set""" - # set incoming rate for fg item + d.basic_amount = flt(flt(d.transfer_qty) * flt(d.basic_rate), d.precision("basic_amount")) + if not d.t_warehouse: + raw_material_cost += flt(d.basic_amount) + + self.set_basic_rate_for_finished_goods(raw_material_cost) + + def set_basic_rate_for_finished_goods(self, raw_material_cost): if self.purpose in ["Manufacture", "Repack"]: number_of_fg_items = len([t.t_warehouse for t in self.get("items") if t.t_warehouse]) for d in self.get("items"): if d.bom_no or (d.t_warehouse and number_of_fg_items == 1): - operation_cost_per_unit = self.get_operation_cost_per_unit(d.bom_no, d.qty) + d.basic_rate = flt(raw_material_cost / flt(d.transfer_qty), d.precision("basic_rate")) + d.basic_amount = flt(flt(d.basic_rate) * flt(d.transfer_qty), d.precision("basic_amount")) + + def distribute_additional_costs(self): + if self.purpose == "Material Issue": + self.additional_costs = [] + + self.total_additional_costs = sum([flt(t.amount) for t in self.get("additional_costs")]) + total_basic_amount = sum([flt(t.basic_amount) for t in self.get("items") if t.t_warehouse]) - d.incoming_rate = operation_cost_per_unit + (raw_material_cost / flt(d.transfer_qty)) - d.amount = flt(flt(d.transfer_qty) * flt(d.incoming_rate), self.precision("transfer_qty", d)) - break + for d in self.get("items"): + if d.t_warehouse and total_basic_amount: + d.additional_cost = (flt(d.basic_amount) / total_basic_amount) * self.total_additional_costs + else: + d.additional_cost = 0 + + def update_valuation_rate(self): + for d in self.get("items"): + d.amount = flt(d.basic_amount + flt(d.additional_cost), d.precision("amount")) + d.valuation_rate = flt(flt(d.basic_rate) + flt(d.additional_cost) / flt(d.transfer_qty), + d.precision("valuation_rate")) - def get_operation_cost_per_unit(self, bom_no, qty): - """Returns operating cost from Production Order for given `bom_no`""" - operation_cost_per_unit = 0 + def validate_valuation_rate(self): + if self.purpose in ["Manufacture", "Repack"]: + valuation_at_source, valuation_at_target = 0, 0 + for d in self.get("items"): + if d.s_warehouse and not d.t_warehouse: + valuation_at_source += flt(d.amount) + if d.t_warehouse and not d.s_warehouse: + valuation_at_target += flt(d.amount) - if self.production_order: - if not getattr(self, "pro_doc", None): - self.pro_doc = frappe.get_doc("Production Order", self.production_order) - for d in self.pro_doc.get("operations"): - if flt(d.completed_qty): - operation_cost_per_unit += flt(d.actual_operating_cost) / flt(d.completed_qty) - else: - operation_cost_per_unit += flt(d.planned_operating_cost) / flt(self.pro_doc.qty) + if valuation_at_target + 0.001 < valuation_at_source: + frappe.throw(_("Total valuation ({0}) for manufactured or repacked item(s) can not be less than total valuation of raw materials ({1})") + .format(valuation_at_target, valuation_at_source)) - # set operating cost from BOM if specified. - if not operation_cost_per_unit and bom_no: - bom = frappe.db.get_value("BOM", bom_no, ["operating_cost", "quantity"], as_dict=1) - operation_cost_per_unit = flt(bom.operating_cost) / flt(bom.quantity) + def set_total_incoming_outgoing_value(self): + self.total_incoming_value = self.total_outgoing_value = 0.0 + for d in self.get("items"): + if d.t_warehouse: + self.total_incoming_value += flt(d.amount) + if d.s_warehouse: + self.total_outgoing_value += flt(d.amount) - return operation_cost_per_unit + self.value_difference = self.total_incoming_value - self.total_outgoing_value + + def set_total_amount(self): + self.total_amount = sum([flt(item.amount) for item in self.get("items")]) def validate_purchase_order(self): """Throw exception if more raw material is transferred against Purchase Order than in @@ -367,9 +368,7 @@ def validate_finished_goods(self): def update_stock_ledger(self): sl_entries = [] - for d in self.get('items'): - tax_amount_per_qty = flt(flt(d.tax_amount) / flt(d.qty), d.precision("tax_amount")) - + for d in self.get('items'): if cstr(d.s_warehouse) and self.docstatus == 1: sl_entries.append(self.get_sl_entries(d, { "warehouse": cstr(d.s_warehouse), @@ -381,7 +380,7 @@ def update_stock_ledger(self): sl_entries.append(self.get_sl_entries(d, { "warehouse": cstr(d.t_warehouse), "actual_qty": flt(d.transfer_qty), - "incoming_rate": flt(d.incoming_rate) + tax_amount_per_qty + "incoming_rate": flt(d.valuation_rate) })) # On cancellation, make stock ledger entry for @@ -402,14 +401,14 @@ def get_gl_entries(self, warehouse_account): gl_entries = super(StockEntry, self).get_gl_entries(warehouse_account) for d in self.get("items"): - tax_amount = flt(d.tax_amount, d.precision("tax_amount")) - if tax_amount: + additional_cost = flt(d.additional_cost, d.precision("additional_cost")) + if additional_cost: gl_entries.append(self.get_gl_dict({ "account": expenses_included_in_valuation, "against": d.expense_account, "cost_center": d.cost_center, "remarks": self.get("remarks") or _("Accounting Entry for Stock"), - "credit": tax_amount + "credit": additional_cost })) gl_entries.append(self.get_gl_dict({ @@ -417,7 +416,7 @@ def get_gl_entries(self, warehouse_account): "against": expenses_included_in_valuation, "cost_center": d.cost_center, "remarks": self.get("remarks") or _("Accounting Entry for Stock"), - "credit": -1 * tax_amount + "credit": -1 * additional_cost # put it as negative credit instead of debit purposefully })) return gl_entries @@ -471,7 +470,7 @@ def get_item_details(self, args=None, for_update=False): 'conversion_factor' : 1, 'batch_no' : '', 'actual_qty' : 0, - 'incoming_rate' : 0 + 'basic_rate' : 0 } for d in [["Account", "expense_account", "default_expense_account"], ["Cost Center", "cost_center", "cost_center"]]: @@ -519,13 +518,16 @@ def get_warehouse_details(self, args): ret = { "actual_qty" : get_previous_sle(args).get("qty_after_transaction") or 0, - "incoming_rate" : get_incoming_rate(args) + "basic_rate" : get_incoming_rate(args) } return ret def get_items(self): self.set('items', []) self.validate_production_order() + + if not self.posting_date or not self.posting_time: + frappe.throw(_("Posting date and posting time is mandatory")) if not getattr(self, "pro_doc", None): self.pro_doc = None @@ -567,7 +569,8 @@ def get_items(self): if self.purpose in ("Manufacture", "Repack"): self.load_items_from_bom() - self.get_stock_and_rate() + self.set_actual_qty() + self.calculate_rate_and_amount() def load_items_from_bom(self): if self.production_order: @@ -695,19 +698,57 @@ def validate_batch(self): if expiry_date: if getdate(self.posting_date) > getdate(expiry_date): frappe.throw(_("Batch {0} of Item {1} has expired.").format(item.batch_no, item.item_code)) - - def distribute_taxes(self): - self.total_taxes_and_charges = sum([flt(t.amount) for t in self.get("taxes")]) - for d in self.get("items"): - if d.t_warehouse and self.total_incoming_value: - d.tax_amount = (flt(d.amount) / flt(self.total_incoming_value)) * self.total_taxes_and_charges - @frappe.whitelist() def get_production_order_details(production_order): - res = frappe.db.sql("""select bom_no, use_multi_level_bom, wip_warehouse, - ifnull(qty, 0) - ifnull(produced_qty, 0) as fg_completed_qty, - (ifnull(additional_operating_cost, 0) / qty)*(ifnull(qty, 0) - ifnull(produced_qty, 0)) as additional_operating_cost - from `tabProduction Order` where name = %s""", production_order, as_dict=1) - - return res and res[0] or {} + production_order = frappe.get_doc("Production Order", production_order) + pending_qty_to_produce = flt(production_order.qty) - flt(production_order.produced_qty) + + return { + "from_bom": 1, + "bom_no": production_order.bom_no, + "use_multi_level_bom": production_order.use_multi_level_bom, + "wip_warehouse": production_order.wip_warehouse, + "fg_warehouse": production_order.fg_warehouse, + "fg_completed_qty": pending_qty_to_produce, + "additional_costs": get_additional_costs(production_order, fg_qty=pending_qty_to_produce) + } + +def get_additional_costs(production_order=None, bom_no=None, fg_qty=None): + additional_costs = [] + operating_cost_per_unit = get_operating_cost_per_unit(production_order, bom_no) + if operating_cost_per_unit: + additional_costs.append({ + "description": "Operating Cost as per Production Order / BOM", + "amount": operating_cost_per_unit * flt(fg_qty) + }) + + if production_order and production_order.additional_operating_cost: + additional_operating_cost_per_unit = \ + flt(production_order.additional_operating_cost) / flt(production_order.qty) + + additional_costs.append({ + "description": "Additional Operating Cost", + "amount": additional_operating_cost_per_unit * flt(fg_qty) + }) + + return additional_costs + +def get_operating_cost_per_unit(production_order=None, bom_no=None): + operating_cost_per_unit = 0 + if production_order: + if not bom_no: + bom_no = production_order.bom_no + + for d in production_order.get("operations"): + if flt(d.completed_qty): + operating_cost_per_unit += flt(d.actual_operating_cost) / flt(d.completed_qty) + else: + operating_cost_per_unit += flt(d.planned_operating_cost) / flt(production_order.qty) + + # Get operating cost from BOM if not found in production_order. + if not operating_cost_per_unit and bom_no: + bom = frappe.db.get_value("BOM", bom_no, ["operating_cost", "quantity"], as_dict=1) + operating_cost_per_unit = flt(bom.operating_cost) / flt(bom.quantity) + + return operating_cost_per_unit \ No newline at end of file diff --git a/erpnext/stock/doctype/stock_entry/test_records.json b/erpnext/stock/doctype/stock_entry/test_records.json index f4d20449e59d..f648b9e6fd61 100644 --- a/erpnext/stock/doctype/stock_entry/test_records.json +++ b/erpnext/stock/doctype/stock_entry/test_records.json @@ -8,7 +8,7 @@ "cost_center": "_Test Cost Center - _TC", "doctype": "Stock Entry Detail", "expense_account": "Stock Adjustment - _TC", - "incoming_rate": 100, + "basic_rate": 100, "item_code": "_Test Item", "parentfield": "items", "qty": 50.0, @@ -32,7 +32,7 @@ "cost_center": "_Test Cost Center - _TC", "doctype": "Stock Entry Detail", "expense_account": "Stock Adjustment - _TC", - "incoming_rate": 100, + "basic_rate": 100, "item_code": "_Test Item", "parentfield": "items", "qty": 40.0, @@ -57,7 +57,7 @@ "cost_center": "_Test Cost Center - _TC", "doctype": "Stock Entry Detail", "expense_account": "Stock Adjustment - _TC", - "incoming_rate": 100, + "basic_rate": 100, "item_code": "_Test Item", "parentfield": "items", "qty": 45.0, @@ -83,7 +83,7 @@ "cost_center": "_Test Cost Center - _TC", "doctype": "Stock Entry Detail", "expense_account": "Stock Adjustment - _TC", - "incoming_rate": 100, + "basic_rate": 100, "item_code": "_Test Item", "parentfield": "items", "qty": 50.0, @@ -97,7 +97,7 @@ "cost_center": "_Test Cost Center - _TC", "doctype": "Stock Entry Detail", "expense_account": "Stock Adjustment - _TC", - "incoming_rate": 5000, + "basic_rate": 5000, "item_code": "_Test Item Home Desktop 100", "parentfield": "items", "qty": 1, diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py index d283c3dd14b2..f00a235fa76c 100644 --- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py @@ -36,12 +36,12 @@ def test_fifo(self): create_stock_reconciliation(item_code="_Test Item 2", warehouse="_Test Warehouse - _TC", qty=0, rate=100) - make_stock_entry(item_code=item_code, target=warehouse, qty=1, incoming_rate=10) + make_stock_entry(item_code=item_code, target=warehouse, qty=1, basic_rate=10) sle = get_sle(item_code = item_code, warehouse = warehouse)[0] self.assertEqual([[1, 10]], eval(sle.stock_queue)) # negative qty - make_stock_entry(item_code=item_code, source=warehouse, qty=2, incoming_rate=10) + make_stock_entry(item_code=item_code, source=warehouse, qty=2, basic_rate=10) sle = get_sle(item_code = item_code, warehouse = warehouse)[0] self.assertEqual([[-1, 10]], eval(sle.stock_queue)) @@ -53,12 +53,12 @@ def test_fifo(self): self.assertEqual([[-2, 10]], eval(sle.stock_queue)) # move stock to positive - make_stock_entry(item_code=item_code, target=warehouse, qty=3, incoming_rate=20) + make_stock_entry(item_code=item_code, target=warehouse, qty=3, basic_rate=20) sle = get_sle(item_code = item_code, warehouse = warehouse)[0] self.assertEqual([[1, 20]], eval(sle.stock_queue)) # incoming entry with diff rate - make_stock_entry(item_code=item_code, target=warehouse, qty=1, incoming_rate=30) + make_stock_entry(item_code=item_code, target=warehouse, qty=1, basic_rate=30) sle = get_sle(item_code = item_code, warehouse = warehouse)[0] self.assertEqual([[1, 20],[1, 30]], eval(sle.stock_queue)) @@ -125,7 +125,7 @@ def test_material_receipt_gl_entry(self): set_perpetual_inventory() mr = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", - qty=50, incoming_rate=100) + qty=50, basic_rate=100) stock_in_hand_account = frappe.db.get_value("Account", {"account_type": "Warehouse", "warehouse": mr.get("items")[0].t_warehouse}) @@ -152,7 +152,7 @@ def test_material_issue_gl_entry(self): set_perpetual_inventory() make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", - qty=50, incoming_rate=100) + qty=50, basic_rate=100) mi = make_stock_entry(item_code="_Test Item", source="_Test Warehouse - _TC", qty=40) @@ -217,9 +217,9 @@ def test_material_transfer_gl_entry(self): def test_repack_no_change_in_valuation(self): set_perpetual_inventory(0) - make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, incoming_rate=100) + make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100) make_stock_entry(item_code="_Test Item Home Desktop 100", target="_Test Warehouse - _TC", - qty=50, incoming_rate=100) + qty=50, basic_rate=100) repack = frappe.copy_doc(test_records[3]) repack.posting_date = nowdate() @@ -238,15 +238,24 @@ def test_repack_no_change_in_valuation(self): set_perpetual_inventory(0) - def test_repack_with_change_in_valuation(self): + def test_repack_with_additional_costs(self): set_perpetual_inventory() - make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, incoming_rate=100) - + make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100) repack = frappe.copy_doc(test_records[3]) repack.posting_date = nowdate() repack.posting_time = nowtime() - repack.additional_operating_cost = 1000.0 + + repack.set("additional_costs", [ + { + "description": "Actual Oerating Cost", + "amount": 1000 + }, + { + "description": "additional operating costs", + "amount": 200 + }, + ]) repack.insert() repack.submit() @@ -260,11 +269,13 @@ def test_repack_with_change_in_valuation(self): "voucher_no": repack.name, "item_code": "_Test Item Home Desktop 100"}, "stock_value_difference")) stock_value_diff = flt(fg_stock_value_diff - rm_stock_value_diff, 2) + + self.assertEqual(stock_value_diff, 1200) self.check_gl_entries("Stock Entry", repack.name, sorted([ - [stock_in_hand_account, stock_value_diff, 0.0], - ["Stock Adjustment - _TC", 0.0, stock_value_diff], + [stock_in_hand_account, 1200, 0.0], + ["Expenses Included In Valuation - _TC", 0.0, 1200.0] ]) ) set_perpetual_inventory(0) @@ -291,10 +302,9 @@ def check_gl_entries(self, voucher_type, voucher_no, expected_gl_entries): gl_entries = frappe.db.sql("""select account, debit, credit from `tabGL Entry` where voucher_type=%s and voucher_no=%s order by account asc, debit asc""", (voucher_type, voucher_no), as_list=1) - + self.assertTrue(gl_entries) gl_entries.sort(key=lambda x: x[0]) - for i, gle in enumerate(gl_entries): self.assertEquals(expected_gl_entries[i][0], gle[0]) self.assertEquals(expected_gl_entries[i][1], gle[1]) @@ -503,6 +513,8 @@ def test_freeze_stocks(self): frappe.db.set_value("Stock Settings", None, "stock_frozen_upto_days", 0) def test_production_order(self): + from erpnext.manufacturing.doctype.production_order.production_order \ + import make_stock_entry as _make_stock_entry bom_no, bom_operation_cost = frappe.db.get_value("BOM", {"item": "_Test FG Item 2", "is_default": 1, "docstatus": 1}, ["name", "operating_cost"]) @@ -514,22 +526,15 @@ def test_production_order(self): "bom_no": bom_no, "qty": 1.0, "stock_uom": "_Test UOM", - "wip_warehouse": "_Test Warehouse - _TC" + "wip_warehouse": "_Test Warehouse - _TC", + "additional_operating_cost": 1000 }) production_order.insert() production_order.submit() - make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, incoming_rate=100) + make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100) - stock_entry = frappe.new_doc("Stock Entry") - stock_entry.update({ - "purpose": "Manufacture", - "production_order": production_order.name, - "bom_no": bom_no, - "fg_completed_qty": "1", - "additional_operating_cost": 1000 - }) - stock_entry.get_items() + stock_entry = _make_stock_entry(production_order.name, "Manufacture", 1) rm_cost = 0 for d in stock_entry.get("items"): @@ -538,7 +543,7 @@ def test_production_order(self): fg_cost = filter(lambda x: x.item_code=="_Test FG Item 2", stock_entry.get("items"))[0].amount self.assertEqual(fg_cost, - flt(rm_cost + bom_operation_cost + stock_entry.additional_operating_cost, 2)) + flt(rm_cost + bom_operation_cost + production_order.additional_operating_cost, 2)) def test_variant_production_order(self): @@ -610,7 +615,7 @@ def make_stock_entry(**args): "s_warehouse": args.from_warehouse or args.source, "t_warehouse": args.to_warehouse or args.target, "qty": args.qty, - "incoming_rate": args.incoming_rate, + "basic_rate": args.basic_rate, "expense_account": args.expense_account or "Stock Adjustment - _TC", "conversion_factor": 1.0, "cost_center": "_Test Cost Center - _TC" diff --git a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json index dcd46bd51fe2..fe8a1b15bea1 100644 --- a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json +++ b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json @@ -1,25 +1,58 @@ { + "allow_copy": 0, + "allow_import": 0, + "allow_rename": 0, "autoname": "hash", "creation": "2013-03-29 18:22:12", + "custom": 0, "docstatus": 0, "doctype": "DocType", "fields": [ { + "allow_on_submit": 0, "fieldname": "barcode", "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Barcode", + "no_copy": 0, "permlevel": 0, - "precision": "" + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "section_break_2", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "permlevel": 0, - "precision": "" + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "s_warehouse", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, "in_filter": 1, "in_list_view": 1, "label": "Source Warehouse", @@ -28,16 +61,38 @@ "oldfieldtype": "Link", "options": "Warehouse", "permlevel": 0, - "read_only": 0 + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "col_break1", "fieldtype": "Column Break", - "permlevel": 0 + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "t_warehouse", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, "in_filter": 1, "in_list_view": 1, "label": "Target Warehouse", @@ -46,247 +101,631 @@ "oldfieldtype": "Link", "options": "Warehouse", "permlevel": 0, - "read_only": 0 + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "sec_break1", "fieldtype": "Section Break", - "permlevel": 0 + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "item_code", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, "in_filter": 1, "in_list_view": 1, "label": "Item Code", + "no_copy": 0, "oldfieldname": "item_code", "oldfieldtype": "Link", "options": "Item", "permlevel": 0, + "print_hide": 0, "read_only": 0, + "report_hide": 0, "reqd": 1, - "search_index": 1 + "search_index": 1, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "col_break2", "fieldtype": "Column Break", - "permlevel": 0 + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "qty", "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, "in_list_view": 1, "label": "Qty", + "no_copy": 0, "oldfieldname": "qty", "oldfieldtype": "Currency", "permlevel": 0, + "print_hide": 0, "read_only": 0, - "reqd": 1 + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "section_break_8", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "permlevel": 0, - "precision": "" + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "item_name", "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Item Name", + "no_copy": 0, "permlevel": 0, "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "description", "fieldtype": "Text", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, "in_list_view": 0, "label": "Description", + "no_copy": 0, "oldfieldname": "description", "oldfieldtype": "Text", "permlevel": 0, + "print_hide": 0, "print_width": "300px", "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, "width": "300px" }, { + "allow_on_submit": 0, "fieldname": "column_break_10", "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "permlevel": 0, - "precision": "" + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "image", "fieldtype": "Attach", "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Image", + "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 1 + "print_hide": 1, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "image_view", "fieldtype": "Image", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Image View", + "no_copy": 0, "options": "image", "permlevel": 0, - "precision": "" + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "quantity_and_rate", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Quantity and Rate", - "permlevel": 0 + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { - "fieldname": "incoming_rate", + "allow_on_submit": 0, + "fieldname": "basic_rate", "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, "in_list_view": 1, - "label": "Valuation Rate", + "label": "Basic Rate (as per Stock UOM)", + "no_copy": 0, "oldfieldname": "incoming_rate", "oldfieldtype": "Currency", "options": "Company:company:default_currency", "permlevel": 0, + "print_hide": 1, "read_only": 0, - "reqd": 0 + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "fieldname": "basic_amount", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Basic Amount", + "no_copy": 0, + "options": "Company:company:default_currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "fieldname": "additional_cost", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Additional Cost", + "no_copy": 0, + "options": "Company:company:default_currency", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "amount", "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Amount", + "no_copy": 0, "oldfieldname": "amount", "oldfieldtype": "Currency", "options": "Company:company:default_currency", "permlevel": 0, - "read_only": 1 + "print_hide": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { - "fieldname": "tax_amount", + "allow_on_submit": 0, + "fieldname": "valuation_rate", "fieldtype": "Currency", - "label": "Tax Amount", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Valuation Rate", + "no_copy": 0, + "options": "Company:company:default_currency", "permlevel": 0, - "precision": "" + "precision": "", + "print_hide": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "col_break3", "fieldtype": "Column Break", - "permlevel": 0 + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "uom", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, "in_list_view": 0, "label": "UOM", + "no_copy": 0, "oldfieldname": "uom", "oldfieldtype": "Link", "options": "UOM", "permlevel": 0, + "print_hide": 0, "read_only": 0, - "reqd": 1 + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "conversion_factor", "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Conversion Factor", + "no_copy": 0, "oldfieldname": "conversion_factor", "oldfieldtype": "Currency", "permlevel": 0, "print_hide": 1, "read_only": 1, - "reqd": 1 + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "stock_uom", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, "in_filter": 0, + "in_list_view": 0, "label": "Stock UOM", + "no_copy": 0, "oldfieldname": "stock_uom", "oldfieldtype": "Link", "options": "UOM", "permlevel": 0, "print_hide": 1, "read_only": 1, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "fieldname": "transfer_qty", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Qty as per Stock UOM", + "no_copy": 0, + "oldfieldname": "transfer_qty", + "oldfieldtype": "Currency", + "permlevel": 0, + "print_hide": 1, + "read_only": 1, + "report_hide": 0, "reqd": 1, - "search_index": 0 + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "serial_no_batch", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Serial No / Batch", - "permlevel": 0 + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "serial_no", "fieldtype": "Text", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Serial No", "no_copy": 1, "oldfieldname": "serial_no", "oldfieldtype": "Text", "permlevel": 0, + "print_hide": 0, "read_only": 0, - "reqd": 0 + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "col_break4", "fieldtype": "Column Break", - "permlevel": 0 + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "batch_no", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Batch No", + "no_copy": 0, "oldfieldname": "batch_no", "oldfieldtype": "Link", "options": "Batch", "permlevel": 0, "print_hide": 0, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "accounting", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Accounting", - "permlevel": 0 + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)", "fieldname": "expense_account", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Difference Account", + "no_copy": 0, "options": "Account", "permlevel": 0, - "print_hide": 1 + "print_hide": 1, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "col_break5", "fieldtype": "Column Break", - "permlevel": 0 + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "default": ":Company", "depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)", "fieldname": "cost_center", "fieldtype": "Link", "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Cost Center", + "no_copy": 0, "options": "Cost Center", "permlevel": 0, "print_hide": 1, "read_only": 0, - "reqd": 0 + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "more_info", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "More Info", - "permlevel": 0 + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { "allow_on_submit": 1, "fieldname": "actual_qty", "fieldtype": "Float", + "hidden": 0, "ignore_user_permissions": 0, "in_filter": 1, + "in_list_view": 0, "label": "Actual Qty (at source/target)", "no_copy": 1, "oldfieldname": "actual_qty", @@ -294,67 +733,107 @@ "permlevel": 0, "print_hide": 1, "read_only": 1, + "report_hide": 0, "reqd": 0, - "search_index": 1 + "search_index": 1, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "description": "BOM No. for a Finished Good Item", "fieldname": "bom_no", "fieldtype": "Link", "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "BOM No", "no_copy": 0, "options": "BOM", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "col_break6", "fieldtype": "Column Break", - "permlevel": 0 - }, - { - "fieldname": "transfer_qty", - "fieldtype": "Float", - "label": "Qty as per Stock UOM", - "oldfieldname": "transfer_qty", - "oldfieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "permlevel": 0, - "print_hide": 1, - "read_only": 1, - "reqd": 1 + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "description": "Material Request used to make this Stock Entry", "fieldname": "material_request", "fieldtype": "Link", "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Material Request", "no_copy": 1, "options": "Material Request", "permlevel": 0, "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "material_request_item", "fieldtype": "Link", "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Material Request Item", "no_copy": 1, "options": "Material Request Item", "permlevel": 0, "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 } ], + "hide_heading": 0, + "hide_toolbar": 0, "idx": 1, + "in_create": 0, + "in_dialog": 0, + "is_submittable": 0, + "issingle": 0, "istable": 1, - "modified": "2015-07-24 17:03:44.214018", + "modified": "2015-08-07 13:21:23.840052", "modified_by": "Administrator", "module": "Stock", "name": "Stock Entry Detail", "owner": "Administrator", - "permissions": [] + "permissions": [], + "read_only": 0, + "read_only_onload": 0 } \ No newline at end of file diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py index dde338611b47..fa2fa1352ddb 100644 --- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py @@ -82,13 +82,13 @@ def insert_existing_sle(self): from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry make_stock_entry(posting_date="2012-12-15", posting_time="02:00", item_code="_Test Item", - target="_Test Warehouse - _TC", qty=10, incoming_rate=700) + target="_Test Warehouse - _TC", qty=10, basic_rate=700) make_stock_entry(posting_date="2012-12-25", posting_time="03:00", item_code="_Test Item", source="_Test Warehouse - _TC", qty=15) make_stock_entry(posting_date="2013-01-05", posting_time="07:00", item_code="_Test Item", - target="_Test Warehouse - _TC", qty=15, incoming_rate=1200) + target="_Test Warehouse - _TC", qty=15, basic_rate=1200) def create_stock_reconciliation(**args): args = frappe._dict(args) diff --git a/erpnext/templates/form_grid/stock_entry_grid.html b/erpnext/templates/form_grid/stock_entry_grid.html index 1782b82007ac..a2bf1df738f2 100644 --- a/erpnext/templates/form_grid/stock_entry_grid.html +++ b/erpnext/templates/form_grid/stock_entry_grid.html @@ -1,6 +1,6 @@ {% var visible_columns = row.get_visible_columns(["item_code", "item_name", "amount", "stock_uom", "uom", "qty", - "s_warehouse", "t_warehouse", "incoming_rate"]); + "s_warehouse", "t_warehouse", "valuation_rate"]); %} {% if(!doc) { %} @@ -43,7 +43,7 @@
{%= doc.get_formatted("amount") %}
- {%= doc.get_formatted("incoming_rate") %} + {%= doc.get_formatted("valuation_rate") %}
diff --git a/erpnext/utilities/repost_stock.py b/erpnext/utilities/repost_stock.py index 52b94aee798b..3cb18eed82ac 100644 --- a/erpnext/utilities/repost_stock.py +++ b/erpnext/utilities/repost_stock.py @@ -237,7 +237,7 @@ def repost_all_stock_vouchers(): doc = frappe.get_doc(voucher_type, voucher_no) if voucher_type=="Stock Entry" and doc.purpose in ["Manufacture", "Repack"]: - doc.get_stock_and_rate(force=1) + doc.calculate_rate_and_amount(force=1) elif voucher_type=="Purchase Receipt" and doc.is_subcontracted == "Yes": doc.validate() From 52f3bfca73982aabc978f523541e86b5d7886093 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 7 Aug 2015 18:58:52 +0530 Subject: [PATCH 6/6] change log and sponsors page --- .../change_log/current/stock_entry_additional_costs.md | 2 ++ sponsors.md | 8 ++++++++ 2 files changed, 10 insertions(+) create mode 100644 erpnext/change_log/current/stock_entry_additional_costs.md diff --git a/erpnext/change_log/current/stock_entry_additional_costs.md b/erpnext/change_log/current/stock_entry_additional_costs.md new file mode 100644 index 000000000000..ef03375381cf --- /dev/null +++ b/erpnext/change_log/current/stock_entry_additional_costs.md @@ -0,0 +1,2 @@ +- Additional Costs in Stock Entry **[Sponsored by PT. Ridho Sribumi Sejahtera]** + - Now additional costs like shipping charges, operating costs etc can be added in Stock Entry in item valuation \ No newline at end of file diff --git a/sponsors.md b/sponsors.md index 5f6c2f2c27e5..9b8448713509 100644 --- a/sponsors.md +++ b/sponsors.md @@ -29,5 +29,13 @@ For Sales / Purchase Return Enhancement #3582 + + + PT. Ridho Sribumi Sejahtera + + + For Additional Costs in Stock Entry #3613 + +