Fixed merge conflict
This commit is contained in:
commit
ae1dcabcb5
@ -227,10 +227,11 @@ cur_frm.cscript.voucher_type = function(doc, cdt, cdn) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var update_jv_details = function(doc, r) {
|
var update_jv_details = function(doc, r) {
|
||||||
$.each(r.message, function(i, d) {
|
var jvdetail = frappe.model.add_child(doc, "Journal Voucher Detail", "entries");
|
||||||
var jvdetail = frappe.model.add_child(doc, "Journal Voucher Detail", "entries");
|
$.each(r, function(i, d) {
|
||||||
jvdetail.account = d.account;
|
var row = frappe.model.add_child(doc, "Journal Voucher Detail", "entries");
|
||||||
jvdetail.balance = d.balance;
|
row.account = d.account;
|
||||||
|
row.balance = d.balance;
|
||||||
});
|
});
|
||||||
refresh_field("entries");
|
refresh_field("entries");
|
||||||
}
|
}
|
||||||
@ -245,7 +246,7 @@ cur_frm.cscript.voucher_type = function(doc, cdt, cdn) {
|
|||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if(r.message) {
|
if(r.message) {
|
||||||
update_jv_details(doc, r);
|
update_jv_details(doc, [r.message]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -259,7 +260,7 @@ cur_frm.cscript.voucher_type = function(doc, cdt, cdn) {
|
|||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
frappe.model.clear_table(doc, "entries");
|
frappe.model.clear_table(doc, "entries");
|
||||||
if(r.message) {
|
if(r.message) {
|
||||||
update_jv_details(doc, r);
|
update_jv_details(doc, r.message);
|
||||||
}
|
}
|
||||||
cur_frm.set_value("is_opening", "Yes")
|
cur_frm.set_value("is_opening", "Yes")
|
||||||
}
|
}
|
||||||
|
@ -111,13 +111,14 @@ class PaymentReconciliation(Document):
|
|||||||
|
|
||||||
payment_amount = payment_amount[0][0] if payment_amount else 0
|
payment_amount = payment_amount[0][0] if payment_amount else 0
|
||||||
|
|
||||||
if d.invoice_amount > payment_amount:
|
if d.invoice_amount - payment_amount > 0.005:
|
||||||
non_reconciled_invoices.append({
|
non_reconciled_invoices.append({
|
||||||
'voucher_no': d.voucher_no,
|
'voucher_no': d.voucher_no,
|
||||||
'voucher_type': d.voucher_type,
|
'voucher_type': d.voucher_type,
|
||||||
'posting_date': d.posting_date,
|
'posting_date': d.posting_date,
|
||||||
'invoice_amount': flt(d.invoice_amount),
|
'invoice_amount': flt(d.invoice_amount),
|
||||||
'outstanding_amount': d.invoice_amount - payment_amount})
|
'outstanding_amount': flt(d.invoice_amount - payment_amount, 2)
|
||||||
|
})
|
||||||
|
|
||||||
self.add_invoice_entries(non_reconciled_invoices)
|
self.add_invoice_entries(non_reconciled_invoices)
|
||||||
|
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
"doc_type": "Journal Voucher",
|
"doc_type": "Journal Voucher",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "Print Format",
|
"doctype": "Print Format",
|
||||||
"html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n<div class=\"page-break\">\n {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n and doc.set(\"select_print_heading\", _(\"Payment Receipt Note\")) -%}{%- endif -%}\n {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n {%- for label, value in (\n (_(\"Received On\"), frappe.utils.formatdate(doc.voucher_date)),\n (_(\"Received From\"), doc.pay_to_recd_from),\n (_(\"Amount\"), \"<strong>\" + doc.total_amount + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n (_(\"Remarks\"), doc.remark)\n ) -%}\n <div class=\"row\">\n <div class=\"col-sm-3\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-sm-9\">{{ value }}</div>\n </div>\n\n {%- endfor -%}\n\n <hr>\n <br>\n <p class=\"strong\">\n {{ _(\"For\") }} {{ doc.company }},<br>\n <br>\n <br>\n <br>\n {{ _(\"Authorized Signatory\") }}\n </p>\n</div>\n\n",
|
"html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n<div class=\"page-break\">\n {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n and doc.set(\"select_print_heading\", _(\"Payment Receipt Note\")) -%}{%- endif -%}\n {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n {%- for label, value in (\n (_(\"Received On\"), frappe.utils.formatdate(doc.voucher_date)),\n (_(\"Received From\"), doc.pay_to_recd_from),\n (_(\"Amount\"), \"<strong>\" + doc.total_amount or 0 + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n (_(\"Remarks\"), doc.remark)\n ) -%}\n <div class=\"row\">\n <div class=\"col-sm-3\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-sm-9\">{{ value }}</div>\n </div>\n\n {%- endfor -%}\n\n <hr>\n <br>\n <p class=\"strong\">\n {{ _(\"For\") }} {{ doc.company }},<br>\n <br>\n <br>\n <br>\n {{ _(\"Authorized Signatory\") }}\n </p>\n</div>\n\n",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"modified": "2014-08-29 15:55:34.248384",
|
"modified": "2014-11-04 11:25:57.560873",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Payment Receipt Voucher",
|
"name": "Payment Receipt Voucher",
|
||||||
|
@ -3,15 +3,13 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
|
from frappe.utils import flt
|
||||||
from frappe.utils import cstr, flt
|
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
|
||||||
from erpnext.stock.doctype.item.item import get_last_purchase_details
|
from erpnext.stock.doctype.item.item import get_last_purchase_details
|
||||||
from erpnext.controllers.buying_controller import BuyingController
|
from erpnext.controllers.buying_controller import BuyingController
|
||||||
|
|
||||||
class PurchaseCommon(BuyingController):
|
class PurchaseCommon(BuyingController):
|
||||||
|
|
||||||
def update_last_purchase_rate(self, obj, is_submit):
|
def update_last_purchase_rate(self, obj, is_submit):
|
||||||
"""updates last_purchase_rate in item table for each item"""
|
"""updates last_purchase_rate in item table for each item"""
|
||||||
|
|
||||||
@ -123,27 +121,6 @@ class PurchaseCommon(BuyingController):
|
|||||||
else:
|
else:
|
||||||
chk_dupl_itm.append(f)
|
chk_dupl_itm.append(f)
|
||||||
|
|
||||||
def get_qty(self, curr_doctype, ref_tab_fname, ref_tab_dn, ref_doc_tname, transaction, curr_parent_name):
|
|
||||||
# Get total Quantities of current doctype (eg. PR) except for qty of this transaction
|
|
||||||
#------------------------------
|
|
||||||
# please check as UOM changes from Material Request - Purchase Order ,so doing following else uom should be same .
|
|
||||||
# i.e. in PO uom is NOS then in PR uom should be NOS
|
|
||||||
# but if in Material Request uom KG it can change in PO
|
|
||||||
|
|
||||||
get_qty = (transaction == 'Material Request - Purchase Order') and 'qty * conversion_factor' or 'qty'
|
|
||||||
qty = frappe.db.sql("""select sum(%s) from `tab%s` where %s = %s and
|
|
||||||
docstatus = 1 and parent != %s""" % (get_qty, curr_doctype, ref_tab_fname, '%s', '%s'),
|
|
||||||
(ref_tab_dn, curr_parent_name))
|
|
||||||
qty = qty and flt(qty[0][0]) or 0
|
|
||||||
|
|
||||||
# get total qty of ref doctype
|
|
||||||
#--------------------
|
|
||||||
max_qty = frappe.db.sql("""select qty from `tab%s` where name = %s
|
|
||||||
and docstatus = 1""" % (ref_doc_tname, '%s'), ref_tab_dn)
|
|
||||||
max_qty = max_qty and flt(max_qty[0][0]) or 0
|
|
||||||
|
|
||||||
return cstr(qty)+'~~~'+cstr(max_qty)
|
|
||||||
|
|
||||||
def check_for_stopped_status(self, doctype, docname):
|
def check_for_stopped_status(self, doctype, docname):
|
||||||
stopped = frappe.db.sql("""select name from `tab%s` where name = %s and
|
stopped = frappe.db.sql("""select name from `tab%s` where name = %s and
|
||||||
status = 'Stopped'""" % (doctype, '%s'), docname)
|
status = 'Stopped'""" % (doctype, '%s'), docname)
|
||||||
|
@ -96,50 +96,45 @@ class PurchaseOrder(BuyingController):
|
|||||||
check_list.append(d.prevdoc_docname)
|
check_list.append(d.prevdoc_docname)
|
||||||
pc_obj.check_for_stopped_status( d.prevdoc_doctype, d.prevdoc_docname)
|
pc_obj.check_for_stopped_status( d.prevdoc_doctype, d.prevdoc_docname)
|
||||||
|
|
||||||
|
def update_requested_qty(self):
|
||||||
|
material_request_map = {}
|
||||||
|
for d in self.get("po_details"):
|
||||||
|
if d.prevdoc_doctype and d.prevdoc_doctype == "Material Request" and d.prevdoc_detail_docname:
|
||||||
|
material_request_map.setdefault(d.prevdoc_docname, []).append(d.prevdoc_detail_docname)
|
||||||
|
|
||||||
def update_bin(self, is_submit, is_stopped = 0):
|
for mr, mr_item_rows in material_request_map.items():
|
||||||
from erpnext.stock.utils import update_bin
|
if mr and mr_item_rows:
|
||||||
pc_obj = frappe.get_doc('Purchase Common')
|
mr_obj = frappe.get_doc("Material Request", mr)
|
||||||
for d in self.get('po_details'):
|
|
||||||
#1. Check if is_stock_item == 'Yes'
|
|
||||||
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes":
|
|
||||||
# this happens when item is changed from non-stock to stock item
|
|
||||||
if not d.warehouse:
|
|
||||||
continue
|
|
||||||
|
|
||||||
ind_qty, po_qty = 0, flt(d.qty) * flt(d.conversion_factor)
|
if mr_obj.status in ["Stopped", "Cancelled"]:
|
||||||
if is_stopped:
|
frappe.throw(_("Material Request {0} is cancelled or stopped").format(mr), frappe.InvalidStatusError)
|
||||||
po_qty = flt(d.qty) > flt(d.received_qty) and \
|
|
||||||
flt( flt(flt(d.qty) - flt(d.received_qty))*flt(d.conversion_factor)) or 0
|
|
||||||
|
|
||||||
# No updates in Material Request on Stop / Unstop
|
mr_obj.update_requested_qty(mr_item_rows)
|
||||||
if cstr(d.prevdoc_doctype) == 'Material Request' and not is_stopped:
|
|
||||||
# get qty and pending_qty of prevdoc
|
|
||||||
curr_ref_qty = pc_obj.get_qty(d.doctype, 'prevdoc_detail_docname',
|
|
||||||
d.prevdoc_detail_docname, 'Material Request Item',
|
|
||||||
'Material Request - Purchase Order', self.name)
|
|
||||||
max_qty, qty, curr_qty = flt(curr_ref_qty.split('~~~')[1]), \
|
|
||||||
flt(curr_ref_qty.split('~~~')[0]), 0
|
|
||||||
|
|
||||||
if flt(qty) + flt(po_qty) > flt(max_qty):
|
def update_ordered_qty(self, po_item_rows=None):
|
||||||
curr_qty = flt(max_qty) - flt(qty)
|
"""update requested qty (before ordered_qty is updated)"""
|
||||||
# special case as there is no restriction
|
from erpnext.stock.utils import get_bin
|
||||||
# for Material Request - Purchase Order
|
|
||||||
curr_qty = curr_qty > 0 and curr_qty or 0
|
|
||||||
else:
|
|
||||||
curr_qty = flt(po_qty)
|
|
||||||
|
|
||||||
ind_qty = -flt(curr_qty)
|
def _update_ordered_qty(item_code, warehouse):
|
||||||
|
ordered_qty = frappe.db.sql("""
|
||||||
|
select sum((po_item.qty - ifnull(po_item.received_qty, 0))*po_item.conversion_factor)
|
||||||
|
from `tabPurchase Order Item` po_item, `tabPurchase Order` po
|
||||||
|
where po_item.item_code=%s and po_item.warehouse=%s
|
||||||
|
and po_item.qty > ifnull(po_item.received_qty, 0) and po_item.parent=po.name
|
||||||
|
and po.status!='Stopped' and po.docstatus=1""", (item_code, warehouse))
|
||||||
|
|
||||||
# Update ordered_qty and indented_qty in bin
|
bin_doc = get_bin(item_code, warehouse)
|
||||||
args = {
|
bin_doc.ordered_qty = flt(ordered_qty[0][0]) if ordered_qty else 0
|
||||||
"item_code": d.item_code,
|
bin_doc.save()
|
||||||
"warehouse": d.warehouse,
|
|
||||||
"ordered_qty": (is_submit and 1 or -1) * flt(po_qty),
|
item_wh_list = []
|
||||||
"indented_qty": (is_submit and 1 or -1) * flt(ind_qty),
|
for d in self.get("po_details"):
|
||||||
"posting_date": self.transaction_date
|
if (not po_item_rows or d.name in po_item_rows) and [d.item_code, d.warehouse] not in item_wh_list \
|
||||||
}
|
and frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes" and d.warehouse:
|
||||||
update_bin(args)
|
item_wh_list.append([d.item_code, d.warehouse])
|
||||||
|
|
||||||
|
for item_code, warehouse in item_wh_list:
|
||||||
|
_update_ordered_qty(item_code, warehouse)
|
||||||
|
|
||||||
def check_modified_date(self):
|
def check_modified_date(self):
|
||||||
mod_db = frappe.db.sql("select modified from `tabPurchase Order` where name = %s",
|
mod_db = frappe.db.sql("select modified from `tabPurchase Order` where name = %s",
|
||||||
@ -152,13 +147,11 @@ class PurchaseOrder(BuyingController):
|
|||||||
|
|
||||||
def update_status(self, status):
|
def update_status(self, status):
|
||||||
self.check_modified_date()
|
self.check_modified_date()
|
||||||
# step 1:=> Set Status
|
|
||||||
frappe.db.set(self,'status',cstr(status))
|
frappe.db.set(self,'status',cstr(status))
|
||||||
|
|
||||||
# step 2:=> Update Bin
|
self.update_requested_qty()
|
||||||
self.update_bin(is_submit = (status == 'Submitted') and 1 or 0, is_stopped = 1)
|
self.update_ordered_qty()
|
||||||
|
|
||||||
# step 3:=> Acknowledge user
|
|
||||||
msgprint(_("Status of {0} {1} is now {2}").format(self.doctype, self.name, status))
|
msgprint(_("Status of {0} {1} is now {2}").format(self.doctype, self.name, status))
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
@ -167,7 +160,8 @@ class PurchaseOrder(BuyingController):
|
|||||||
purchase_controller = frappe.get_doc("Purchase Common")
|
purchase_controller = frappe.get_doc("Purchase Common")
|
||||||
|
|
||||||
self.update_prevdoc_status()
|
self.update_prevdoc_status()
|
||||||
self.update_bin(is_submit = 1, is_stopped = 0)
|
self.update_requested_qty()
|
||||||
|
self.update_ordered_qty()
|
||||||
|
|
||||||
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
|
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
|
||||||
self.company, self.grand_total)
|
self.company, self.grand_total)
|
||||||
@ -192,8 +186,13 @@ class PurchaseOrder(BuyingController):
|
|||||||
throw(_("Purchase Invoice {0} is already submitted").format(", ".join(submitted)))
|
throw(_("Purchase Invoice {0} is already submitted").format(", ".join(submitted)))
|
||||||
|
|
||||||
frappe.db.set(self,'status','Cancelled')
|
frappe.db.set(self,'status','Cancelled')
|
||||||
|
|
||||||
self.update_prevdoc_status()
|
self.update_prevdoc_status()
|
||||||
self.update_bin( is_submit = 0, is_stopped = 0)
|
|
||||||
|
# Must be called after updating ordered qty in Material Request
|
||||||
|
self.update_requested_qty()
|
||||||
|
self.update_ordered_qty()
|
||||||
|
|
||||||
pc_obj.update_last_purchase_rate(self, is_submit = 0)
|
pc_obj.update_last_purchase_rate(self, is_submit = 0)
|
||||||
|
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
|
@ -29,8 +29,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
frappe.get_doc(pr).insert()
|
frappe.get_doc(pr).insert()
|
||||||
|
|
||||||
def test_ordered_qty(self):
|
def test_ordered_qty(self):
|
||||||
frappe.db.sql("delete from tabBin")
|
existing_ordered_qty = self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt
|
from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt
|
||||||
|
|
||||||
po = frappe.copy_doc(test_records[0]).insert()
|
po = frappe.copy_doc(test_records[0]).insert()
|
||||||
@ -43,8 +42,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
po.get("po_details")[0].item_code = "_Test Item"
|
po.get("po_details")[0].item_code = "_Test Item"
|
||||||
po.submit()
|
po.submit()
|
||||||
|
|
||||||
self.assertEquals(frappe.db.get_value("Bin", {"item_code": "_Test Item",
|
self.assertEquals(self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC"), existing_ordered_qty + 10)
|
||||||
"warehouse": "_Test Warehouse - _TC"}, "ordered_qty"), 10)
|
|
||||||
|
|
||||||
pr = make_purchase_receipt(po.name)
|
pr = make_purchase_receipt(po.name)
|
||||||
|
|
||||||
@ -56,8 +54,9 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
pr.insert()
|
pr.insert()
|
||||||
pr.submit()
|
pr.submit()
|
||||||
|
|
||||||
self.assertEquals(flt(frappe.db.get_value("Bin", {"item_code": "_Test Item",
|
po.load_from_db()
|
||||||
"warehouse": "_Test Warehouse - _TC"}, "ordered_qty")), 6.0)
|
self.assertEquals(po.get("po_details")[0].received_qty, 4)
|
||||||
|
self.assertEquals(self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC"), existing_ordered_qty + 6)
|
||||||
|
|
||||||
frappe.db.set_value('Item', '_Test Item', 'tolerance', 50)
|
frappe.db.set_value('Item', '_Test Item', 'tolerance', 50)
|
||||||
|
|
||||||
@ -68,8 +67,16 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
pr1.insert()
|
pr1.insert()
|
||||||
pr1.submit()
|
pr1.submit()
|
||||||
|
|
||||||
self.assertEquals(flt(frappe.db.get_value("Bin", {"item_code": "_Test Item",
|
po.load_from_db()
|
||||||
"warehouse": "_Test Warehouse - _TC"}, "ordered_qty")), 0.0)
|
self.assertEquals(po.get("po_details")[0].received_qty, 12)
|
||||||
|
self.assertEquals(self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC"), existing_ordered_qty)
|
||||||
|
|
||||||
|
pr1.load_from_db()
|
||||||
|
pr1.cancel()
|
||||||
|
|
||||||
|
po.load_from_db()
|
||||||
|
self.assertEquals(po.get("po_details")[0].received_qty, 4)
|
||||||
|
self.assertEquals(self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC"), existing_ordered_qty + 6)
|
||||||
|
|
||||||
def test_make_purchase_invoice(self):
|
def test_make_purchase_invoice(self):
|
||||||
from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_invoice
|
from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_invoice
|
||||||
@ -113,6 +120,9 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
from erpnext.controllers.tests.test_recurring_document import test_recurring_document
|
from erpnext.controllers.tests.test_recurring_document import test_recurring_document
|
||||||
test_recurring_document(self, test_records)
|
test_recurring_document(self, test_records)
|
||||||
|
|
||||||
|
def _get_ordered_qty(self, item_code, warehouse):
|
||||||
|
return flt(frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}, "ordered_qty"))
|
||||||
|
|
||||||
|
|
||||||
test_dependencies = ["BOM", "Item Price"]
|
test_dependencies = ["BOM", "Item Price"]
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ class StockController(AccountsController):
|
|||||||
_(self.doctype), self.name, item.get("item_code")))
|
_(self.doctype), self.name, item.get("item_code")))
|
||||||
|
|
||||||
def get_sl_entries(self, d, args):
|
def get_sl_entries(self, d, args):
|
||||||
sl_dict = {
|
sl_dict = frappe._dict({
|
||||||
"item_code": d.get("item_code", None),
|
"item_code": d.get("item_code", None),
|
||||||
"warehouse": d.get("warehouse", None),
|
"warehouse": d.get("warehouse", None),
|
||||||
"posting_date": self.posting_date,
|
"posting_date": self.posting_date,
|
||||||
@ -192,7 +192,7 @@ class StockController(AccountsController):
|
|||||||
"serial_no": d.get("serial_no"),
|
"serial_no": d.get("serial_no"),
|
||||||
"project": d.get("project_name"),
|
"project": d.get("project_name"),
|
||||||
"is_cancelled": self.docstatus==2 and "Yes" or "No"
|
"is_cancelled": self.docstatus==2 and "Yes" or "No"
|
||||||
}
|
})
|
||||||
|
|
||||||
sl_dict.update(args)
|
sl_dict.update(args)
|
||||||
return sl_dict
|
return sl_dict
|
||||||
|
@ -34,8 +34,8 @@ communication_covert_to = ["Lead", "Support Ticket", "Job Application"]
|
|||||||
|
|
||||||
doc_events = {
|
doc_events = {
|
||||||
"Stock Entry": {
|
"Stock Entry": {
|
||||||
"on_submit": "erpnext.stock.doctype.material_request.material_request.update_completed_qty",
|
"on_submit": "erpnext.stock.doctype.material_request.material_request.update_completed_and_requested_qty",
|
||||||
"on_cancel": "erpnext.stock.doctype.material_request.material_request.update_completed_qty"
|
"on_cancel": "erpnext.stock.doctype.material_request.material_request.update_completed_and_requested_qty"
|
||||||
},
|
},
|
||||||
"User": {
|
"User": {
|
||||||
"validate": "erpnext.hr.doctype.employee.employee.validate_employee_role",
|
"validate": "erpnext.hr.doctype.employee.employee.validate_employee_role",
|
||||||
|
@ -87,6 +87,7 @@ execute:frappe.delete_doc("DocType", "Purchase Request")
|
|||||||
execute:frappe.delete_doc("DocType", "Purchase Request Item")
|
execute:frappe.delete_doc("DocType", "Purchase Request Item")
|
||||||
erpnext.patches.v4_2.recalculate_bom_cost
|
erpnext.patches.v4_2.recalculate_bom_cost
|
||||||
erpnext.patches.v4_2.fix_gl_entries_for_stock_transactions
|
erpnext.patches.v4_2.fix_gl_entries_for_stock_transactions
|
||||||
|
erpnext.patches.v4_2.update_requested_and_ordered_qty
|
||||||
erpnext.patches.v4_2.party_model
|
erpnext.patches.v4_2.party_model
|
||||||
erpnext.patches.v5_0.update_frozen_accounts_permission_role
|
erpnext.patches.v5_0.update_frozen_accounts_permission_role
|
||||||
erpnext.patches.v5_0.update_dn_against_doc_fields
|
erpnext.patches.v5_0.update_dn_against_doc_fields
|
||||||
|
24
erpnext/patches/v4_2/update_requested_and_ordered_qty.py
Normal file
24
erpnext/patches/v4_2/update_requested_and_ordered_qty.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
from erpnext.utilities.repost_stock import update_bin_qty, get_indented_qty, get_ordered_qty
|
||||||
|
|
||||||
|
count=0
|
||||||
|
for item_code, warehouse in frappe.db.sql("""select distinct item_code, warehouse from
|
||||||
|
(select item_code, warehouse from tabBin
|
||||||
|
union
|
||||||
|
select item_code, warehouse from `tabStock Ledger Entry`) a"""):
|
||||||
|
try:
|
||||||
|
count += 1
|
||||||
|
update_bin_qty(item_code, warehouse, {
|
||||||
|
"indented_qty": get_indented_qty(item_code, warehouse),
|
||||||
|
"ordered_qty": get_ordered_qty(item_code, warehouse)
|
||||||
|
})
|
||||||
|
if count % 200 == 0:
|
||||||
|
frappe.db.commit()
|
||||||
|
except:
|
||||||
|
frappe.db.rollback()
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"creation": "2013-04-03 16:38:41",
|
"creation": "2013-04-03 16:38:41",
|
||||||
"description": "Log of Activities performed by users against Tasks that can be used for tracking time, billing.",
|
"description": "Log of Activities performed by users against Tasks that can be used for tracking time, billing.",
|
||||||
@ -25,14 +25,6 @@
|
|||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "hours",
|
|
||||||
"fieldtype": "Float",
|
|
||||||
"in_list_view": 1,
|
|
||||||
"label": "Hours",
|
|
||||||
"permlevel": 0,
|
|
||||||
"read_only": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "to_time",
|
"fieldname": "to_time",
|
||||||
"fieldtype": "Datetime",
|
"fieldtype": "Datetime",
|
||||||
@ -42,6 +34,14 @@
|
|||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "hours",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Hours",
|
||||||
|
"permlevel": 0,
|
||||||
|
"read_only": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_3",
|
"fieldname": "column_break_3",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
@ -151,7 +151,7 @@
|
|||||||
"icon": "icon-time",
|
"icon": "icon-time",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"modified": "2014-08-04 05:23:15.740050",
|
"modified": "2014-10-22 16:53:26.993828",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Projects",
|
"module": "Projects",
|
||||||
"name": "Time Log",
|
"name": "Time Log",
|
||||||
|
@ -131,6 +131,7 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({
|
|||||||
|
|
||||||
if(me.is_default("warehouse") ? true : me.warehouse == sl.warehouse) {
|
if(me.is_default("warehouse") ? true : me.warehouse == sl.warehouse) {
|
||||||
var item = me.item_by_name[sl.item_code];
|
var item = me.item_by_name[sl.item_code];
|
||||||
|
if(item.closing_qty_value==undefined) item.closing_qty_value = 0;
|
||||||
|
|
||||||
if(me.value_or_qty!="Quantity") {
|
if(me.value_or_qty!="Quantity") {
|
||||||
var wh = me.get_item_warehouse(sl.warehouse, sl.item_code);
|
var wh = me.get_item_warehouse(sl.warehouse, sl.item_code);
|
||||||
|
@ -589,18 +589,18 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
|
|||||||
});
|
});
|
||||||
|
|
||||||
frappe.ui.form.on(cur_frm.doctype,"project_name", function(frm) {
|
frappe.ui.form.on(cur_frm.doctype,"project_name", function(frm) {
|
||||||
frappe.call({
|
if(in_list(["Delivery Note", "Sales Invoice"], frm.doc.doctype)) {
|
||||||
method:'erpnext.projects.doctype.project.project.get_cost_center_name' ,
|
frappe.call({
|
||||||
args: { project_name: frm.doc.project_name },
|
method:'erpnext.projects.doctype.project.project.get_cost_center_name' ,
|
||||||
callback: function(r, rt) {
|
args: { project_name: frm.doc.project_name },
|
||||||
if(!r.exc && r.message) {
|
callback: function(r, rt) {
|
||||||
$.each(frm.doc[cur_frm.cscript.fname] || [], function(i, row) {
|
if(!r.exc) {
|
||||||
if(frappe.meta.has_field(cur_frm.cscript.tname , "cost_center")) {
|
$.each(frm.doc[cur_frm.cscript.fname] || [], function(i, row) {
|
||||||
frappe.model.set_value(row.doctype, row.name, "cost_center", r.message);
|
frappe.model.set_value(row.doctype, row.name, "cost_center", r.message);
|
||||||
msgprint(__("Cost Center For Item with Item Code '"+row.item_name+"' has been Changed to "+ r.message));
|
msgprint(__("Cost Center For Item with Item Code '"+row.item_name+"' has been Changed to "+ r.message));
|
||||||
}
|
})
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})
|
}
|
||||||
})
|
})
|
||||||
|
@ -68,11 +68,15 @@ class DeliveryNote(SellingController):
|
|||||||
else:
|
else:
|
||||||
df.delete_key("__print_hide")
|
df.delete_key("__print_hide")
|
||||||
|
|
||||||
toggle_print_hide(self.meta, "currency")
|
|
||||||
|
|
||||||
item_meta = frappe.get_meta("Delivery Note Item")
|
item_meta = frappe.get_meta("Delivery Note Item")
|
||||||
for fieldname in ("rate", "amount", "price_list_rate", "discount_percentage"):
|
print_hide_fields = {
|
||||||
toggle_print_hide(item_meta, fieldname)
|
"parent": ["grand_total_export", "rounded_total_export", "in_words_export", "currency", "net_total_export"],
|
||||||
|
"items": ["rate", "amount", "price_list_rate", "discount_percentage"]
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, fieldname in print_hide_fields.items():
|
||||||
|
for f in fieldname:
|
||||||
|
toggle_print_hide(self.meta if key == "parent" else item_meta, f)
|
||||||
|
|
||||||
def get_portal_page(self):
|
def get_portal_page(self):
|
||||||
return "shipment" if self.docstatus==1 else None
|
return "shipment" if self.docstatus==1 else None
|
||||||
|
@ -82,30 +82,9 @@ class MaterialRequest(BuyingController):
|
|||||||
# NOTE: Since Item BOM and FG quantities are combined, using current data, it cannot be validated
|
# NOTE: Since Item BOM and FG quantities are combined, using current data, it cannot be validated
|
||||||
# Though the creation of Material Request from a Production Plan can be rethought to fix this
|
# Though the creation of Material Request from a Production Plan can be rethought to fix this
|
||||||
|
|
||||||
def update_bin(self, is_submit, is_stopped):
|
|
||||||
""" Update Quantity Requested for Purchase in Bin for Material Request of type 'Purchase'"""
|
|
||||||
|
|
||||||
from erpnext.stock.utils import update_bin
|
|
||||||
for d in self.get('indent_details'):
|
|
||||||
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes":
|
|
||||||
if not d.warehouse:
|
|
||||||
frappe.throw(_("Warehouse required for stock Item {0}").format(d.item_code))
|
|
||||||
|
|
||||||
qty =flt(d.qty)
|
|
||||||
if is_stopped:
|
|
||||||
qty = (d.qty > d.ordered_qty) and flt(flt(d.qty) - flt(d.ordered_qty)) or 0
|
|
||||||
|
|
||||||
args = {
|
|
||||||
"item_code": d.item_code,
|
|
||||||
"warehouse": d.warehouse,
|
|
||||||
"indented_qty": (is_submit and 1 or -1) * flt(qty),
|
|
||||||
"posting_date": self.transaction_date
|
|
||||||
}
|
|
||||||
update_bin(args)
|
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
frappe.db.set(self, 'status', 'Submitted')
|
frappe.db.set(self, 'status', 'Submitted')
|
||||||
self.update_bin(is_submit = 1, is_stopped = 0)
|
self.update_requested_qty()
|
||||||
|
|
||||||
def check_modified_date(self):
|
def check_modified_date(self):
|
||||||
mod_db = frappe.db.sql("""select modified from `tabMaterial Request` where name = %s""",
|
mod_db = frappe.db.sql("""select modified from `tabMaterial Request` where name = %s""",
|
||||||
@ -118,23 +97,18 @@ class MaterialRequest(BuyingController):
|
|||||||
|
|
||||||
def update_status(self, status):
|
def update_status(self, status):
|
||||||
self.check_modified_date()
|
self.check_modified_date()
|
||||||
self.update_bin(is_submit = (status == 'Submitted') and 1 or 0, is_stopped = 1)
|
self.update_requested_qty()
|
||||||
frappe.db.set(self, 'status', cstr(status))
|
frappe.db.set(self, 'status', cstr(status))
|
||||||
frappe.msgprint(_("Status updated to {0}").format(_(status)))
|
frappe.msgprint(_("Status updated to {0}").format(_(status)))
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
# Step 1:=> Get Purchase Common Obj
|
|
||||||
pc_obj = frappe.get_doc('Purchase Common')
|
pc_obj = frappe.get_doc('Purchase Common')
|
||||||
|
|
||||||
# Step 2:=> Check for stopped status
|
|
||||||
pc_obj.check_for_stopped_status(self.doctype, self.name)
|
pc_obj.check_for_stopped_status(self.doctype, self.name)
|
||||||
|
|
||||||
# Step 3:=> Check if Purchase Order has been submitted against current Material Request
|
|
||||||
pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Order', docname = self.name, detail_doctype = 'Purchase Order Item')
|
pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Order', docname = self.name, detail_doctype = 'Purchase Order Item')
|
||||||
# Step 4:=> Update Bin
|
|
||||||
self.update_bin(is_submit = 0, is_stopped = (cstr(self.status) == 'Stopped') and 1 or 0)
|
|
||||||
|
|
||||||
# Step 5:=> Set Status
|
self.update_requested_qty()
|
||||||
|
|
||||||
frappe.db.set(self,'status','Cancelled')
|
frappe.db.set(self,'status','Cancelled')
|
||||||
|
|
||||||
def update_completed_qty(self, mr_items=None):
|
def update_completed_qty(self, mr_items=None):
|
||||||
@ -165,56 +139,47 @@ class MaterialRequest(BuyingController):
|
|||||||
self.per_ordered = flt((per_ordered / flt(len(item_doclist))) * 100.0, 2)
|
self.per_ordered = flt((per_ordered / flt(len(item_doclist))) * 100.0, 2)
|
||||||
frappe.db.set_value(self.doctype, self.name, "per_ordered", self.per_ordered)
|
frappe.db.set_value(self.doctype, self.name, "per_ordered", self.per_ordered)
|
||||||
|
|
||||||
def update_completed_qty(doc, method):
|
def update_requested_qty(self, mr_item_rows=None):
|
||||||
if doc.doctype == "Stock Entry":
|
"""update requested qty (before ordered_qty is updated)"""
|
||||||
|
from erpnext.stock.utils import get_bin
|
||||||
|
|
||||||
|
def _update_requested_qty(item_code, warehouse):
|
||||||
|
requested_qty = frappe.db.sql("""select sum(mr_item.qty - ifnull(mr_item.ordered_qty, 0))
|
||||||
|
from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
|
||||||
|
where mr_item.item_code=%s and mr_item.warehouse=%s
|
||||||
|
and mr_item.qty > ifnull(mr_item.ordered_qty, 0) and mr_item.parent=mr.name
|
||||||
|
and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
|
||||||
|
|
||||||
|
bin_doc = get_bin(item_code, warehouse)
|
||||||
|
bin_doc.indented_qty = flt(requested_qty[0][0]) if requested_qty else 0
|
||||||
|
bin_doc.save()
|
||||||
|
|
||||||
|
item_wh_list = []
|
||||||
|
for d in self.get("indent_details"):
|
||||||
|
if (not mr_item_rows or d.name in mr_item_rows) and [d.item_code, d.warehouse] not in item_wh_list \
|
||||||
|
and frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes" and d.warehouse:
|
||||||
|
item_wh_list.append([d.item_code, d.warehouse])
|
||||||
|
|
||||||
|
for item_code, warehouse in item_wh_list:
|
||||||
|
_update_requested_qty(item_code, warehouse)
|
||||||
|
|
||||||
|
def update_completed_and_requested_qty(stock_entry, method):
|
||||||
|
if stock_entry.doctype == "Stock Entry":
|
||||||
material_request_map = {}
|
material_request_map = {}
|
||||||
|
|
||||||
for d in doc.get("mtn_details"):
|
for d in stock_entry.get("mtn_details"):
|
||||||
if d.material_request:
|
if d.material_request:
|
||||||
material_request_map.setdefault(d.material_request, []).append(d.material_request_item)
|
material_request_map.setdefault(d.material_request, []).append(d.material_request_item)
|
||||||
|
|
||||||
for mr_name, mr_items in material_request_map.items():
|
for mr, mr_item_rows in material_request_map.items():
|
||||||
mr_obj = frappe.get_doc("Material Request", mr_name)
|
if mr and mr_item_rows:
|
||||||
|
mr_obj = frappe.get_doc("Material Request", mr)
|
||||||
|
|
||||||
if mr_obj.status in ["Stopped", "Cancelled"]:
|
if mr_obj.status in ["Stopped", "Cancelled"]:
|
||||||
frappe.throw(_("Material Request {0} is cancelled or stopped").format(mr_obj.name),
|
frappe.throw(_("Material Request {0} is cancelled or stopped").format(mr), frappe.InvalidStatusError)
|
||||||
frappe.InvalidStatusError)
|
|
||||||
|
|
||||||
_update_requested_qty(doc, mr_obj, mr_items)
|
mr_obj.update_completed_qty(mr_item_rows)
|
||||||
|
mr_obj.update_requested_qty(mr_item_rows)
|
||||||
# update ordered percentage and qty
|
|
||||||
mr_obj.update_completed_qty(mr_items)
|
|
||||||
|
|
||||||
def _update_requested_qty(doc, mr_obj, mr_items):
|
|
||||||
"""update requested qty (before ordered_qty is updated)"""
|
|
||||||
from erpnext.stock.utils import update_bin
|
|
||||||
for mr_item_name in mr_items:
|
|
||||||
mr_item = mr_obj.get("indent_details", {"name": mr_item_name})
|
|
||||||
se_detail = doc.get("mtn_details", {"material_request": mr_obj.name,
|
|
||||||
"material_request_item": mr_item_name})
|
|
||||||
|
|
||||||
if mr_item and se_detail:
|
|
||||||
mr_item = mr_item[0]
|
|
||||||
se_detail = se_detail[0]
|
|
||||||
mr_item.ordered_qty = flt(mr_item.ordered_qty)
|
|
||||||
mr_item.qty = flt(mr_item.qty)
|
|
||||||
se_detail.transfer_qty = flt(se_detail.transfer_qty)
|
|
||||||
|
|
||||||
if se_detail.docstatus == 2 and mr_item.ordered_qty > mr_item.qty \
|
|
||||||
and se_detail.transfer_qty == mr_item.ordered_qty:
|
|
||||||
add_indented_qty = mr_item.qty
|
|
||||||
elif se_detail.docstatus == 1 and \
|
|
||||||
mr_item.ordered_qty + se_detail.transfer_qty > mr_item.qty:
|
|
||||||
add_indented_qty = mr_item.qty - mr_item.ordered_qty
|
|
||||||
else:
|
|
||||||
add_indented_qty = se_detail.transfer_qty
|
|
||||||
|
|
||||||
update_bin({
|
|
||||||
"item_code": se_detail.item_code,
|
|
||||||
"warehouse": se_detail.t_warehouse,
|
|
||||||
"indented_qty": (se_detail.docstatus==2 and 1 or -1) * add_indented_qty,
|
|
||||||
"posting_date": doc.posting_date,
|
|
||||||
})
|
|
||||||
|
|
||||||
def set_missing_values(source, target_doc):
|
def set_missing_values(source, target_doc):
|
||||||
target_doc.run_method("set_missing_values")
|
target_doc.run_method("set_missing_values")
|
||||||
|
@ -58,12 +58,6 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
self.assertEquals(se.doctype, "Stock Entry")
|
self.assertEquals(se.doctype, "Stock Entry")
|
||||||
self.assertEquals(len(se.get("mtn_details")), len(mr.get("indent_details")))
|
self.assertEquals(len(se.get("mtn_details")), len(mr.get("indent_details")))
|
||||||
|
|
||||||
def _test_requested_qty(self, qty1, qty2):
|
|
||||||
self.assertEqual(flt(frappe.db.get_value("Bin", {"item_code": "_Test Item Home Desktop 100",
|
|
||||||
"warehouse": "_Test Warehouse - _TC"}, "indented_qty")), qty1)
|
|
||||||
self.assertEqual(flt(frappe.db.get_value("Bin", {"item_code": "_Test Item Home Desktop 200",
|
|
||||||
"warehouse": "_Test Warehouse - _TC"}, "indented_qty")), qty2)
|
|
||||||
|
|
||||||
def _insert_stock_entry(self, qty1, qty2):
|
def _insert_stock_entry(self, qty1, qty2):
|
||||||
se = frappe.get_doc({
|
se = frappe.get_doc({
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
@ -103,7 +97,8 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
se.submit()
|
se.submit()
|
||||||
|
|
||||||
def test_completed_qty_for_purchase(self):
|
def test_completed_qty_for_purchase(self):
|
||||||
frappe.db.sql("""delete from `tabBin`""")
|
existing_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
|
existing_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
# submit material request of type Purchase
|
# submit material request of type Purchase
|
||||||
mr = frappe.copy_doc(test_records[0])
|
mr = frappe.copy_doc(test_records[0])
|
||||||
@ -115,8 +110,6 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
self.assertEquals(mr.get("indent_details")[0].ordered_qty, 0)
|
self.assertEquals(mr.get("indent_details")[0].ordered_qty, 0)
|
||||||
self.assertEquals(mr.get("indent_details")[1].ordered_qty, 0)
|
self.assertEquals(mr.get("indent_details")[1].ordered_qty, 0)
|
||||||
|
|
||||||
self._test_requested_qty(54.0, 3.0)
|
|
||||||
|
|
||||||
# map a purchase order
|
# map a purchase order
|
||||||
from erpnext.stock.doctype.material_request.material_request import make_purchase_order
|
from erpnext.stock.doctype.material_request.material_request import make_purchase_order
|
||||||
po_doc = make_purchase_order(mr.name)
|
po_doc = make_purchase_order(mr.name)
|
||||||
@ -149,7 +142,12 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
self.assertEquals(mr.per_ordered, 50)
|
self.assertEquals(mr.per_ordered, 50)
|
||||||
self.assertEquals(mr.get("indent_details")[0].ordered_qty, 27.0)
|
self.assertEquals(mr.get("indent_details")[0].ordered_qty, 27.0)
|
||||||
self.assertEquals(mr.get("indent_details")[1].ordered_qty, 1.5)
|
self.assertEquals(mr.get("indent_details")[1].ordered_qty, 1.5)
|
||||||
self._test_requested_qty(27.0, 1.5)
|
|
||||||
|
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
|
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
|
self.assertEquals(current_requested_qty_item1, existing_requested_qty_item1 + 27.0)
|
||||||
|
self.assertEquals(current_requested_qty_item2, existing_requested_qty_item2 + 1.5)
|
||||||
|
|
||||||
po.cancel()
|
po.cancel()
|
||||||
# check if per complete is as expected
|
# check if per complete is as expected
|
||||||
@ -158,11 +156,15 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
self.assertEquals(mr.get("indent_details")[0].ordered_qty, None)
|
self.assertEquals(mr.get("indent_details")[0].ordered_qty, None)
|
||||||
self.assertEquals(mr.get("indent_details")[1].ordered_qty, None)
|
self.assertEquals(mr.get("indent_details")[1].ordered_qty, None)
|
||||||
|
|
||||||
self._test_requested_qty(54.0, 3.0)
|
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
|
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
|
self.assertEquals(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
|
||||||
|
self.assertEquals(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
|
||||||
|
|
||||||
def test_completed_qty_for_transfer(self):
|
def test_completed_qty_for_transfer(self):
|
||||||
frappe.db.sql("""delete from `tabBin`""")
|
existing_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
frappe.db.sql("""delete from `tabStock Ledger Entry`""")
|
existing_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
# submit material request of type Purchase
|
# submit material request of type Purchase
|
||||||
mr = frappe.copy_doc(test_records[0])
|
mr = frappe.copy_doc(test_records[0])
|
||||||
@ -175,7 +177,11 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
self.assertEquals(mr.get("indent_details")[0].ordered_qty, 0)
|
self.assertEquals(mr.get("indent_details")[0].ordered_qty, 0)
|
||||||
self.assertEquals(mr.get("indent_details")[1].ordered_qty, 0)
|
self.assertEquals(mr.get("indent_details")[1].ordered_qty, 0)
|
||||||
|
|
||||||
self._test_requested_qty(54.0, 3.0)
|
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
|
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
|
self.assertEquals(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
|
||||||
|
self.assertEquals(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
|
||||||
|
|
||||||
from erpnext.stock.doctype.material_request.material_request import make_stock_entry
|
from erpnext.stock.doctype.material_request.material_request import make_stock_entry
|
||||||
|
|
||||||
@ -226,7 +232,11 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
self.assertEquals(mr.get("indent_details")[0].ordered_qty, 27.0)
|
self.assertEquals(mr.get("indent_details")[0].ordered_qty, 27.0)
|
||||||
self.assertEquals(mr.get("indent_details")[1].ordered_qty, 1.5)
|
self.assertEquals(mr.get("indent_details")[1].ordered_qty, 1.5)
|
||||||
|
|
||||||
self._test_requested_qty(27.0, 1.5)
|
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
|
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
|
self.assertEquals(current_requested_qty_item1, existing_requested_qty_item1 + 27.0)
|
||||||
|
self.assertEquals(current_requested_qty_item2, existing_requested_qty_item2 + 1.5)
|
||||||
|
|
||||||
# check if per complete is as expected for Stock Entry cancelled
|
# check if per complete is as expected for Stock Entry cancelled
|
||||||
se.cancel()
|
se.cancel()
|
||||||
@ -235,11 +245,15 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
self.assertEquals(mr.get("indent_details")[0].ordered_qty, 0)
|
self.assertEquals(mr.get("indent_details")[0].ordered_qty, 0)
|
||||||
self.assertEquals(mr.get("indent_details")[1].ordered_qty, 0)
|
self.assertEquals(mr.get("indent_details")[1].ordered_qty, 0)
|
||||||
|
|
||||||
self._test_requested_qty(54.0, 3.0)
|
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
|
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
|
self.assertEquals(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
|
||||||
|
self.assertEquals(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
|
||||||
|
|
||||||
def test_completed_qty_for_over_transfer(self):
|
def test_completed_qty_for_over_transfer(self):
|
||||||
frappe.db.sql("""delete from `tabBin`""")
|
existing_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
frappe.db.sql("""delete from `tabStock Ledger Entry`""")
|
existing_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
# submit material request of type Purchase
|
# submit material request of type Purchase
|
||||||
mr = frappe.copy_doc(test_records[0])
|
mr = frappe.copy_doc(test_records[0])
|
||||||
@ -252,8 +266,6 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
self.assertEquals(mr.get("indent_details")[0].ordered_qty, 0)
|
self.assertEquals(mr.get("indent_details")[0].ordered_qty, 0)
|
||||||
self.assertEquals(mr.get("indent_details")[1].ordered_qty, 0)
|
self.assertEquals(mr.get("indent_details")[1].ordered_qty, 0)
|
||||||
|
|
||||||
self._test_requested_qty(54.0, 3.0)
|
|
||||||
|
|
||||||
# map a stock entry
|
# map a stock entry
|
||||||
from erpnext.stock.doctype.material_request.material_request import make_stock_entry
|
from erpnext.stock.doctype.material_request.material_request import make_stock_entry
|
||||||
|
|
||||||
@ -297,7 +309,12 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
self.assertEquals(mr.per_ordered, 100)
|
self.assertEquals(mr.per_ordered, 100)
|
||||||
self.assertEquals(mr.get("indent_details")[0].ordered_qty, 60.0)
|
self.assertEquals(mr.get("indent_details")[0].ordered_qty, 60.0)
|
||||||
self.assertEquals(mr.get("indent_details")[1].ordered_qty, 3.0)
|
self.assertEquals(mr.get("indent_details")[1].ordered_qty, 3.0)
|
||||||
self._test_requested_qty(0.0, 0.0)
|
|
||||||
|
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
|
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
|
self.assertEquals(current_requested_qty_item1, existing_requested_qty_item1)
|
||||||
|
self.assertEquals(current_requested_qty_item2, existing_requested_qty_item2)
|
||||||
|
|
||||||
# check if per complete is as expected for Stock Entry cancelled
|
# check if per complete is as expected for Stock Entry cancelled
|
||||||
se.cancel()
|
se.cancel()
|
||||||
@ -306,7 +323,11 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
self.assertEquals(mr.get("indent_details")[0].ordered_qty, 0)
|
self.assertEquals(mr.get("indent_details")[0].ordered_qty, 0)
|
||||||
self.assertEquals(mr.get("indent_details")[1].ordered_qty, 0)
|
self.assertEquals(mr.get("indent_details")[1].ordered_qty, 0)
|
||||||
|
|
||||||
self._test_requested_qty(54.0, 3.0)
|
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
|
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
|
self.assertEquals(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
|
||||||
|
self.assertEquals(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
|
||||||
|
|
||||||
def test_incorrect_mapping_of_stock_entry(self):
|
def test_incorrect_mapping_of_stock_entry(self):
|
||||||
# submit material request of type Purchase
|
# submit material request of type Purchase
|
||||||
@ -348,5 +369,9 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
mr.company = "_Test Company 1"
|
mr.company = "_Test Company 1"
|
||||||
self.assertRaises(InvalidWarehouseCompany, mr.insert)
|
self.assertRaises(InvalidWarehouseCompany, mr.insert)
|
||||||
|
|
||||||
|
def _get_requested_qty(self, item_code, warehouse):
|
||||||
|
return flt(frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}, "indented_qty"))
|
||||||
|
|
||||||
|
|
||||||
test_dependencies = ["Currency Exchange"]
|
test_dependencies = ["Currency Exchange"]
|
||||||
test_records = frappe.get_test_records('Material Request')
|
test_records = frappe.get_test_records('Material Request')
|
||||||
|
@ -8,7 +8,6 @@ from frappe.utils import cstr, flt, cint
|
|||||||
|
|
||||||
from frappe import _
|
from frappe import _
|
||||||
import frappe.defaults
|
import frappe.defaults
|
||||||
from erpnext.stock.utils import update_bin
|
|
||||||
|
|
||||||
from erpnext.controllers.buying_controller import BuyingController
|
from erpnext.controllers.buying_controller import BuyingController
|
||||||
|
|
||||||
@ -157,29 +156,19 @@ class PurchaseReceipt(BuyingController):
|
|||||||
self.make_sl_entries(sl_entries)
|
self.make_sl_entries(sl_entries)
|
||||||
|
|
||||||
def update_ordered_qty(self):
|
def update_ordered_qty(self):
|
||||||
stock_items = self.get_stock_items()
|
po_map = {}
|
||||||
for d in self.get("purchase_receipt_details"):
|
for d in self.get("purchase_receipt_details"):
|
||||||
if d.item_code in stock_items and d.warehouse \
|
if d.prevdoc_doctype and d.prevdoc_doctype == "Purchase Order" and d.prevdoc_detail_docname:
|
||||||
and cstr(d.prevdoc_doctype) == 'Purchase Order':
|
po_map.setdefault(d.prevdoc_docname, []).append(d.prevdoc_detail_docname)
|
||||||
|
|
||||||
already_received_qty = self.get_already_received_qty(d.prevdoc_docname,
|
for po, po_item_rows in po_map.items():
|
||||||
d.prevdoc_detail_docname)
|
if po and po_item_rows:
|
||||||
po_qty, ordered_warehouse = self.get_po_qty_and_warehouse(d.prevdoc_detail_docname)
|
po_obj = frappe.get_doc("Purchase Order", po)
|
||||||
|
|
||||||
if not ordered_warehouse:
|
if po_obj.status in ["Stopped", "Cancelled"]:
|
||||||
frappe.throw(_("Warehouse is missing in Purchase Order"))
|
frappe.throw(_("Material Request {0} is cancelled or stopped").format(po), frappe.InvalidStatusError)
|
||||||
|
|
||||||
if already_received_qty + d.qty > po_qty:
|
po_obj.update_ordered_qty(po_item_rows)
|
||||||
ordered_qty = - (po_qty - already_received_qty) * flt(d.conversion_factor)
|
|
||||||
else:
|
|
||||||
ordered_qty = - flt(d.qty) * flt(d.conversion_factor)
|
|
||||||
|
|
||||||
update_bin({
|
|
||||||
"item_code": d.item_code,
|
|
||||||
"warehouse": ordered_warehouse,
|
|
||||||
"posting_date": self.posting_date,
|
|
||||||
"ordered_qty": flt(ordered_qty) if self.docstatus==1 else -flt(ordered_qty)
|
|
||||||
})
|
|
||||||
|
|
||||||
def get_already_received_qty(self, po, po_detail):
|
def get_already_received_qty(self, po, po_detail):
|
||||||
qty = frappe.db.sql("""select sum(qty) from `tabPurchase Receipt Item`
|
qty = frappe.db.sql("""select sum(qty) from `tabPurchase Receipt Item`
|
||||||
@ -265,11 +254,13 @@ class PurchaseReceipt(BuyingController):
|
|||||||
|
|
||||||
frappe.db.set(self,'status','Cancelled')
|
frappe.db.set(self,'status','Cancelled')
|
||||||
|
|
||||||
self.update_ordered_qty()
|
|
||||||
|
|
||||||
self.update_stock_ledger()
|
self.update_stock_ledger()
|
||||||
|
|
||||||
self.update_prevdoc_status()
|
self.update_prevdoc_status()
|
||||||
|
|
||||||
|
# Must be called after updating received qty in PO
|
||||||
|
self.update_ordered_qty()
|
||||||
|
|
||||||
pc_obj.update_last_purchase_rate(self, 0)
|
pc_obj.update_last_purchase_rate(self, 0)
|
||||||
|
|
||||||
self.make_gl_entries_on_cancel()
|
self.make_gl_entries_on_cancel()
|
||||||
|
@ -1 +0,0 @@
|
|||||||
Average "age" of an Item in a particular Warehouse based on First-in-first-out (FIFO).
|
|
@ -1 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
@ -1,183 +0,0 @@
|
|||||||
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
|
||||||
// License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
|
|
||||||
frappe.pages['stock-ageing'].onload = function(wrapper) {
|
|
||||||
frappe.ui.make_app_page({
|
|
||||||
parent: wrapper,
|
|
||||||
title: __('Stock Ageing'),
|
|
||||||
single_column: true
|
|
||||||
});
|
|
||||||
|
|
||||||
new erpnext.StockAgeing(wrapper);
|
|
||||||
|
|
||||||
|
|
||||||
wrapper.appframe.add_module_icon("Stock")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
frappe.require("assets/erpnext/js/stock_grid_report.js");
|
|
||||||
|
|
||||||
erpnext.StockAgeing = erpnext.StockGridReport.extend({
|
|
||||||
init: function(wrapper) {
|
|
||||||
this._super({
|
|
||||||
title: __("Stock Ageing"),
|
|
||||||
page: wrapper,
|
|
||||||
parent: $(wrapper).find('.layout-main'),
|
|
||||||
appframe: wrapper.appframe,
|
|
||||||
doctypes: ["Item", "Warehouse", "Stock Ledger Entry", "Item Group", "Brand", "Serial No"],
|
|
||||||
})
|
|
||||||
},
|
|
||||||
setup_columns: function() {
|
|
||||||
this.columns = [
|
|
||||||
{id: "name", name: __("Item"), field: "name", width: 300,
|
|
||||||
link_formatter: {
|
|
||||||
open_btn: true,
|
|
||||||
doctype: '"Item"'
|
|
||||||
}},
|
|
||||||
{id: "item_name", name: __("Item Name"), field: "item_name",
|
|
||||||
width: 100, formatter: this.text_formatter},
|
|
||||||
{id: "description", name: __("Description"), field: "description",
|
|
||||||
width: 200, formatter: this.text_formatter},
|
|
||||||
{id: "brand", name: __("Brand"), field: "brand", width: 100},
|
|
||||||
{id: "average_age", name: __("Average Age"), field: "average_age",
|
|
||||||
formatter: this.currency_formatter},
|
|
||||||
{id: "earliest", name: __("Earliest"), field: "earliest",
|
|
||||||
formatter: this.currency_formatter},
|
|
||||||
{id: "latest", name: __("Latest"), field: "latest",
|
|
||||||
formatter: this.currency_formatter},
|
|
||||||
{id: "stock_uom", name: "UOM", field: "stock_uom", width: 100},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
filters: [
|
|
||||||
{fieldtype:"Select", label: __("Warehouse"), link:"Warehouse",
|
|
||||||
default_value: "Select Warehouse..."},
|
|
||||||
{fieldtype:"Select", label: __("Brand"), link:"Brand",
|
|
||||||
default_value: "Select Brand...", filter: function(val, item, opts) {
|
|
||||||
return val == opts.default_value || item.brand == val;
|
|
||||||
}, link_formatter: {filter_input: "brand"}},
|
|
||||||
{fieldtype:"Select", label: __("Plot By"),
|
|
||||||
options: ["Average Age", "Earliest", "Latest"]},
|
|
||||||
{fieldtype:"Date", label: __("To Date")},
|
|
||||||
{fieldtype:"Button", label: __("Refresh"), icon:"icon-refresh icon-white"},
|
|
||||||
{fieldtype:"Button", label: __("Reset Filters"), icon: "icon-filter"}
|
|
||||||
],
|
|
||||||
setup_filters: function() {
|
|
||||||
var me = this;
|
|
||||||
this._super();
|
|
||||||
this.trigger_refresh_on_change(["warehouse", "plot_by", "brand"]);
|
|
||||||
this.show_zero_check();
|
|
||||||
},
|
|
||||||
init_filter_values: function() {
|
|
||||||
this._super();
|
|
||||||
this.filter_inputs.to_date.val(dateutil.obj_to_user(new Date()));
|
|
||||||
},
|
|
||||||
prepare_data: function() {
|
|
||||||
var me = this;
|
|
||||||
|
|
||||||
if(!this.data) {
|
|
||||||
me._data = frappe.report_dump.data["Item"];
|
|
||||||
me.item_by_name = me.make_name_map(me._data);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.data = [].concat(this._data);
|
|
||||||
|
|
||||||
this.serialized_buying_rates = this.get_serialized_buying_rates();
|
|
||||||
|
|
||||||
$.each(this.data, function(i, d) {
|
|
||||||
me.reset_item_values(d);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.prepare_balances();
|
|
||||||
|
|
||||||
// filter out brand
|
|
||||||
this.data = $.map(this.data, function(d) {
|
|
||||||
return me.apply_filter(d, "brand") ? d : null;
|
|
||||||
});
|
|
||||||
|
|
||||||
// filter out rows with zero values
|
|
||||||
this.data = $.map(this.data, function(d) {
|
|
||||||
return me.apply_zero_filter(null, d, null, me) ? d : null;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
prepare_balances: function() {
|
|
||||||
var me = this;
|
|
||||||
var to_date = dateutil.str_to_obj(this.to_date);
|
|
||||||
var data = frappe.report_dump.data["Stock Ledger Entry"];
|
|
||||||
|
|
||||||
this.item_warehouse = {};
|
|
||||||
|
|
||||||
for(var i=0, j=data.length; i<j; i++) {
|
|
||||||
var sl = data[i];
|
|
||||||
var posting_date = dateutil.str_to_obj(sl.posting_date);
|
|
||||||
|
|
||||||
if(me.is_default("warehouse") ? true : me.warehouse == sl.warehouse) {
|
|
||||||
var wh = me.get_item_warehouse(sl.warehouse, sl.item_code);
|
|
||||||
|
|
||||||
// call diff to build fifo stack in item_warehouse
|
|
||||||
var diff = me.get_value_diff(wh, sl, true);
|
|
||||||
|
|
||||||
if(posting_date > to_date)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$.each(me.data, function(i, item) {
|
|
||||||
var full_fifo_stack = [];
|
|
||||||
if(me.is_default("warehouse")) {
|
|
||||||
$.each(me.item_warehouse[item.name] || {}, function(i, wh) {
|
|
||||||
full_fifo_stack = full_fifo_stack.concat(wh.fifo_stack || [])
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
full_fifo_stack = me.get_item_warehouse(me.warehouse, item.name).fifo_stack || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
var age_qty = total_qty = 0.0;
|
|
||||||
var min_age = max_age = null;
|
|
||||||
|
|
||||||
$.each(full_fifo_stack, function(i, batch) {
|
|
||||||
var batch_age = dateutil.get_diff(me.to_date, batch[2]);
|
|
||||||
age_qty += batch_age * batch[0];
|
|
||||||
total_qty += batch[0];
|
|
||||||
max_age = Math.max(max_age, batch_age);
|
|
||||||
if(min_age===null) min_age=batch_age;
|
|
||||||
else min_age = Math.min(min_age, batch_age);
|
|
||||||
});
|
|
||||||
|
|
||||||
item.average_age = total_qty.toFixed(2)==0.0 ? 0
|
|
||||||
: (age_qty / total_qty).toFixed(2);
|
|
||||||
item.earliest = max_age || 0.0;
|
|
||||||
item.latest = min_age || 0.0;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.data = this.data.sort(function(a, b) {
|
|
||||||
var sort_by = me.plot_by.replace(" ", "_").toLowerCase();
|
|
||||||
return b[sort_by] - a[sort_by];
|
|
||||||
});
|
|
||||||
},
|
|
||||||
get_plot_data: function() {
|
|
||||||
var data = [];
|
|
||||||
var me = this;
|
|
||||||
|
|
||||||
data.push({
|
|
||||||
label: me.plot_by,
|
|
||||||
data: $.map(me.data, function(item, idx) {
|
|
||||||
return [[idx+1, item[me.plot_by.replace(" ", "_").toLowerCase() ]]]
|
|
||||||
}),
|
|
||||||
bars: {show: true},
|
|
||||||
});
|
|
||||||
|
|
||||||
return data.length ? data : false;
|
|
||||||
},
|
|
||||||
get_plot_options: function() {
|
|
||||||
var me = this;
|
|
||||||
return {
|
|
||||||
grid: { hoverable: true, clickable: true },
|
|
||||||
xaxis: {
|
|
||||||
ticks: $.map(me.data, function(item, idx) { return [[idx+1, item.name]] }),
|
|
||||||
max: 15
|
|
||||||
},
|
|
||||||
series: { downsample: { threshold: 1000 } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"creation": "2012-09-21 20:15:14.000000",
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "Page",
|
|
||||||
"icon": "icon-table",
|
|
||||||
"idx": 1,
|
|
||||||
"modified": "2013-07-11 14:44:08.000000",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "Stock",
|
|
||||||
"name": "stock-ageing",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"page_name": "stock-ageing",
|
|
||||||
"roles": [
|
|
||||||
{
|
|
||||||
"role": "Analytics"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "Material Manager"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"standard": "Yes",
|
|
||||||
"title": "Stock Ageing"
|
|
||||||
}
|
|
@ -42,13 +42,12 @@ def get_columns():
|
|||||||
|
|
||||||
def get_fifo_queue(filters):
|
def get_fifo_queue(filters):
|
||||||
item_details = {}
|
item_details = {}
|
||||||
prev_qty = 0.0
|
|
||||||
for d in get_stock_ledger_entries(filters):
|
for d in get_stock_ledger_entries(filters):
|
||||||
item_details.setdefault(d.name, {"details": d, "fifo_queue": []})
|
item_details.setdefault(d.name, {"details": d, "fifo_queue": []})
|
||||||
fifo_queue = item_details[d.name]["fifo_queue"]
|
fifo_queue = item_details[d.name]["fifo_queue"]
|
||||||
|
|
||||||
if d.voucher_type == "Stock Reconciliation":
|
if d.voucher_type == "Stock Reconciliation":
|
||||||
d.actual_qty = flt(d.qty_after_transaction) - flt(prev_qty)
|
d.actual_qty = flt(d.qty_after_transaction) - flt(item_details[d.name].get("qty_after_transaction", 0))
|
||||||
|
|
||||||
if d.actual_qty > 0:
|
if d.actual_qty > 0:
|
||||||
fifo_queue.append([d.actual_qty, d.posting_date])
|
fifo_queue.append([d.actual_qty, d.posting_date])
|
||||||
@ -66,7 +65,7 @@ def get_fifo_queue(filters):
|
|||||||
batch[0] -= qty_to_pop
|
batch[0] -= qty_to_pop
|
||||||
qty_to_pop = 0
|
qty_to_pop = 0
|
||||||
|
|
||||||
prev_qty = d.qty_after_transaction
|
item_details[d.name]["qty_after_transaction"] = d.qty_after_transaction
|
||||||
|
|
||||||
return item_details
|
return item_details
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ def make_sl_entries(sl_entries, is_amended=None):
|
|||||||
if sle.get('is_cancelled') == 'Yes':
|
if sle.get('is_cancelled') == 'Yes':
|
||||||
sle['actual_qty'] = -flt(sle['actual_qty'])
|
sle['actual_qty'] = -flt(sle['actual_qty'])
|
||||||
|
|
||||||
if sle.get("actual_qty") or sle.voucher_type=="Stock Reconciliation":
|
if sle.get("actual_qty") or sle.get("voucher_type")=="Stock Reconciliation":
|
||||||
sle_id = make_entry(sle)
|
sle_id = make_entry(sle)
|
||||||
|
|
||||||
args = sle.copy()
|
args = sle.copy()
|
||||||
|
@ -119,7 +119,7 @@ def get_fifo_rate(previous_stock_queue, qty):
|
|||||||
"""get FIFO (average) Rate from Queue"""
|
"""get FIFO (average) Rate from Queue"""
|
||||||
if qty >= 0:
|
if qty >= 0:
|
||||||
total = sum(f[0] for f in previous_stock_queue)
|
total = sum(f[0] for f in previous_stock_queue)
|
||||||
return total and sum(f[0] * f[1] for f in previous_stock_queue) / flt(total) or 0.0
|
return sum(flt(f[0]) * flt(f[1]) for f in previous_stock_queue) / flt(total) if total else 0.0
|
||||||
else:
|
else:
|
||||||
available_qty_for_outgoing, outgoing_cost = 0, 0
|
available_qty_for_outgoing, outgoing_cost = 0, 0
|
||||||
qty_to_pop = abs(qty)
|
qty_to_pop = abs(qty)
|
||||||
|
@ -52,9 +52,14 @@ cur_frm.fields_dict['serial_no'].get_query = function(doc, cdt, cdn) {
|
|||||||
['Serial No', 'docstatus', '!=', 2],
|
['Serial No', 'docstatus', '!=', 2],
|
||||||
['Serial No', 'status', '=', "Delivered"]
|
['Serial No', 'status', '=', "Delivered"]
|
||||||
];
|
];
|
||||||
if(doc.item_code) cond = ['Serial No', 'item_code', '=', doc.item_code];
|
if(doc.item_code) {
|
||||||
if(doc.customer) cond = ['Serial No', 'customer', '=', doc.customer];
|
cond = ['Serial No', 'item_code', '=', doc.item_code];
|
||||||
filter.push(cond);
|
filter.push(cond);
|
||||||
|
}
|
||||||
|
if(doc.customer) {
|
||||||
|
cond = ['Serial No', 'customer', '=', doc.customer];
|
||||||
|
filter.push(cond);
|
||||||
|
}
|
||||||
return{
|
return{
|
||||||
filters:filter
|
filters:filter
|
||||||
}
|
}
|
||||||
@ -97,4 +102,4 @@ cur_frm.cscript.company = function(doc, cdt, cdn) {
|
|||||||
|
|
||||||
cur_frm.cscript.complaint_date = function(doc, cdt, cdn){
|
cur_frm.cscript.complaint_date = function(doc, cdt, cdn){
|
||||||
erpnext.get_fiscal_year(doc.company, doc.complaint_date);
|
erpnext.get_fiscal_year(doc.company, doc.complaint_date);
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,8 @@ class Address(Document):
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_address_display(address_dict):
|
def get_address_display(address_dict):
|
||||||
|
if not address_dict:
|
||||||
|
return
|
||||||
if not isinstance(address_dict, dict):
|
if not isinstance(address_dict, dict):
|
||||||
address_dict = frappe.db.get_value("Address", address_dict, "*", as_dict=True) or {}
|
address_dict = frappe.db.get_value("Address", address_dict, "*", as_dict=True) or {}
|
||||||
|
|
||||||
|
@ -93,11 +93,11 @@ def get_reserved_qty(item_code, warehouse):
|
|||||||
return flt(reserved_qty[0][0]) if reserved_qty else 0
|
return flt(reserved_qty[0][0]) if reserved_qty else 0
|
||||||
|
|
||||||
def get_indented_qty(item_code, warehouse):
|
def get_indented_qty(item_code, warehouse):
|
||||||
indented_qty = frappe.db.sql("""select sum(pr_item.qty - ifnull(pr_item.ordered_qty, 0))
|
indented_qty = frappe.db.sql("""select sum(mr_item.qty - ifnull(mr_item.ordered_qty, 0))
|
||||||
from `tabMaterial Request Item` pr_item, `tabMaterial Request` pr
|
from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
|
||||||
where pr_item.item_code=%s and pr_item.warehouse=%s
|
where mr_item.item_code=%s and mr_item.warehouse=%s
|
||||||
and pr_item.qty > ifnull(pr_item.ordered_qty, 0) and pr_item.parent=pr.name
|
and mr_item.qty > ifnull(mr_item.ordered_qty, 0) and mr_item.parent=mr.name
|
||||||
and pr.status!='Stopped' and pr.docstatus=1""", (item_code, warehouse))
|
and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
|
||||||
|
|
||||||
return flt(indented_qty[0][0]) if indented_qty else 0
|
return flt(indented_qty[0][0]) if indented_qty else 0
|
||||||
|
|
||||||
|
@ -2,5 +2,6 @@
|
|||||||
"db_name": "test_frappe",
|
"db_name": "test_frappe",
|
||||||
"db_password": "test_frappe",
|
"db_password": "test_frappe",
|
||||||
"admin_password": "admin",
|
"admin_password": "admin",
|
||||||
|
"host_name": "http://localhost:8888",
|
||||||
"mute_emails": 1
|
"mute_emails": 1
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user