Compare commits

..

30 Commits

Author SHA1 Message Date
Pratik Vyas
52e8c3d42b Merge branch 'v4.x.x' 2015-03-30 12:41:48 +05:30
Pratik Vyas
10224c9d86 bumped to version 4.24.3 2015-03-30 13:11:48 +06:00
Nabin Hait
abfe09b8ee Merge pull request #3017 from nabinhait/v4.x.x
Landed cost voucher: fixes for serialized item
2015-03-27 17:05:20 +05:30
Nabin Hait
54c865e77c Landed cost voucher: fixes for serialized item 2015-03-27 15:39:06 +05:30
Nabin Hait
712440c045 Merge pull request #3012 from nabinhait/v4.x.x
purchase order items to be billed report
2015-03-26 12:50:40 +05:30
Nabin Hait
7057970c0c purchase order items to be billed report 2015-03-26 11:05:13 +05:30
Pratik Vyas
c7402e2989 Merge branch 'v4.x.x' 2015-03-20 17:32:07 +05:30
Pratik Vyas
e07e5bbe00 bumped to version 4.24.2 2015-03-20 18:02:07 +06:00
Nabin Hait
04069bbc00 Merge pull request #2985 from nabinhait/v4.x.x
V4.x.x
2015-03-20 16:28:57 +05:30
Nabin Hait
63e00dcfd2 Set qty as per stock_uom while mapping Material request to Purchase order 2015-03-20 16:25:53 +05:30
Nabin Hait
2ed71bac20 Batch related cleanup 2015-03-20 15:06:30 +05:30
Nabin Hait
5601d9fbda match condition in get_query 2015-03-20 14:40:36 +05:30
Pratik Vyas
7b4b31fdf7 Merge branch 'develop' 2015-03-16 21:38:30 +05:30
Pratik Vyas
ec25117ab0 bumped to version 4.24.1 2015-03-16 22:08:30 +06:00
Nabin Hait
dfa013e73f Merge pull request #2962 from nabinhait/develop
manipulate_grand_total_for_inclusive_tax
2015-03-16 17:54:54 +05:30
Nabin Hait
f2791f8898 manipulate_grand_total_for_inclusive_tax 2015-03-16 17:01:09 +05:30
Nabin Hait
66773229a4 Merge pull request #2958 from anandpdoshi/anand-mar-13
manipulate grand total for inclusive tax
2015-03-16 15:58:23 +05:30
Anand Doshi
ead48094b6 manipulate diff only if diff <= 0.02 2015-03-13 18:59:01 +05:30
Anand Doshi
d6822ddd7c manipulate grand total for inclusive tax 2015-03-13 18:23:10 +05:30
Nabin Hait
4944fb33ce Merge pull request #2942 from sbktechnology/develop
Added Actual Batch Qty for item in DN & SI
2015-03-11 10:22:47 +05:30
Sambhaji Kolate
845f1c636e code cleanup 2015-03-10 15:19:29 +05:30
Sambhaji Kolate
98dbccd1d6 added actual_batch_qty at warehouse in DN & SI #1873 2015-03-10 15:04:28 +05:30
Pratik Vyas
7346ff3d08 Merge branch 'develop' 2015-03-10 10:41:35 +05:30
Pratik Vyas
21761c204c bumped to version 4.24.0 2015-03-10 11:11:35 +06:00
Nabin Hait
87f3ba139e Merge pull request #2936 from nabinhait/develop
Repost reserved qty and sle for sales invoice without warehouse
2015-03-09 18:50:46 +05:30
Nabin Hait
11498cac94 Repost sle for si without warehouse 2015-03-09 18:28:35 +05:30
Nabin Hait
7a31f6aaca repost reserved qty if negative 2015-03-09 16:31:11 +05:30
Nabin Hait
7d5a2390dd Merge pull request #2934 from nabinhait/develop
Pricing Rule Issue
2015-03-09 15:31:37 +05:30
Nabin Hait
081c3ec476 c-form message issue 2015-03-09 15:11:34 +05:30
Nabin Hait
e2f054cc27 transaction date issue in pricing rule fixed 2015-03-09 14:54:37 +05:30
26 changed files with 260 additions and 120 deletions

