Additional Costs in Stock Entry
This commit is contained in:
parent
246e47e76e
commit
3c3a3ecea8
@ -746,7 +746,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
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()
|
||||
|
||||
|
@ -10,6 +10,9 @@ from frappe.model.document import Document
|
||||
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()
|
||||
|
@ -28,9 +28,9 @@ class TestProductionOrder(unittest.TestCase):
|
||||
|
||||
# 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 @@ class TestProductionOrder(unittest.TestCase):
|
||||
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()
|
||||
|
@ -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
|
||||
|
42
erpnext/patches/v5_4/stock_entry_additional_costs.py
Normal file
42
erpnext/patches/v5_4/stock_entry_additional_costs.py
Normal file
@ -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()
|
@ -37,7 +37,7 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
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 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
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 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
|
||||
# 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 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
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 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
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()
|
||||
|
||||
|
@ -47,7 +47,7 @@ class TestItem(unittest.TestCase):
|
||||
|
||||
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)
|
||||
|
||||
|
@ -305,7 +305,7 @@ def make_stock_entry(source_name, target_doc=None):
|
||||
|
||||
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": {
|
||||
|
@ -72,7 +72,7 @@ class TestMaterialRequest(unittest.TestCase):
|
||||
"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 @@ class TestMaterialRequest(unittest.TestCase):
|
||||
"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 @@ class TestMaterialRequest(unittest.TestCase):
|
||||
"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 @@ class TestMaterialRequest(unittest.TestCase):
|
||||
"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 @@ class TestMaterialRequest(unittest.TestCase):
|
||||
"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
|
||||
|
@ -80,9 +80,9 @@ class TestPurchaseReceipt(unittest.TestCase):
|
||||
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)
|
||||
|
@ -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<items.length;i++) {
|
||||
total_amount += flt(items[i].amount);
|
||||
}
|
||||
doc.total_amount = total_amount;
|
||||
refresh_field("total_amount");
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -29,8 +29,7 @@ class StockEntry(StockController):
|
||||
def onload(self):
|
||||
if self.docstatus==1:
|
||||
for item in self.get("items"):
|
||||
item.update(get_available_qty(item.item_code,
|
||||
item.s_warehouse))
|
||||
item.update(get_available_qty(item.item_code, item.s_warehouse))
|
||||
|
||||
def validate(self):
|
||||
self.pro_doc = None
|
||||
@ -46,15 +45,13 @@ class StockEntry(StockController):
|
||||
self.validate_uom_is_integer("stock_uom", "transfer_qty")
|
||||
self.validate_warehouse()
|
||||
self.validate_production_order()
|
||||
self.get_stock_and_rate()
|
||||
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()
|
||||
self.validate_batch()
|
||||
|
||||
self.set_actual_qty()
|
||||
self.calculate_rate_and_amount()
|
||||
|
||||
def on_submit(self):
|
||||
self.update_stock_ledger()
|
||||
@ -214,6 +211,88 @@ class StockEntry(StockController):
|
||||
if fg_qty_already_entered >= qty:
|
||||
frappe.throw(_("Stock Entries already created for Production Order ")
|
||||
+ self.production_order + ":" + ", ".join(other_ste), DuplicateEntryForProductionOrderError)
|
||||
|
||||
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'):
|
||||
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
|
||||
})
|
||||
|
||||
# get actual stock at source warehouse
|
||||
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:
|
||||
frappe.throw(_("""Row {0}: Qty not avalable in warehouse {1} on {2} {3}.
|
||||
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)
|
||||
|
||||
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,
|
||||
})
|
||||
|
||||
# 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
|
||||
|
||||
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):
|
||||
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])
|
||||
|
||||
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 validate_valuation_rate(self):
|
||||
if self.purpose in ["Manufacture", "Repack"]:
|
||||
@ -222,11 +301,11 @@ class StockEntry(StockController):
|
||||
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)
|
||||
valuation_at_target += flt(d.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))
|
||||
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
|
||||
@ -234,91 +313,13 @@ class StockEntry(StockController):
|
||||
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.total_outgoing_value += flt(d.amount)
|
||||
|
||||
self.value_difference = self.total_outgoing_value - self.total_incoming_value
|
||||
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 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"))
|
||||
|
||||
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({
|
||||
"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,
|
||||
})
|
||||
|
||||
# get actual stock at source warehouse
|
||||
d.actual_qty = get_previous_sle(args).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:
|
||||
frappe.throw(_("""Row {0}: Qty not avalable in warehouse {1} on {2} {3}.
|
||||
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)
|
||||
|
||||
|
||||
self.add_operation_cost(raw_material_cost, force)
|
||||
|
||||
def add_operation_cost(self, raw_material_cost, force):
|
||||
"""Adds operating cost if Production Order is set"""
|
||||
# set incoming rate for fg item
|
||||
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.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
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
# 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)
|
||||
|
||||
return operation_cost_per_unit
|
||||
|
||||
def validate_purchase_order(self):
|
||||
"""Throw exception if more raw material is transferred against Purchase Order than in
|
||||
the raw materials supplied table"""
|
||||
@ -367,9 +368,7 @@ class StockEntry(StockController):
|
||||
|
||||
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 @@ class StockEntry(StockController):
|
||||
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 @@ class StockEntry(StockController):
|
||||
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 @@ class StockEntry(StockController):
|
||||
"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 @@ class StockEntry(StockController):
|
||||
'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 @@ class StockEntry(StockController):
|
||||
|
||||
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 @@ class StockEntry(StockController):
|
||||
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 @@ class StockEntry(StockController):
|
||||
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
|
@ -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,
|
||||
|
@ -36,12 +36,12 @@ class TestStockEntry(unittest.TestCase):
|
||||
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 @@ class TestStockEntry(unittest.TestCase):
|
||||
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 @@ class TestStockEntry(unittest.TestCase):
|
||||
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 @@ class TestStockEntry(unittest.TestCase):
|
||||
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 @@ class TestStockEntry(unittest.TestCase):
|
||||
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 @@ class TestStockEntry(unittest.TestCase):
|
||||
|
||||
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 @@ class TestStockEntry(unittest.TestCase):
|
||||
"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 @@ class TestStockEntry(unittest.TestCase):
|
||||
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 @@ class TestStockEntry(unittest.TestCase):
|
||||
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 @@ class TestStockEntry(unittest.TestCase):
|
||||
"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 @@ class TestStockEntry(unittest.TestCase):
|
||||
|
||||
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"
|
||||
|
@ -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
|
||||
"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,
|
||||
"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
|
||||
}
|
@ -82,13 +82,13 @@ class TestStockReconciliation(unittest.TestCase):
|
||||
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)
|
||||
|
@ -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 @@
|
||||
<div class="col-sm-2 col-xs-2 text-right">
|
||||
{%= doc.get_formatted("amount") %}
|
||||
<div class="small text-muted">
|
||||
{%= doc.get_formatted("incoming_rate") %}
|
||||
{%= doc.get_formatted("valuation_rate") %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -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()
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user