View File

@@ -1,2 +1,2 @@
from __future__ import unicode_literals
__version__ = '4.23.0'
__version__ = '4.24.3'

View File

@@ -18,17 +18,17 @@ class CForm(Document):
`tabSales Invoice` where name = %s and docstatus = 1""", d.invoice_no)
if inv and inv[0][0] != 'Yes':
frappe.throw("C-form is not applicable for Invoice: %s" % d.invoice_no)
frappe.throw("C-form is not applicable for Invoice: {0}".format(d.invoice_no))
elif inv and inv[0][1] and inv[0][1] != self.name:
frappe.throw("""Invoice %s is tagged in another C-form: %s.
frappe.throw("""Invoice {0} is tagged in another C-form: {1}.
If you want to change C-form no for this invoice,
please remove invoice no from the previous c-form and then try again""" %
(d.invoice_no, inv[0][1]))
please remove invoice no from the previous c-form and then try again"""\
.format(d.invoice_no, inv[0][1]))
elif not inv:
frappe.throw("Row %s: Invoice %s is invalid, it might be cancelled / does not exist. \
Please enter a valid Invoice" % d.idx, d.invoice_no)
frappe.throw("Row {0}: Invoice {1} is invalid, it might be cancelled / does not exist. \
Please enter a valid Invoice".format(d.idx, d.invoice_no))
def on_update(self):
""" Update C-Form No on invoices"""

View File

@@ -244,7 +244,7 @@ cur_frm.cscript.hide_fields = function(doc) {
cur_frm.fields_dict['entries'].grid.set_column_disp(item_flds_normal, true);
}
item_flds_stock = ['serial_no', 'batch_no', 'actual_qty', 'expense_account', 'warehouse']
item_flds_stock = ['serial_no', 'batch_no', 'actual_qty', 'actual_batch_qty', 'expense_account', 'warehouse']
cur_frm.fields_dict['entries'].grid.set_column_disp(item_flds_stock,
(cint(doc.update_stock)==1 ? true : false));

View File

@@ -339,6 +339,19 @@
"fieldtype": "Column Break",
"permlevel": 0
},
{
"allow_on_submit": 1,
"fieldname": "actual_batch_qty",
"fieldtype": "Float",
"label": "Available Batch Qty at Warehouse",
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_width": "150px",
"read_only": 1,
"width": "150px"
},
{
"allow_on_submit": 1,
"fieldname": "actual_qty",
@@ -439,7 +452,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2014-09-09 05:35:36.019576",
"modified": "2015-03-10 14:56:45.641026",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",

View File

@@ -6,12 +6,12 @@
"doctype": "Report",
"idx": 1,
"is_standard": "Yes",
"modified": "2014-06-03 07:18:17.244501",
"modified": "2015-03-26 11:00:48.720037",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Order Items To Be Billed",
"owner": "Administrator",
"query": "select \n `tabPurchase Order`.`name` as \"Purchase Order:Link/Purchase Order:120\",\n `tabPurchase Order`.`transaction_date` as \"Date:Date:100\",\n\t`tabPurchase Order`.`supplier` as \"Supplier:Link/Supplier:120\",\n\t`tabPurchase Order Item`.`project_name` as \"Project\",\n\t`tabPurchase Order Item`.item_code as \"Item Code:Link/Item:120\",\n\t`tabPurchase Order Item`.base_amount as \"Amount:Currency:100\",\n\t`tabPurchase Order Item`.billed_amt as \"Billed Amount:Currency:100\", \n\t(`tabPurchase Order Item`.base_amount - ifnull(`tabPurchase Order Item`.billed_amt, 0)) as \"Amount to Bill:Currency:100\",\n\t`tabPurchase Order Item`.item_name as \"Item Name::150\",\n\t`tabPurchase Order Item`.description as \"Description::200\"\nfrom\n\t`tabPurchase Order`, `tabPurchase Order Item`\nwhere\n\t`tabPurchase Order Item`.`parent` = `tabPurchase Order`.`name`\n\tand `tabPurchase Order`.docstatus = 1\n\tand `tabPurchase Order`.status != \"Stopped\"\n\tand ifnull(`tabPurchase Order Item`.billed_amt, 0) < ifnull(`tabPurchase Order Item`.base_amount, 0)\norder by `tabPurchase Order`.transaction_date asc",
"query": "select \n `tabPurchase Order`.`name` as \"Purchase Order:Link/Purchase Order:120\",\n `tabPurchase Order`.`transaction_date` as \"Date:Date:100\",\n\t`tabPurchase Order`.`supplier` as \"Supplier:Link/Supplier:120\",\n\t`tabPurchase Order Item`.`project_name` as \"Project\",\n\t`tabPurchase Order Item`.item_code as \"Item Code:Link/Item:120\",\n\t`tabPurchase Order Item`.base_amount as \"Amount:Currency:100\",\n\t(`tabPurchase Order Item`.billed_amt * ifnull(`tabPurchase Order`.conversion_rate, 1)) as \"Billed Amount:Currency:100\", \n\t(`tabPurchase Order Item`.base_amount - (ifnull(`tabPurchase Order Item`.billed_amt, 0) * ifnull(`tabPurchase Order`.conversion_rate, 1))) as \"Amount to Bill:Currency:100\",\n\t`tabPurchase Order Item`.item_name as \"Item Name::150\",\n\t`tabPurchase Order Item`.description as \"Description::200\"\nfrom\n\t`tabPurchase Order`, `tabPurchase Order Item`\nwhere\n\t`tabPurchase Order Item`.`parent` = `tabPurchase Order`.`name`\n\tand `tabPurchase Order`.docstatus = 1\n\tand `tabPurchase Order`.status != \"Stopped\"\n\tand (ifnull(`tabPurchase Order Item`.billed_amt, 0) * ifnull(`tabPurchase Order`.conversion_rate, 1)) < ifnull(`tabPurchase Order Item`.base_amount, 0)\norder by `tabPurchase Order`.transaction_date asc",
"ref_doctype": "Purchase Invoice",
"report_name": "Purchase Order Items To Be Billed",
"report_type": "Query Report"

View File

@@ -112,6 +112,8 @@ class AccountsController(TransactionBase):
if item.get("item_code"):
args = parent_dict.copy()
args.update(item.as_dict())
if not args.get("transaction_date"):
args["transaction_date"] = args.get("posting_date")
ret = get_item_details(args)
for fieldname, value in ret.items():
@@ -183,6 +185,7 @@ class AccountsController(TransactionBase):
self.calculate_net_total()
self.calculate_taxes()
self.manipulate_grand_total_for_inclusive_tax()
self.calculate_totals()
self._cleanup()
@@ -351,6 +354,22 @@ class AccountsController(TransactionBase):
self.precision(base_field, item))
item.set(base_field, value_in_company_currency)
def manipulate_grand_total_for_inclusive_tax(self):
# if fully inclusive taxes and diff
if (self.meta.get_field("net_total_export") and self.tax_doclist
and all(cint(t.included_in_print_rate) for t in self.tax_doclist)):
last_tax = self.tax_doclist[-1]
diff = self.net_total_export - flt(last_tax.total / self.conversion_rate,
self.precision("grand_total_export"))
if diff and abs(diff) <= (2.0 / 10**(self.precision("tax_amount", last_tax))):
adjustment_amount = flt(diff * self.conversion_rate, self.precision("tax_amount", last_tax))
last_tax.tax_amount += adjustment_amount
last_tax.tax_amount_after_discount_amount += adjustment_amount
last_tax.total += adjustment_amount
def calculate_total_advance(self, parenttype, advance_parentfield):
if self.doctype == parenttype and self.docstatus < 2:
sum_of_allocated_amount = sum([flt(adv.allocated_amount, self.precision("allocated_amount", adv))

View File

@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe.widgets.reportview import get_match_cond
from frappe.model.db_query import DatabaseQuery
from frappe.utils import nowdate
def get_filters_cond(doctype, filters, conditions):
if filters:
@@ -154,8 +155,6 @@ def tax_account_query(doctype, txt, searchfield, start, page_len, filters):
return tax_accounts
def item_query(doctype, txt, searchfield, start, page_len, filters):
from frappe.utils import nowdate
conditions = []
return frappe.db.sql("""select tabItem.name,
@@ -229,36 +228,48 @@ def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len,
}, { "start": start, "page_len": page_len, "txt": ("%%%s%%" % txt) })
def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
from erpnext.controllers.queries import get_match_cond
if not filters.get("posting_date"):
filters["posting_date"] = nowdate()
if filters.has_key('warehouse'):
return frappe.db.sql("""select batch_no from `tabStock Ledger Entry` sle
where item_code = '%(item_code)s'
and warehouse = '%(warehouse)s'
and batch_no like '%(txt)s'
and exists(select * from `tabBatch`
where name = sle.batch_no
and (ifnull(expiry_date, '')='' or expiry_date >= '%(posting_date)s')
and docstatus != 2)
%(mcond)s
group by batch_no having sum(actual_qty) > 0
order by batch_no desc
limit %(start)s, %(page_len)s """ % {'item_code': filters['item_code'],
'warehouse': filters['warehouse'], 'posting_date': filters['posting_date'],
'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype),
'start': start, 'page_len': page_len})
batch_nos = None
args = {
'item_code': filters.get("item_code"),
'warehouse': filters.get("warehouse"),
'posting_date': filters.get('posting_date'),
'txt': "%%%s%%" % txt,
'mcond':get_match_cond(doctype),
"start": start,
"page_len": page_len
}
if args.get("warehouse"):
batch_nos = frappe.db.sql("""select sle.batch_no
from `tabStock Ledger Entry` sle, `tabBatch`
where sle.batch_no = `tabBatch`.name
and sle.item_code = '%(item_code)s'
and sle.warehouse = '%(warehouse)s'
and sle.batch_no like '%(txt)s'
and (ifnull(`tabBatch`.expiry_date, '2099-12-31') >= %(posting_date)s
or `tabBatch`.expiry_date = '')
and `tabBatch`.docstatus != 2
%(mcond)s
group by batch_no having sum(actual_qty) > 0
order by batch_no desc
limit %(start)s, %(page_len)s """
% args)
if batch_nos:
return batch_nos
else:
return frappe.db.sql("""select name from tabBatch
where docstatus != 2
and item = '%(item_code)s'
and (ifnull(expiry_date, '')='' or expiry_date >= '%(posting_date)s')
and name like '%(txt)s'
%(mcond)s
order by name desc
limit %(start)s, %(page_len)s""" % {'item_code': filters['item_code'],
'posting_date': filters['posting_date'], 'txt': "%%%s%%" % txt,
'mcond':get_match_cond(doctype),'start': start,
'page_len': page_len})
return frappe.db.sql("""select name from `tabBatch`
where item = '%(item_code)s'
and docstatus < 2
and (ifnull(expiry_date, '2099-12-31') >= %(posting_date)s
or expiry_date = '' or expiry_date = "0000-00-00")
%(mcond)s
order by name desc
limit %(start)s, %(page_len)s
""" % args)
def get_account_list(doctype, txt, searchfield, start, page_len, filters):
filter_list = []

View File

@@ -197,9 +197,10 @@ class StockController(AccountsController):
sl_dict.update(args)
return sl_dict
def make_sl_entries(self, sl_entries, is_amended=None, allow_negative_stock=False):
def make_sl_entries(self, sl_entries, is_amended=None, allow_negative_stock=False,
via_landed_cost_voucher=False):
from erpnext.stock.stock_ledger import make_sl_entries
make_sl_entries(sl_entries, is_amended, allow_negative_stock)
make_sl_entries(sl_entries, is_amended, allow_negative_stock, via_landed_cost_voucher)
def make_gl_entries_on_cancel(self):
if frappe.db.sql("""select name from `tabGL Entry` where voucher_type=%s

View File

@@ -5,7 +5,7 @@ app_publisher = "Web Notes Technologies Pvt. Ltd. and Contributors"
app_description = "Open Source Enterprise Resource Planning for Small and Midsized Organizations"
app_icon = "icon-th"
app_color = "#e74c3c"
app_version = "4.23.0"
app_version = "4.24.3"
error_report_email = "support@erpnext.com"

View File

@@ -94,3 +94,5 @@ erpnext.patches.v4_2.discount_amount
erpnext.patches.v4_2.update_landed_cost_voucher
erpnext.patches.v4_2.set_item_has_batch
erpnext.patches.v4_2.update_stock_uom_for_dn_in_sle
erpnext.patches.v4_2.repost_reserved_qty
erpnext.patches.v4_2.repost_sle_for_si_with_no_warehouse

View File

@@ -0,0 +1,12 @@
# 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
from erpnext.utilities.repost_stock import update_bin_qty, get_reserved_qty
def execute():
for item_code, warehouse in frappe.db.sql("select item_code, warehouse from tabBin where ifnull(reserved_qty, 0) < 0"):
update_bin_qty(item_code, warehouse, {
"reserved_qty": get_reserved_qty(item_code, warehouse)
})

View File

@@ -0,0 +1,34 @@
# 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
from erpnext.stock.stock_ledger import NegativeStockError
def execute():
si_list = frappe.db.sql("""select distinct si.name
from `tabSales Invoice Item` si_item, `tabSales Invoice` si
where si.name = si_item.parent and si.modified > '2015-02-16' and si.docstatus=1
and ifnull(si_item.warehouse, '') = '' and ifnull(si.update_stock, 0) = 1
order by posting_date, posting_time""", as_dict=1)
failed_list = []
for si in si_list:
try:
si_doc = frappe.get_doc("Sales Invoice", si.name)
si_doc.docstatus = 2
si_doc.on_cancel()
si_doc.docstatus = 1
si_doc.set_missing_item_details()
si_doc.on_submit()
frappe.db.commit()
except:
failed_list.append(si.name)
frappe.local.stockledger_exceptions = None
frappe.db.rollback()
print "Failed to repost: ", failed_list

View File

@@ -148,7 +148,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
order_type: me.frm.doc.order_type,
is_pos: cint(me.frm.doc.is_pos),
is_subcontracted: me.frm.doc.is_subcontracted,
transaction_date: me.frm.doc.transaction_date,
transaction_date: me.frm.doc.transaction_date || me.frm.doc.posting_date,
ignore_pricing_rule: me.frm.doc.ignore_pricing_rule,
doctype: item.doctype,
name: item.name,
@@ -632,6 +632,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
this.determine_exclusive_rate && this.determine_exclusive_rate();
this.calculate_net_total();
this.calculate_taxes();
this.manipulate_grand_total_for_inclusive_tax && this.manipulate_grand_total_for_inclusive_tax();
this.calculate_totals();
this._cleanup();

View File

@@ -215,6 +215,8 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
},
warehouse: function(doc, cdt, cdn) {
var me = this;
this.batch_no(doc, cdt, cdn);
var item = frappe.get_doc(cdt, cdn);
if(item.item_code && item.warehouse) {
return this.frm.call({
@@ -456,6 +458,29 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
});
},
manipulate_grand_total_for_inclusive_tax: function() {
// if fully inclusive taxes and diff
if (this.frm.tax_doclist.length) {
var all_inclusive = frappe.utils.all(this.frm.tax_doclist.map(function(d) {
return cint(d.included_in_print_rate);
}));
if (all_inclusive) {
var last_tax = this.frm.tax_doclist.slice(-1)[0];
var diff = this.frm.doc.net_total_export
- flt(last_tax.total / this.frm.doc.conversion_rate, precision("grand_total_export"));
if ( diff && Math.abs(diff) <= (2.0 / Math.pow(10, precision("tax_amount", last_tax))) ) {
var adjustment_amount = flt(diff * this.frm.doc.conversion_rate, precision("tax_amount", last_tax));
last_tax.tax_amount += adjustment_amount;
last_tax.tax_amount_after_discount += adjustment_amount;
last_tax.total += adjustment_amount;
}
}
}
},
_cleanup: function() {
this._super();
this.frm.doc.in_words = this.frm.doc.in_words_export = "";
@@ -475,6 +500,24 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
})
}
},
batch_no: function(doc, cdt, cdn) {
var me = this;
var item = frappe.get_doc(cdt, cdn);
if(doc.warehouse && doc.item_code && doc.batch_no) {
return this.frm.call({
method: "erpnext.stock.get_item_details.get_batch_qty",
child: item,
args: {
"batch_no": item.batch_no,
"warehouse": item.warehouse,
"item_code": item.item_code
},
"fieldname": "actual_batch_qty"
});
}
},
set_dynamic_labels: function() {
this._super();

View File

@@ -23,7 +23,7 @@ class Bin(Document):
if (not getattr(self, f, None)) or (not self.get(f)):
self.set(f, 0.0)
def update_stock(self, args, allow_negative_stock=False):
def update_stock(self, args, allow_negative_stock=False, via_landed_cost_voucher=False):
self.update_qty(args)
if args.get("actual_qty") or args.get("voucher_type") == "Stock Reconciliation":
@@ -38,7 +38,7 @@ class Bin(Document):
"warehouse": self.warehouse,
"posting_date": args.get("posting_date"),
"posting_time": args.get("posting_time")
}, allow_negative_stock=allow_negative_stock)
}, allow_negative_stock=allow_negative_stock, via_landed_cost_voucher=via_landed_cost_voucher)
def update_qty(self, args):
# update the stock values (for current quantities)

View File

@@ -314,6 +314,19 @@
"fieldtype": "Column Break",
"permlevel": 0
},
{
"allow_on_submit": 1,
"fieldname": "actual_batch_qty",
"fieldtype": "Float",
"label": "Available Batch Qty at Warehouse",
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_width": "150px",
"read_only": 1,
"width": "150px"
},
{
"allow_on_submit": 1,
"fieldname": "actual_qty",
@@ -426,7 +439,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2014-09-09 05:35:37.460939",
"modified": "2015-03-10 12:21:17.028911",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note Item",

View File

@@ -6,6 +6,7 @@ import frappe
from frappe import _
from frappe.utils import flt
from frappe.model.document import Document
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
class LandedCostVoucher(Document):
def get_items_from_purchase_receipts(self):
@@ -92,13 +93,25 @@ class LandedCostVoucher(Document):
# save will update landed_cost_voucher_amount and voucher_amount in PR,
# as those fields are allowed to edit after submit
pr.save()
# update latest valuation rate in serial no
self.update_rate_in_serial_no(pr)
# update stock & gl entries for cancelled state of PR
pr.docstatus = 2
pr.update_stock_ledger(allow_negative_stock=True)
pr.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True)
pr.make_gl_entries_on_cancel()
# update stock & gl entries for submit state of PR
pr.docstatus = 1
pr.update_stock_ledger()
pr.update_stock_ledger(via_landed_cost_voucher=True)
pr.make_gl_entries()
def update_rate_in_serial_no(self, purchase_receipt):
for item in purchase_receipt.get("purchase_receipt_details"):
if item.serial_no:
serial_nos = get_serial_nos(item.serial_no)
if serial_nos:
frappe.db.sql("update `tabSerial No` set purchase_rate=%s where name in ({0})"
.format(", ".join(["%s"]*len(serial_nos))), tuple([item.valuation_rate] + serial_nos))

View File

@@ -185,6 +185,7 @@ def set_missing_values(source, target_doc):
def update_item(obj, target, source_parent):
target.conversion_factor = 1
target.qty = flt(obj.qty) - flt(obj.ordered_qty)
target.stock_qty = target.qty
@frappe.whitelist()
def make_purchase_order(source_name, target_doc=None):

View File

@@ -129,7 +129,7 @@ class PurchaseReceipt(BuyingController):
if not d.prevdoc_docname:
frappe.throw(_("Purchase Order number required for Item {0}").format(d.item_code))
def update_stock_ledger(self, allow_negative_stock=False):
def update_stock_ledger(self, allow_negative_stock=False, via_landed_cost_voucher=False):
sl_entries = []
stock_items = self.get_stock_items()
@@ -154,7 +154,8 @@ class PurchaseReceipt(BuyingController):
}))
self.bk_flush_supp_wh(sl_entries)
self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock)
self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock,
via_landed_cost_voucher=via_landed_cost_voucher)
def update_ordered_qty(self):
po_map = {}

View File

@@ -378,18 +378,20 @@ cur_frm.cscript.purpose = function(doc, cdt, cdn) {
// Overloaded query for link batch_no
cur_frm.fields_dict['mtn_details'].grid.get_field('batch_no').get_query = function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
if(d.item_code) {
return{
query: "erpnext.stock.doctype.stock_entry.stock_entry.get_batch_no",
filters:{
'item_code': d.item_code,
's_warehouse': d.s_warehouse,
'posting_date': doc.posting_date
}
}
var item = locals[cdt][cdn];
if(!item.item_code) {
frappe.throw(__("Please enter Item Code to get batch nos"));
} else {
msgprint(__("Please enter Item Code to get batch no"));
filters = {
'item_code': item.item_code,
'posting_date': me.frm.doc.posting_date,
}
if(item.s_warehouse) filters["warehouse"] = item.s_warehouse
return {
query : "erpnext.controllers.queries.get_batch_no",
filters: filters
}
}
}

View File

@@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
import frappe.defaults
from frappe.utils import cstr, cint, flt, comma_or, nowdate
from frappe.utils import cstr, cint, flt, comma_or
from frappe import _
from erpnext.stock.utils import get_incoming_rate
@@ -680,51 +680,6 @@ def query_return_item(doctype, txt, searchfield, start, page_len, filters):
return result[start:start+page_len]
def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
if not filters.get("posting_date"):
filters["posting_date"] = nowdate()
batch_nos = None
args = {
'item_code': filters.get("item_code"),
's_warehouse': filters.get('s_warehouse'),
'posting_date': filters.get('posting_date'),
'txt': "%%%s%%" % txt,
'mcond':get_match_cond(doctype),
"start": start,
"page_len": page_len
}
if filters.get("s_warehouse"):
batch_nos = frappe.db.sql("""select batch_no
from `tabStock Ledger Entry` sle
where item_code = '%(item_code)s'
and warehouse = '%(s_warehouse)s'
and batch_no like '%(txt)s'
and exists(select * from `tabBatch`
where name = sle.batch_no
and (ifnull(expiry_date, '2099-12-31') >= %(posting_date)s
or expiry_date = '')
and docstatus != 2)
%(mcond)s
group by batch_no having sum(actual_qty) > 0
order by batch_no desc
limit %(start)s, %(page_len)s """
% args)
if batch_nos:
return batch_nos
else:
return frappe.db.sql("""select name from `tabBatch`
where item = '%(item_code)s'
and docstatus < 2
and (ifnull(expiry_date, '2099-12-31') >= %(posting_date)s
or expiry_date = '' or expiry_date = "0000-00-00")
%(mcond)s
order by name desc
limit %(start)s, %(page_len)s
""" % args)
def get_stock_items_for_return(ref_doc, parentfields):
"""return item codes filtered from doc, which are stock items"""
if isinstance(parentfields, basestring):

View File

@@ -27,8 +27,9 @@ class StockLedgerEntry(Document):
self.check_stock_frozen_date()
self.actual_amt_check()
from erpnext.stock.doctype.serial_no.serial_no import process_serial_no
process_serial_no(self)
if not self.get("via_landed_cost_voucher"):
from erpnext.stock.doctype.serial_no.serial_no import process_serial_no
process_serial_no(self)
#check for item quantity available in stock
def actual_amt_check(self):

View File

@@ -278,6 +278,15 @@ def get_serial_nos_by_fifo(args, item_doc):
"qty": cint(args.qty)
}))
def get_actual_batch_qty(batch_no,warehouse,item_code):
actual_batch_qty = 0
if batch_no:
actual_batch_qty = flt(frappe.db.sql("""select sum(actual_qty)
from `tabStock Ledger Entry`
where warehouse=%s and item_code=%s and batch_no=%s""",
(warehouse, item_code, batch_no))[0][0])
return actual_batch_qty
@frappe.whitelist()
def get_conversion_factor(item_code, uom):
return {"conversion_factor": frappe.db.get_value("UOM Conversion Detail",
@@ -293,6 +302,12 @@ def get_available_qty(item_code, warehouse):
return frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse},
["projected_qty", "actual_qty"], as_dict=True) or {}
@frappe.whitelist()
def get_batch_qty(batch_no,warehouse,item_code):
actual_batch_qty = get_actual_batch_qty(batch_no,warehouse,item_code)
if batch_no:
return {'actual_batch_qty': actual_batch_qty}
@frappe.whitelist()
def apply_price_list(args):
"""

View File

@@ -14,7 +14,7 @@ class NegativeStockError(frappe.ValidationError): pass
_exceptions = frappe.local('stockledger_exceptions')
# _exceptions = []
def make_sl_entries(sl_entries, is_amended=None, allow_negative_stock=False):
def make_sl_entries(sl_entries, is_amended=None, allow_negative_stock=False, via_landed_cost_voucher=False):
if sl_entries:
from erpnext.stock.utils import update_bin
@@ -28,14 +28,14 @@ def make_sl_entries(sl_entries, is_amended=None, allow_negative_stock=False):
sle['actual_qty'] = -flt(sle['actual_qty'])
if sle.get("actual_qty") or sle.get("voucher_type")=="Stock Reconciliation":
sle_id = make_entry(sle, allow_negative_stock)
sle_id = make_entry(sle, allow_negative_stock, via_landed_cost_voucher)
args = sle.copy()
args.update({
"sle_id": sle_id,
"is_amended": is_amended
})
update_bin(args, allow_negative_stock)
update_bin(args, allow_negative_stock, via_landed_cost_voucher)
if cancel:
delete_cancelled_entry(sl_entries[0].get('voucher_type'), sl_entries[0].get('voucher_no'))
@@ -46,11 +46,12 @@ def set_as_cancel(voucher_type, voucher_no):
where voucher_no=%s and voucher_type=%s""",
(now(), frappe.session.user, voucher_type, voucher_no))
def make_entry(args, allow_negative_stock=False):
def make_entry(args, allow_negative_stock=False, via_landed_cost_voucher=False):
args.update({"doctype": "Stock Ledger Entry"})
sle = frappe.get_doc(args)
sle.ignore_permissions = 1
sle.allow_negative_stock=allow_negative_stock
sle.via_landed_cost_voucher = via_landed_cost_voucher
sle.insert()
sle.submit()
return sle.name
@@ -59,7 +60,9 @@ def delete_cancelled_entry(voucher_type, voucher_no):
frappe.db.sql("""delete from `tabStock Ledger Entry`
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
def update_entries_after(args, allow_zero_rate=False, allow_negative_stock=False, verbose=1):
def update_entries_after(args, allow_zero_rate=False, allow_negative_stock=False,
via_landed_cost_voucher=False, verbose=1):
"""
update valution rate and qty after transaction
from the current time-bucket onwards
@@ -91,7 +94,7 @@ def update_entries_after(args, allow_zero_rate=False, allow_negative_stock=False
stock_value_difference = 0.0
for sle in entries_to_fix:
if sle.serial_no or not allow_negative_stock:
if (sle.serial_no and not via_landed_cost_voucher) or not allow_negative_stock:
# validate negative stock for serialized items, fifo valuation
# or when negative stock is not allowed for moving average
if not validate_negative_stock(qty_after_transaction, sle):

View File

@@ -53,11 +53,11 @@ def get_bin(item_code, warehouse):
bin_obj.ignore_permissions = True
return bin_obj
def update_bin(args, allow_negative_stock=False):
def update_bin(args, allow_negative_stock=False, via_landed_cost_voucher=False):
is_stock_item = frappe.db.get_value('Item', args.get("item_code"), 'is_stock_item')
if is_stock_item == 'Yes':
bin = get_bin(args.get("item_code"), args.get("warehouse"))
bin.update_stock(args, allow_negative_stock)
bin.update_stock(args, allow_negative_stock, via_landed_cost_voucher)
return bin
else:
frappe.msgprint(_("Item {0} ignored since it is not a stock item").format(args.get("item_code")))

View File

@@ -1,7 +1,7 @@
from setuptools import setup, find_packages
import os
version = "4.23.0"
version = "4.24.3"
with open("requirements.txt", "r") as f:
install_requires = f.readlines()