Merge branch 'develop'
@ -2,7 +2,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
|
|
||||||
__version__ = '8.0.3'
|
__version__ = '8.0.4'
|
||||||
|
|
||||||
def get_default_company(user=None):
|
def get_default_company(user=None):
|
||||||
'''Get default company for user'''
|
'''Get default company for user'''
|
||||||
@ -25,6 +25,14 @@ def get_default_currency():
|
|||||||
if company:
|
if company:
|
||||||
return frappe.db.get_value('Company', company, 'default_currency')
|
return frappe.db.get_value('Company', company, 'default_currency')
|
||||||
|
|
||||||
|
def get_company_currency(company):
|
||||||
|
'''Returns the default company currency'''
|
||||||
|
if not frappe.flags.company_currency:
|
||||||
|
frappe.flags.company_currency = {}
|
||||||
|
if not company in frappe.flags.company_currency:
|
||||||
|
frappe.flags.company_currency[company] = frappe.db.get_value('Company', company, 'default_currency')
|
||||||
|
return frappe.flags.company_currency[company]
|
||||||
|
|
||||||
def set_perpetual_inventory(enable=1):
|
def set_perpetual_inventory(enable=1):
|
||||||
accounts_settings = frappe.get_doc("Accounts Settings")
|
accounts_settings = frappe.get_doc("Accounts Settings")
|
||||||
accounts_settings.auto_accounting_for_stock = enable
|
accounts_settings.auto_accounting_for_stock = enable
|
||||||
|
@ -2,13 +2,12 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe, erpnext
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import flt, fmt_money, getdate, formatdate
|
from frappe.utils import flt, fmt_money, getdate, formatdate
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from erpnext.accounts.party import validate_party_gle_currency, validate_party_frozen_disabled
|
from erpnext.accounts.party import validate_party_gle_currency, validate_party_frozen_disabled
|
||||||
from erpnext.accounts.utils import get_account_currency
|
from erpnext.accounts.utils import get_account_currency
|
||||||
from erpnext.setup.doctype.company.company import get_company_currency
|
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
from erpnext.exceptions import InvalidAccountCurrency
|
from erpnext.exceptions import InvalidAccountCurrency
|
||||||
|
|
||||||
@ -116,7 +115,7 @@ class GLEntry(Document):
|
|||||||
validate_party_frozen_disabled(self.party_type, self.party)
|
validate_party_frozen_disabled(self.party_type, self.party)
|
||||||
|
|
||||||
def validate_currency(self):
|
def validate_currency(self):
|
||||||
company_currency = get_company_currency(self.company)
|
company_currency = erpnext.get_company_currency(self.company)
|
||||||
account_currency = get_account_currency(self.account)
|
account_currency = get_account_currency(self.account)
|
||||||
|
|
||||||
if not self.account_currency:
|
if not self.account_currency:
|
||||||
|
@ -2,12 +2,11 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe, json
|
import frappe, erpnext, json
|
||||||
from frappe.utils import cstr, flt, fmt_money, formatdate
|
from frappe.utils import cstr, flt, fmt_money, formatdate
|
||||||
from frappe import msgprint, _, scrub
|
from frappe import msgprint, _, scrub
|
||||||
from erpnext.controllers.accounts_controller import AccountsController
|
from erpnext.controllers.accounts_controller import AccountsController
|
||||||
from erpnext.accounts.utils import get_balance_on, get_account_currency
|
from erpnext.accounts.utils import get_balance_on, get_account_currency
|
||||||
from erpnext.setup.utils import get_company_currency
|
|
||||||
from erpnext.accounts.party import get_party_account
|
from erpnext.accounts.party import get_party_account
|
||||||
from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
|
from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
|
||||||
from erpnext.hr.doctype.employee_loan.employee_loan import update_disbursement_status
|
from erpnext.hr.doctype.employee_loan.employee_loan import update_disbursement_status
|
||||||
@ -746,7 +745,7 @@ def get_outstanding(args):
|
|||||||
if isinstance(args, basestring):
|
if isinstance(args, basestring):
|
||||||
args = json.loads(args)
|
args = json.loads(args)
|
||||||
|
|
||||||
company_currency = get_company_currency(args.get("company"))
|
company_currency = erpnext.get_company_currency(args.get("company"))
|
||||||
|
|
||||||
if args.get("doctype") == "Journal Entry":
|
if args.get("doctype") == "Journal Entry":
|
||||||
condition = " and party=%(party)s" if args.get("party") else ""
|
condition = " and party=%(party)s" if args.get("party") else ""
|
||||||
@ -805,7 +804,7 @@ def get_account_balance_and_party_type(account, date, company, debit=None, credi
|
|||||||
if not frappe.has_permission("Account"):
|
if not frappe.has_permission("Account"):
|
||||||
frappe.msgprint(_("No Permission"), raise_exception=1)
|
frappe.msgprint(_("No Permission"), raise_exception=1)
|
||||||
|
|
||||||
company_currency = get_company_currency(company)
|
company_currency = erpnext.get_company_currency(company)
|
||||||
account_details = frappe.db.get_value("Account", account, ["account_type", "account_currency"], as_dict=1)
|
account_details = frappe.db.get_value("Account", account, ["account_type", "account_currency"], as_dict=1)
|
||||||
|
|
||||||
if not account_details:
|
if not account_details:
|
||||||
@ -853,7 +852,7 @@ def get_exchange_rate(posting_date, account=None, account_currency=None, company
|
|||||||
if not account_currency:
|
if not account_currency:
|
||||||
account_currency = account_details.account_currency
|
account_currency = account_details.account_currency
|
||||||
|
|
||||||
company_currency = get_company_currency(company)
|
company_currency = erpnext.get_company_currency(company)
|
||||||
|
|
||||||
if account_currency != company_currency:
|
if account_currency != company_currency:
|
||||||
if reference_type in ("Sales Invoice", "Purchase Invoice") and reference_name:
|
if reference_type in ("Sales Invoice", "Purchase Invoice") and reference_name:
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
frappe.provide("erpnext.accounts");
|
frappe.provide("erpnext.accounts");
|
||||||
{% include 'erpnext/buying/doctype/purchase_common/purchase_common.js' %};
|
{% include 'erpnext/public/js/controllers/buying.js' %};
|
||||||
|
|
||||||
|
|
||||||
erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||||
setup: function(doc) {
|
setup: function(doc) {
|
||||||
|
@ -2,10 +2,9 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe, erpnext
|
||||||
from frappe.utils import cint, formatdate, flt, getdate
|
from frappe.utils import cint, formatdate, flt, getdate
|
||||||
from frappe import _, throw
|
from frappe import _, throw
|
||||||
from erpnext.setup.utils import get_company_currency
|
|
||||||
import frappe.defaults
|
import frappe.defaults
|
||||||
|
|
||||||
from erpnext.controllers.buying_controller import BuyingController
|
from erpnext.controllers.buying_controller import BuyingController
|
||||||
@ -15,6 +14,7 @@ from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_bille
|
|||||||
from erpnext.controllers.stock_controller import get_warehouse_account
|
from erpnext.controllers.stock_controller import get_warehouse_account
|
||||||
from erpnext.accounts.general_ledger import make_gl_entries, merge_similar_entries, delete_gl_entries
|
from erpnext.accounts.general_ledger import make_gl_entries, merge_similar_entries, delete_gl_entries
|
||||||
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
|
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
|
||||||
|
from erpnext.buying.utils import check_for_closed_status
|
||||||
|
|
||||||
form_grid_templates = {
|
form_grid_templates = {
|
||||||
"items": "templates/form_grid/item_grid.html"
|
"items": "templates/form_grid/item_grid.html"
|
||||||
@ -93,7 +93,7 @@ class PurchaseInvoice(BuyingController):
|
|||||||
super(PurchaseInvoice, self).set_missing_values(for_validate)
|
super(PurchaseInvoice, self).set_missing_values(for_validate)
|
||||||
|
|
||||||
def check_conversion_rate(self):
|
def check_conversion_rate(self):
|
||||||
default_currency = get_company_currency(self.company)
|
default_currency = erpnext.get_company_currency(self.company)
|
||||||
if not default_currency:
|
if not default_currency:
|
||||||
throw(_('Please enter default currency in Company Master'))
|
throw(_('Please enter default currency in Company Master'))
|
||||||
if (self.currency == default_currency and flt(self.conversion_rate) != 1.00) or not self.conversion_rate or (self.currency != default_currency and flt(self.conversion_rate) == 1.00):
|
if (self.currency == default_currency and flt(self.conversion_rate) != 1.00) or not self.conversion_rate or (self.currency != default_currency and flt(self.conversion_rate) == 1.00):
|
||||||
@ -113,12 +113,11 @@ class PurchaseInvoice(BuyingController):
|
|||||||
|
|
||||||
def check_for_closed_status(self):
|
def check_for_closed_status(self):
|
||||||
check_list = []
|
check_list = []
|
||||||
pc_obj = frappe.get_doc('Purchase Common')
|
|
||||||
|
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
if d.purchase_order and not d.purchase_order in check_list and not d.purchase_receipt:
|
if d.purchase_order and not d.purchase_order in check_list and not d.purchase_receipt:
|
||||||
check_list.append(d.purchase_order)
|
check_list.append(d.purchase_order)
|
||||||
pc_obj.check_for_closed_status('Purchase Order', d.purchase_order)
|
check_for_closed_status('Purchase Order', d.purchase_order)
|
||||||
|
|
||||||
def validate_with_previous_doc(self):
|
def validate_with_previous_doc(self):
|
||||||
super(PurchaseInvoice, self).validate_with_previous_doc({
|
super(PurchaseInvoice, self).validate_with_previous_doc({
|
||||||
|
@ -4,11 +4,10 @@
|
|||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe, erpnext
|
||||||
from frappe import _, msgprint, throw
|
from frappe import _, msgprint, throw
|
||||||
from frappe.utils import flt, fmt_money
|
from frappe.utils import flt, fmt_money
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from erpnext.setup.utils import get_company_currency
|
|
||||||
|
|
||||||
class OverlappingConditionError(frappe.ValidationError): pass
|
class OverlappingConditionError(frappe.ValidationError): pass
|
||||||
class FromGreaterThanToError(frappe.ValidationError): pass
|
class FromGreaterThanToError(frappe.ValidationError): pass
|
||||||
@ -77,7 +76,7 @@ class ShippingRule(Document):
|
|||||||
overlaps.append([d1, d2])
|
overlaps.append([d1, d2])
|
||||||
|
|
||||||
if overlaps:
|
if overlaps:
|
||||||
company_currency = get_company_currency(self.company)
|
company_currency = erpnext.get_company_currency(self.company)
|
||||||
msgprint(_("Overlapping conditions found between:"))
|
msgprint(_("Overlapping conditions found between:"))
|
||||||
messages = []
|
messages = []
|
||||||
for d1, d2 in overlaps:
|
for d1, d2 in overlaps:
|
||||||
|
@ -151,13 +151,6 @@ def set_account_and_due_date(party, account, party_type, company, posting_date,
|
|||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def get_company_currency():
|
|
||||||
company_currency = frappe._dict()
|
|
||||||
for d in frappe.get_all("Company", fields=["name", "default_currency"]):
|
|
||||||
company_currency.setdefault(d.name, d.default_currency)
|
|
||||||
|
|
||||||
return company_currency
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_party_account(party_type, party, company):
|
def get_party_account(party_type, party, company):
|
||||||
"""Returns the account for the given `party`.
|
"""Returns the account for the given `party`.
|
||||||
|
@ -12,7 +12,7 @@ from frappe.utils import flt
|
|||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
if not filters: filters = frappe._dict()
|
if not filters: filters = frappe._dict()
|
||||||
company_currency = frappe.db.get_value("Company", filters.company, "default_currency")
|
filters.currency = frappe.db.get_value("Company", filters.company, "default_currency")
|
||||||
|
|
||||||
gross_profit_data = GrossProfitGenerator(filters)
|
gross_profit_data = GrossProfitGenerator(filters)
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ def execute(filters=None):
|
|||||||
for col in group_wise_columns.get(scrub(filters.group_by)):
|
for col in group_wise_columns.get(scrub(filters.group_by)):
|
||||||
row.append(src.get(col))
|
row.append(src.get(col))
|
||||||
|
|
||||||
row.append(company_currency)
|
row.append(filters.currency)
|
||||||
data.append(row)
|
data.append(row)
|
||||||
|
|
||||||
return columns, data
|
return columns, data
|
||||||
@ -224,7 +224,10 @@ class GrossProfitGenerator(object):
|
|||||||
else:
|
else:
|
||||||
average_buying_rate = get_incoming_rate(row)
|
average_buying_rate = get_incoming_rate(row)
|
||||||
if not average_buying_rate:
|
if not average_buying_rate:
|
||||||
average_buying_rate = get_valuation_rate(item_code, row.warehouse, allow_zero_rate=True)
|
average_buying_rate = get_valuation_rate(item_code, row.warehouse,
|
||||||
|
row.parenttype, row.parent, allow_zero_rate=True,
|
||||||
|
currency=self.filters.currency)
|
||||||
|
|
||||||
self.average_buying_rate[item_code] = average_buying_rate
|
self.average_buying_rate[item_code] = average_buying_rate
|
||||||
|
|
||||||
return self.average_buying_rate[item_code]
|
return self.average_buying_rate[item_code]
|
||||||
|
@ -1 +0,0 @@
|
|||||||
Common scripts for purchase transactions.
|
|
@ -1 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"allow_copy": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 0,
|
|
||||||
"creation": "2012-03-27 14:35:51",
|
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
|
||||||
"fields": [],
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 1,
|
|
||||||
"in_create": 0,
|
|
||||||
"in_dialog": 0,
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 1,
|
|
||||||
"istable": 0,
|
|
||||||
"modified": "2013-12-20 19:23:27",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "Buying",
|
|
||||||
"name": "Purchase Common",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"permissions": [],
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0
|
|
||||||
}
|
|
@ -1,105 +0,0 @@
|
|||||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe, json
|
|
||||||
from frappe.utils import flt, cstr, cint
|
|
||||||
from frappe import _
|
|
||||||
|
|
||||||
from erpnext.stock.doctype.item.item import get_last_purchase_details
|
|
||||||
from erpnext.controllers.buying_controller import BuyingController
|
|
||||||
|
|
||||||
class PurchaseCommon(BuyingController):
|
|
||||||
def update_last_purchase_rate(self, obj, is_submit):
|
|
||||||
"""updates last_purchase_rate in item table for each item"""
|
|
||||||
|
|
||||||
import frappe.utils
|
|
||||||
this_purchase_date = frappe.utils.getdate(obj.get('posting_date') or obj.get('transaction_date'))
|
|
||||||
|
|
||||||
for d in obj.get("items"):
|
|
||||||
# get last purchase details
|
|
||||||
last_purchase_details = get_last_purchase_details(d.item_code, obj.name)
|
|
||||||
|
|
||||||
# compare last purchase date and this transaction's date
|
|
||||||
last_purchase_rate = None
|
|
||||||
if last_purchase_details and \
|
|
||||||
(last_purchase_details.purchase_date > this_purchase_date):
|
|
||||||
last_purchase_rate = last_purchase_details['base_rate']
|
|
||||||
elif is_submit == 1:
|
|
||||||
# even if this transaction is the latest one, it should be submitted
|
|
||||||
# for it to be considered for latest purchase rate
|
|
||||||
if flt(d.conversion_factor):
|
|
||||||
last_purchase_rate = flt(d.base_rate) / flt(d.conversion_factor)
|
|
||||||
else:
|
|
||||||
frappe.throw(_("UOM Conversion factor is required in row {0}").format(d.idx))
|
|
||||||
|
|
||||||
# update last purchsae rate
|
|
||||||
if last_purchase_rate:
|
|
||||||
frappe.db.sql("""update `tabItem` set last_purchase_rate = %s where name = %s""",
|
|
||||||
(flt(last_purchase_rate), d.item_code))
|
|
||||||
|
|
||||||
def validate_for_items(self, obj):
|
|
||||||
items = []
|
|
||||||
for d in obj.get("items"):
|
|
||||||
if not d.qty:
|
|
||||||
if obj.doctype == "Purchase Receipt" and d.rejected_qty:
|
|
||||||
continue
|
|
||||||
frappe.throw(_("Please enter quantity for Item {0}").format(d.item_code))
|
|
||||||
|
|
||||||
# udpate with latest quantities
|
|
||||||
bin = frappe.db.sql("""select projected_qty from `tabBin` where
|
|
||||||
item_code = %s and warehouse = %s""", (d.item_code, d.warehouse), as_dict=1)
|
|
||||||
|
|
||||||
f_lst ={'projected_qty': bin and flt(bin[0]['projected_qty']) or 0, 'ordered_qty': 0, 'received_qty' : 0}
|
|
||||||
if d.doctype in ('Purchase Receipt Item', 'Purchase Invoice Item'):
|
|
||||||
f_lst.pop('received_qty')
|
|
||||||
for x in f_lst :
|
|
||||||
if d.meta.get_field(x):
|
|
||||||
d.set(x, f_lst[x])
|
|
||||||
|
|
||||||
item = frappe.db.sql("""select is_stock_item,
|
|
||||||
is_sub_contracted_item, end_of_life, disabled from `tabItem` where name=%s""",
|
|
||||||
d.item_code, as_dict=1)[0]
|
|
||||||
|
|
||||||
from erpnext.stock.doctype.item.item import validate_end_of_life
|
|
||||||
validate_end_of_life(d.item_code, item.end_of_life, item.disabled)
|
|
||||||
|
|
||||||
# validate stock item
|
|
||||||
if item.is_stock_item==1 and d.qty and not d.warehouse and not d.delivered_by_supplier:
|
|
||||||
frappe.throw(_("Warehouse is mandatory for stock Item {0} in row {1}").format(d.item_code, d.idx))
|
|
||||||
|
|
||||||
items.append(cstr(d.item_code))
|
|
||||||
|
|
||||||
if items and len(items) != len(set(items)) and \
|
|
||||||
not cint(frappe.db.get_single_value("Buying Settings", "allow_multiple_items") or 0):
|
|
||||||
frappe.throw(_("Same item cannot be entered multiple times."))
|
|
||||||
|
|
||||||
def check_for_closed_status(self, doctype, docname):
|
|
||||||
status = frappe.db.get_value(doctype, docname, "status")
|
|
||||||
|
|
||||||
if status == "Closed":
|
|
||||||
frappe.throw(_("{0} {1} status is {2}").format(doctype, docname, status), frappe.InvalidStatusError)
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
|
||||||
def get_linked_material_requests(items):
|
|
||||||
items = json.loads(items)
|
|
||||||
mr_list = []
|
|
||||||
for item in items:
|
|
||||||
material_request = frappe.db.sql("""SELECT distinct mr.name AS mr_name,
|
|
||||||
(mr_item.qty - mr_item.ordered_qty) AS qty,
|
|
||||||
mr_item.item_code AS item_code,
|
|
||||||
mr_item.name AS mr_item
|
|
||||||
FROM `tabMaterial Request` mr, `tabMaterial Request Item` mr_item
|
|
||||||
WHERE mr.name = mr_item.parent
|
|
||||||
AND mr_item.item_code = %(item)s
|
|
||||||
AND mr.material_request_type = 'Purchase'
|
|
||||||
AND mr.per_ordered < 99.99
|
|
||||||
AND mr.docstatus = 1
|
|
||||||
AND mr.status != 'Stopped'
|
|
||||||
ORDER BY mr_item.item_code ASC""",{"item": item}, as_dict=1)
|
|
||||||
if material_request:
|
|
||||||
mr_list.append(material_request)
|
|
||||||
|
|
||||||
return mr_list
|
|
||||||
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
frappe.provide("erpnext.buying");
|
frappe.provide("erpnext.buying");
|
||||||
|
|
||||||
{% include 'erpnext/buying/doctype/purchase_common/purchase_common.js' %};
|
{% include 'erpnext/public/js/controllers/buying.js' %};
|
||||||
|
|
||||||
frappe.ui.form.on("Purchase Order", {
|
frappe.ui.form.on("Purchase Order", {
|
||||||
setup: function(frm) {
|
setup: function(frm) {
|
||||||
|
@ -11,6 +11,8 @@ from erpnext.controllers.buying_controller import BuyingController
|
|||||||
from erpnext.stock.doctype.item.item import get_last_purchase_details
|
from erpnext.stock.doctype.item.item import get_last_purchase_details
|
||||||
from erpnext.stock.stock_balance import update_bin_qty, get_ordered_qty
|
from erpnext.stock.stock_balance import update_bin_qty, get_ordered_qty
|
||||||
from frappe.desk.notifications import clear_doctype_notifications
|
from frappe.desk.notifications import clear_doctype_notifications
|
||||||
|
from erpnext.buying.utils import (validate_for_items, check_for_closed_status,
|
||||||
|
update_last_purchase_rate)
|
||||||
|
|
||||||
|
|
||||||
form_grid_templates = {
|
form_grid_templates = {
|
||||||
@ -37,9 +39,8 @@ class PurchaseOrder(BuyingController):
|
|||||||
super(PurchaseOrder, self).validate()
|
super(PurchaseOrder, self).validate()
|
||||||
|
|
||||||
self.set_status()
|
self.set_status()
|
||||||
pc_obj = frappe.get_doc('Purchase Common')
|
validate_for_items(self)
|
||||||
pc_obj.validate_for_items(self)
|
self.check_for_closed_status()
|
||||||
self.check_for_closed_status(pc_obj)
|
|
||||||
|
|
||||||
self.validate_uom_is_integer("uom", "qty")
|
self.validate_uom_is_integer("uom", "qty")
|
||||||
self.validate_uom_is_integer("stock_uom", ["qty", "required_qty"])
|
self.validate_uom_is_integer("stock_uom", ["qty", "required_qty"])
|
||||||
@ -111,12 +112,12 @@ class PurchaseOrder(BuyingController):
|
|||||||
= d.rate = item_last_purchase_rate
|
= d.rate = item_last_purchase_rate
|
||||||
|
|
||||||
# Check for Closed status
|
# Check for Closed status
|
||||||
def check_for_closed_status(self, pc_obj):
|
def check_for_closed_status(self):
|
||||||
check_list =[]
|
check_list =[]
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
if d.meta.get_field('material_request') and d.material_request and d.material_request not in check_list:
|
if d.meta.get_field('material_request') and d.material_request and d.material_request not in check_list:
|
||||||
check_list.append(d.material_request)
|
check_list.append(d.material_request)
|
||||||
pc_obj.check_for_closed_status('Material Request', d.material_request)
|
check_for_closed_status('Material Request', d.material_request)
|
||||||
|
|
||||||
def update_requested_qty(self):
|
def update_requested_qty(self):
|
||||||
material_request_map = {}
|
material_request_map = {}
|
||||||
@ -168,8 +169,6 @@ class PurchaseOrder(BuyingController):
|
|||||||
if self.is_against_so():
|
if self.is_against_so():
|
||||||
self.update_status_updater()
|
self.update_status_updater()
|
||||||
|
|
||||||
purchase_controller = frappe.get_doc("Purchase Common")
|
|
||||||
|
|
||||||
self.update_prevdoc_status()
|
self.update_prevdoc_status()
|
||||||
self.update_requested_qty()
|
self.update_requested_qty()
|
||||||
self.update_ordered_qty()
|
self.update_ordered_qty()
|
||||||
@ -177,7 +176,7 @@ class PurchaseOrder(BuyingController):
|
|||||||
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
|
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
|
||||||
self.company, self.base_grand_total)
|
self.company, self.base_grand_total)
|
||||||
|
|
||||||
purchase_controller.update_last_purchase_rate(self, is_submit = 1)
|
update_last_purchase_rate(self, is_submit = 1)
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
if self.is_against_so():
|
if self.is_against_so():
|
||||||
@ -186,8 +185,7 @@ class PurchaseOrder(BuyingController):
|
|||||||
if self.has_drop_ship_item():
|
if self.has_drop_ship_item():
|
||||||
self.update_delivered_qty_in_sales_order()
|
self.update_delivered_qty_in_sales_order()
|
||||||
|
|
||||||
pc_obj = frappe.get_doc('Purchase Common')
|
self.check_for_closed_status()
|
||||||
self.check_for_closed_status(pc_obj)
|
|
||||||
|
|
||||||
frappe.db.set(self,'status','Cancelled')
|
frappe.db.set(self,'status','Cancelled')
|
||||||
|
|
||||||
@ -197,7 +195,7 @@ class PurchaseOrder(BuyingController):
|
|||||||
self.update_requested_qty()
|
self.update_requested_qty()
|
||||||
self.update_ordered_qty()
|
self.update_ordered_qty()
|
||||||
|
|
||||||
pc_obj.update_last_purchase_rate(self, is_submit = 0)
|
update_last_purchase_rate(self, is_submit = 0)
|
||||||
|
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
pass
|
pass
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
|
||||||
{% include 'erpnext/buying/doctype/purchase_common/purchase_common.js' %};
|
{% include 'erpnext/public/js/controllers/buying.js' %};
|
||||||
|
|
||||||
cur_frm.add_fetch('contact', 'email_id', 'email_id')
|
cur_frm.add_fetch('contact', 'email_id', 'email_id')
|
||||||
|
|
||||||
|
@ -14,13 +14,14 @@ from frappe.core.doctype.communication.email import make
|
|||||||
from erpnext.accounts.party import get_party_account_currency, get_party_details
|
from erpnext.accounts.party import get_party_account_currency, get_party_details
|
||||||
from erpnext.stock.doctype.material_request.material_request import set_missing_values
|
from erpnext.stock.doctype.material_request.material_request import set_missing_values
|
||||||
from erpnext.controllers.buying_controller import BuyingController
|
from erpnext.controllers.buying_controller import BuyingController
|
||||||
|
from erpnext.buying.utils import validate_for_items
|
||||||
|
|
||||||
STANDARD_USERS = ("Guest", "Administrator")
|
STANDARD_USERS = ("Guest", "Administrator")
|
||||||
|
|
||||||
class RequestforQuotation(BuyingController):
|
class RequestforQuotation(BuyingController):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_duplicate_supplier()
|
self.validate_duplicate_supplier()
|
||||||
self.validate_common()
|
validate_for_items(self)
|
||||||
self.update_email_id()
|
self.update_email_id()
|
||||||
|
|
||||||
def validate_duplicate_supplier(self):
|
def validate_duplicate_supplier(self):
|
||||||
@ -28,10 +29,6 @@ class RequestforQuotation(BuyingController):
|
|||||||
if len(supplier_list) != len(set(supplier_list)):
|
if len(supplier_list) != len(set(supplier_list)):
|
||||||
frappe.throw(_("Same supplier has been entered multiple times"))
|
frappe.throw(_("Same supplier has been entered multiple times"))
|
||||||
|
|
||||||
def validate_common(self):
|
|
||||||
pc = frappe.get_doc('Purchase Common')
|
|
||||||
pc.validate_for_items(self)
|
|
||||||
|
|
||||||
def update_email_id(self):
|
def update_email_id(self):
|
||||||
for rfq_supplier in self.suppliers:
|
for rfq_supplier in self.suppliers:
|
||||||
if not rfq_supplier.email_id:
|
if not rfq_supplier.email_id:
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
// attach required files
|
// attach required files
|
||||||
{% include 'erpnext/buying/doctype/purchase_common/purchase_common.js' %};
|
{% include 'erpnext/public/js/controllers/buying.js' %};
|
||||||
|
|
||||||
frappe.ui.form.on('Suppier Quotation', {
|
frappe.ui.form.on('Suppier Quotation', {
|
||||||
setup: function() {
|
setup: function() {
|
||||||
|
@ -8,6 +8,7 @@ from frappe.utils import flt
|
|||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
|
|
||||||
from erpnext.controllers.buying_controller import BuyingController
|
from erpnext.controllers.buying_controller import BuyingController
|
||||||
|
from erpnext.buying.utils import validate_for_items
|
||||||
|
|
||||||
form_grid_templates = {
|
form_grid_templates = {
|
||||||
"items": "templates/form_grid/item_grid.html"
|
"items": "templates/form_grid/item_grid.html"
|
||||||
@ -24,7 +25,7 @@ class SupplierQuotation(BuyingController):
|
|||||||
validate_status(self.status, ["Draft", "Submitted", "Stopped",
|
validate_status(self.status, ["Draft", "Submitted", "Stopped",
|
||||||
"Cancelled"])
|
"Cancelled"])
|
||||||
|
|
||||||
self.validate_common()
|
validate_for_items(self)
|
||||||
self.validate_with_previous_doc()
|
self.validate_with_previous_doc()
|
||||||
self.validate_uom_is_integer("uom", "qty")
|
self.validate_uom_is_integer("uom", "qty")
|
||||||
|
|
||||||
@ -50,11 +51,6 @@ class SupplierQuotation(BuyingController):
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def validate_common(self):
|
|
||||||
pc = frappe.get_doc('Purchase Common')
|
|
||||||
pc.validate_for_items(self)
|
|
||||||
|
|
||||||
def get_list_context(context=None):
|
def get_list_context(context=None):
|
||||||
from erpnext.controllers.website_list_for_contact import get_list_context
|
from erpnext.controllers.website_list_for_contact import get_list_context
|
||||||
list_context = get_list_context(context)
|
list_context = get_list_context(context)
|
||||||
|
80
erpnext/buying/utils.py
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from frappe.utils import flt, cstr, cint
|
||||||
|
from frappe import _
|
||||||
|
|
||||||
|
from erpnext.stock.doctype.item.item import get_last_purchase_details
|
||||||
|
from erpnext.stock.doctype.item.item import validate_end_of_life
|
||||||
|
|
||||||
|
def update_last_purchase_rate(doc, is_submit):
|
||||||
|
"""updates last_purchase_rate in item table for each item"""
|
||||||
|
|
||||||
|
import frappe.utils
|
||||||
|
this_purchase_date = frappe.utils.getdate(doc.get('posting_date') or doc.get('transaction_date'))
|
||||||
|
|
||||||
|
for d in doc.get("items"):
|
||||||
|
# get last purchase details
|
||||||
|
last_purchase_details = get_last_purchase_details(d.item_code, doc.name)
|
||||||
|
|
||||||
|
# compare last purchase date and this transaction's date
|
||||||
|
last_purchase_rate = None
|
||||||
|
if last_purchase_details and \
|
||||||
|
(last_purchase_details.purchase_date > this_purchase_date):
|
||||||
|
last_purchase_rate = last_purchase_details['base_rate']
|
||||||
|
elif is_submit == 1:
|
||||||
|
# even if this transaction is the latest one, it should be submitted
|
||||||
|
# for it to be considered for latest purchase rate
|
||||||
|
if flt(d.conversion_factor):
|
||||||
|
last_purchase_rate = flt(d.base_rate) / flt(d.conversion_factor)
|
||||||
|
else:
|
||||||
|
frappe.throw(_("UOM Conversion factor is required in row {0}").format(d.idx))
|
||||||
|
|
||||||
|
# update last purchsae rate
|
||||||
|
if last_purchase_rate:
|
||||||
|
frappe.db.sql("""update `tabItem` set last_purchase_rate = %s where name = %s""",
|
||||||
|
(flt(last_purchase_rate), d.item_code))
|
||||||
|
|
||||||
|
def validate_for_items(doc):
|
||||||
|
items = []
|
||||||
|
for d in doc.get("items"):
|
||||||
|
if not d.qty:
|
||||||
|
if doc.doctype == "Purchase Receipt" and d.rejected_qty:
|
||||||
|
continue
|
||||||
|
frappe.throw(_("Please enter quantity for Item {0}").format(d.item_code))
|
||||||
|
|
||||||
|
# update with latest quantities
|
||||||
|
bin = frappe.db.sql("""select projected_qty from `tabBin` where
|
||||||
|
item_code = %s and warehouse = %s""", (d.item_code, d.warehouse), as_dict=1)
|
||||||
|
|
||||||
|
f_lst ={'projected_qty': bin and flt(bin[0]['projected_qty']) or 0, 'ordered_qty': 0, 'received_qty' : 0}
|
||||||
|
if d.doctype in ('Purchase Receipt Item', 'Purchase Invoice Item'):
|
||||||
|
f_lst.pop('received_qty')
|
||||||
|
for x in f_lst :
|
||||||
|
if d.meta.get_field(x):
|
||||||
|
d.set(x, f_lst[x])
|
||||||
|
|
||||||
|
item = frappe.db.sql("""select is_stock_item,
|
||||||
|
is_sub_contracted_item, end_of_life, disabled from `tabItem` where name=%s""",
|
||||||
|
d.item_code, as_dict=1)[0]
|
||||||
|
|
||||||
|
validate_end_of_life(d.item_code, item.end_of_life, item.disabled)
|
||||||
|
|
||||||
|
# validate stock item
|
||||||
|
if item.is_stock_item==1 and d.qty and not d.warehouse and not d.delivered_by_supplier:
|
||||||
|
frappe.throw(_("Warehouse is mandatory for stock Item {0} in row {1}").format(d.item_code, d.idx))
|
||||||
|
|
||||||
|
items.append(cstr(d.item_code))
|
||||||
|
|
||||||
|
if items and len(items) != len(set(items)) and \
|
||||||
|
not cint(frappe.db.get_single_value("Buying Settings", "allow_multiple_items") or 0):
|
||||||
|
frappe.throw(_("Same item cannot be entered multiple times."))
|
||||||
|
|
||||||
|
def check_for_closed_status(doctype, docname):
|
||||||
|
status = frappe.db.get_value(doctype, docname, "status")
|
||||||
|
|
||||||
|
if status == "Closed":
|
||||||
|
frappe.throw(_("{0} {1} status is {2}").format(doctype, docname, status), frappe.InvalidStatusError)
|
||||||
|
|
@ -2,10 +2,10 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe, erpnext
|
||||||
from frappe import _, throw
|
from frappe import _, throw
|
||||||
from frappe.utils import today, flt, cint, fmt_money, formatdate, getdate
|
from frappe.utils import today, flt, cint, fmt_money, formatdate, getdate
|
||||||
from erpnext.setup.utils import get_company_currency, get_exchange_rate
|
from erpnext.setup.utils import get_exchange_rate
|
||||||
from erpnext.accounts.utils import get_fiscal_years, validate_fiscal_year, get_account_currency
|
from erpnext.accounts.utils import get_fiscal_years, validate_fiscal_year, get_account_currency
|
||||||
from erpnext.utilities.transaction_base import TransactionBase
|
from erpnext.utilities.transaction_base import TransactionBase
|
||||||
from erpnext.controllers.recurring_document import convert_to_recurring, validate_recurring_document
|
from erpnext.controllers.recurring_document import convert_to_recurring, validate_recurring_document
|
||||||
@ -22,7 +22,7 @@ class AccountsController(TransactionBase):
|
|||||||
@property
|
@property
|
||||||
def company_currency(self):
|
def company_currency(self):
|
||||||
if not hasattr(self, "__company_currency"):
|
if not hasattr(self, "__company_currency"):
|
||||||
self.__company_currency = get_company_currency(self.company)
|
self.__company_currency = erpnext.get_company_currency(self.company)
|
||||||
|
|
||||||
return self.__company_currency
|
return self.__company_currency
|
||||||
|
|
||||||
|
@ -6,9 +6,10 @@ import frappe
|
|||||||
from frappe import _, msgprint
|
from frappe import _, msgprint
|
||||||
from frappe.utils import flt,cint, cstr
|
from frappe.utils import flt,cint, cstr
|
||||||
|
|
||||||
from erpnext.setup.utils import get_company_currency
|
|
||||||
from erpnext.accounts.party import get_party_details
|
from erpnext.accounts.party import get_party_details
|
||||||
from erpnext.stock.get_item_details import get_conversion_factor
|
from erpnext.stock.get_item_details import get_conversion_factor
|
||||||
|
from erpnext.buying.utils import validate_for_items
|
||||||
|
from erpnext.stock.stock_ledger import get_valuation_rate
|
||||||
|
|
||||||
from erpnext.controllers.stock_controller import StockController
|
from erpnext.controllers.stock_controller import StockController
|
||||||
|
|
||||||
@ -40,9 +41,7 @@ class BuyingController(StockController):
|
|||||||
# self.validate_purchase_return()
|
# self.validate_purchase_return()
|
||||||
self.validate_rejected_warehouse()
|
self.validate_rejected_warehouse()
|
||||||
self.validate_accepted_rejected_qty()
|
self.validate_accepted_rejected_qty()
|
||||||
|
validate_for_items(self)
|
||||||
pc_obj = frappe.get_doc('Purchase Common')
|
|
||||||
pc_obj.validate_for_items(self)
|
|
||||||
|
|
||||||
#sub-contracting
|
#sub-contracting
|
||||||
self.validate_for_subcontracting()
|
self.validate_for_subcontracting()
|
||||||
@ -88,9 +87,8 @@ class BuyingController(StockController):
|
|||||||
|
|
||||||
def set_total_in_words(self):
|
def set_total_in_words(self):
|
||||||
from frappe.utils import money_in_words
|
from frappe.utils import money_in_words
|
||||||
company_currency = get_company_currency(self.company)
|
|
||||||
if self.meta.get_field("base_in_words"):
|
if self.meta.get_field("base_in_words"):
|
||||||
self.base_in_words = money_in_words(self.base_grand_total, company_currency)
|
self.base_in_words = money_in_words(self.base_grand_total, self.company_currency)
|
||||||
if self.meta.get_field("in_words"):
|
if self.meta.get_field("in_words"):
|
||||||
self.in_words = money_in_words(self.grand_total, self.currency)
|
self.in_words = money_in_words(self.grand_total, self.currency)
|
||||||
|
|
||||||
@ -225,9 +223,8 @@ class BuyingController(StockController):
|
|||||||
"serial_no": rm.serial_no
|
"serial_no": rm.serial_no
|
||||||
})
|
})
|
||||||
if not rm.rate:
|
if not rm.rate:
|
||||||
from erpnext.stock.stock_ledger import get_valuation_rate
|
|
||||||
rm.rate = get_valuation_rate(bom_item.item_code, self.supplier_warehouse,
|
rm.rate = get_valuation_rate(bom_item.item_code, self.supplier_warehouse,
|
||||||
self.doctype, self.name)
|
self.doctype, self.name, currency=self.company_currency)
|
||||||
else:
|
else:
|
||||||
rm.rate = bom_item.rate
|
rm.rate = bom_item.rate
|
||||||
|
|
||||||
|
@ -4,11 +4,9 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import cint, flt, cstr, comma_or
|
from frappe.utils import cint, flt, cstr, comma_or
|
||||||
from erpnext.setup.utils import get_company_currency
|
|
||||||
from frappe import _, throw
|
from frappe import _, throw
|
||||||
from erpnext.stock.get_item_details import get_bin_details
|
from erpnext.stock.get_item_details import get_bin_details
|
||||||
from erpnext.stock.utils import get_incoming_rate
|
from erpnext.stock.utils import get_incoming_rate
|
||||||
from erpnext.stock.stock_ledger import get_valuation_rate
|
|
||||||
from erpnext.stock.get_item_details import get_conversion_factor
|
from erpnext.stock.get_item_details import get_conversion_factor
|
||||||
|
|
||||||
from erpnext.controllers.stock_controller import StockController
|
from erpnext.controllers.stock_controller import StockController
|
||||||
@ -113,13 +111,11 @@ class SellingController(StockController):
|
|||||||
|
|
||||||
def set_total_in_words(self):
|
def set_total_in_words(self):
|
||||||
from frappe.utils import money_in_words
|
from frappe.utils import money_in_words
|
||||||
company_currency = get_company_currency(self.company)
|
|
||||||
|
|
||||||
disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, "disable_rounded_total"))
|
disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, "disable_rounded_total"))
|
||||||
|
|
||||||
if self.meta.get_field("base_in_words"):
|
if self.meta.get_field("base_in_words"):
|
||||||
self.base_in_words = money_in_words(disable_rounded_total and
|
self.base_in_words = money_in_words(disable_rounded_total and
|
||||||
abs(self.base_grand_total) or abs(self.base_rounded_total), company_currency)
|
abs(self.base_grand_total) or abs(self.base_rounded_total), self.company_currency)
|
||||||
if self.meta.get_field("in_words"):
|
if self.meta.get_field("in_words"):
|
||||||
self.in_words = money_in_words(disable_rounded_total and
|
self.in_words = money_in_words(disable_rounded_total and
|
||||||
abs(self.grand_total) or abs(self.rounded_total), self.currency)
|
abs(self.grand_total) or abs(self.rounded_total), self.currency)
|
||||||
|
@ -97,7 +97,7 @@ class StockController(AccountsController):
|
|||||||
|
|
||||||
def update_stock_ledger_entries(self, sle):
|
def update_stock_ledger_entries(self, sle):
|
||||||
sle.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
|
sle.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
|
||||||
self.doctype, self.name)
|
self.doctype, self.name, currency=self.company_currency)
|
||||||
|
|
||||||
sle.stock_value = flt(sle.qty_after_transaction) * flt(sle.valuation_rate)
|
sle.stock_value = flt(sle.qty_after_transaction) * flt(sle.valuation_rate)
|
||||||
sle.stock_value_difference = flt(sle.actual_qty) * flt(sle.valuation_rate)
|
sle.stock_value_difference = flt(sle.actual_qty) * flt(sle.valuation_rate)
|
||||||
|
@ -3,10 +3,9 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import json
|
import json
|
||||||
import frappe
|
import frappe, erpnext
|
||||||
from frappe import _, scrub
|
from frappe import _, scrub
|
||||||
from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
|
from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
|
||||||
from erpnext.setup.utils import get_company_currency
|
|
||||||
from erpnext.controllers.accounts_controller import validate_conversion_rate, \
|
from erpnext.controllers.accounts_controller import validate_conversion_rate, \
|
||||||
validate_taxes_and_charges, validate_inclusive_tax
|
validate_taxes_and_charges, validate_inclusive_tax
|
||||||
|
|
||||||
@ -38,7 +37,7 @@ class calculate_taxes_and_totals(object):
|
|||||||
|
|
||||||
def validate_conversion_rate(self):
|
def validate_conversion_rate(self):
|
||||||
# validate conversion rate
|
# validate conversion rate
|
||||||
company_currency = get_company_currency(self.doc.company)
|
company_currency = erpnext.get_company_currency(self.doc.company)
|
||||||
if not self.doc.currency or self.doc.currency == company_currency:
|
if not self.doc.currency or self.doc.currency == company_currency:
|
||||||
self.doc.currency = company_currency
|
self.doc.currency = company_currency
|
||||||
self.doc.conversion_rate = 1.0
|
self.doc.conversion_rate = 1.0
|
||||||
@ -327,7 +326,7 @@ class calculate_taxes_and_totals(object):
|
|||||||
self.doc.rounded_total = round_based_on_smallest_currency_fraction(self.doc.grand_total,
|
self.doc.rounded_total = round_based_on_smallest_currency_fraction(self.doc.grand_total,
|
||||||
self.doc.currency, self.doc.precision("rounded_total"))
|
self.doc.currency, self.doc.precision("rounded_total"))
|
||||||
if self.doc.meta.get_field("base_rounded_total"):
|
if self.doc.meta.get_field("base_rounded_total"):
|
||||||
company_currency = get_company_currency(self.doc.company)
|
company_currency = erpnext.get_company_currency(self.doc.company)
|
||||||
|
|
||||||
self.doc.base_rounded_total = \
|
self.doc.base_rounded_total = \
|
||||||
round_based_on_smallest_currency_fraction(self.doc.base_grand_total,
|
round_based_on_smallest_currency_fraction(self.doc.base_grand_total,
|
||||||
|
@ -197,6 +197,7 @@ def make_quotation(source_name, target_doc=None):
|
|||||||
|
|
||||||
# get default taxes
|
# get default taxes
|
||||||
taxes = get_default_taxes_and_charges("Sales Taxes and Charges Template")
|
taxes = get_default_taxes_and_charges("Sales Taxes and Charges Template")
|
||||||
|
if taxes:
|
||||||
quotation.extend("taxes", taxes)
|
quotation.extend("taxes", taxes)
|
||||||
|
|
||||||
quotation.run_method("set_missing_values")
|
quotation.run_method("set_missing_values")
|
||||||
|
@ -63,6 +63,10 @@ def complete_setup(domain='Manufacturing'):
|
|||||||
"language": "english"
|
"language": "english"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
company = erpnext.get_default_company()
|
||||||
|
company.db_set('default_payroll_payable_account',
|
||||||
|
frappe.db.get_value('Account', dict(account_name='Payroll Payable')))
|
||||||
|
|
||||||
def setup_demo_page():
|
def setup_demo_page():
|
||||||
# home page should always be "start"
|
# home page should always be "start"
|
||||||
website_settings = frappe.get_doc("Website Settings", "Website Settings")
|
website_settings = frappe.get_doc("Website Settings", "Website Settings")
|
||||||
|
@ -34,14 +34,16 @@ def work():
|
|||||||
process_payroll.salary_slip_based_on_timesheet = 0
|
process_payroll.salary_slip_based_on_timesheet = 0
|
||||||
process_payroll.create_salary_slips()
|
process_payroll.create_salary_slips()
|
||||||
process_payroll.submit_salary_slips()
|
process_payroll.submit_salary_slips()
|
||||||
process_payroll.make_journal_entry(reference_date=frappe.flags.current_date,
|
process_payroll.make_accural_jv_entry()
|
||||||
reference_number=random_string(10))
|
# process_payroll.make_journal_entry(reference_date=frappe.flags.current_date,
|
||||||
|
# reference_number=random_string(10))
|
||||||
|
|
||||||
process_payroll.salary_slip_based_on_timesheet = 1
|
process_payroll.salary_slip_based_on_timesheet = 1
|
||||||
process_payroll.create_salary_slips()
|
process_payroll.create_salary_slips()
|
||||||
process_payroll.submit_salary_slips()
|
process_payroll.submit_salary_slips()
|
||||||
process_payroll.make_journal_entry(reference_date=frappe.flags.current_date,
|
process_payroll.make_accural_jv_entry()
|
||||||
reference_number=random_string(10))
|
# process_payroll.make_journal_entry(reference_date=frappe.flags.current_date,
|
||||||
|
# reference_number=random_string(10))
|
||||||
|
|
||||||
if frappe.db.get_global('demo_hr_user'):
|
if frappe.db.get_global('demo_hr_user'):
|
||||||
make_timesheet_records()
|
make_timesheet_records()
|
||||||
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 62 KiB |
BIN
erpnext/docs/assets/img/accounts/pos-email.png
Normal file
After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 570 KiB After Width: | Height: | Size: 570 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 110 KiB |
BIN
erpnext/docs/assets/img/users-and-permissions/roles-for-page.png
Normal file
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 79 KiB |
@ -27,7 +27,7 @@ In ERPNext all Sales and Purchase transactions, like Sales Invoice, Quotation, S
|
|||||||
|
|
||||||
### Customer
|
### Customer
|
||||||
|
|
||||||
You can select one of the existing Customer from the Customer master. If Customer doesn't exist in the Customer master, enter Customer Name in the POS Invoice view itself. On creation of POS Invoice, Customer will be auto-created in the Customer master.
|
In POS, user can select the existing customer during making an order or create the new customer. This features works in the offline mode also. User can also add the customer details like contact number, address details etc on the form. The customer which has been created from the POS will be synced when the internet connection is active.
|
||||||
|
|
||||||
<img class="screenshot" alt="POS Customer" src="{{docs_base_url}}/assets/img/accounts/pos-customer.png">
|
<img class="screenshot" alt="POS Customer" src="{{docs_base_url}}/assets/img/accounts/pos-customer.png">
|
||||||
|
|
||||||
@ -105,4 +105,9 @@ Credits:
|
|||||||
|
|
||||||
To see entries after “Submit”, click on “View Ledger”.
|
To see entries after “Submit”, click on “View Ledger”.
|
||||||
|
|
||||||
|
### Email
|
||||||
|
User can send email from the POS, after submission of an order, user has to click on menu > email
|
||||||
|
<img class="screenshot" alt="POS Payment" src="{{docs_base_url}}/assets/img/accounts/pos-email.png">
|
||||||
|
After sync of an order, email sent to the customer with the print of the bill in the attachment
|
||||||
|
|
||||||
{next}
|
{next}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
adding-users
|
adding-users
|
||||||
role-based-permissions
|
role-based-permissions
|
||||||
user-permissions
|
user-permissions
|
||||||
|
role-permisison-for-page-and-report
|
||||||
sharing
|
sharing
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
# Role Permission for Page and Report
|
||||||
|
|
||||||
|
In ERPNext, user can make his custom user interface using Page and the custom report using Report Builder or Query Report. ERPNext has role-based-permission system where user can assign roles to the user. And the same role can be assigned to the page and report, to access them.
|
||||||
|
|
||||||
|
If user has enabled the developer mode, then they can add the roles directly in the page and report record. But in that case, the permissions will also be reflected in the json file for the page / report.
|
||||||
|
|
||||||
|
### For Page
|
||||||
|
<img alt="Assign roles to the page" class="screenshot" src="{{docs_base_url}}/assets/img/users-and-permissions/roles-for-page.png">
|
||||||
|
|
||||||
|
### For Report
|
||||||
|
<img alt="Assign roles to the report" class="screenshot" src="{{docs_base_url}}/assets/img/users-and-permissions/roles-for-report.png">
|
||||||
|
|
||||||
|
## Tool for custom roles assignment
|
||||||
|
|
||||||
|
If developer mode is disabled, then user can assign the roles to the page and report, using "Role Permission for Page and Report" page.
|
||||||
|
|
||||||
|
To access, goto Setup > Permissions > Role Permission for Page and Report
|
||||||
|
|
||||||
|
<img alt="Tools to assign custom roles to the page" class="screenshot" src="{{docs_base_url}}/assets/img/users-and-permissions/role-permission-for-page-and-report.png">
|
||||||
|
|
||||||
|
### Reset to defaults
|
||||||
|
|
||||||
|
Using "Reset to Default" button, user can remove the custom permissions applied on a page or report. Then default permissions will be applicable on that page or report.
|
||||||
|
|
||||||
|
<img alt="Reset the default roles" class="screenshot" src="{{docs_base_url}}/assets/img/users-and-permissions/reset-roles-permisison-for-page-report.png">
|
@ -5,7 +5,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe import _
|
from frappe.model.naming import append_number_if_name_exists
|
||||||
|
|
||||||
class SalaryComponent(Document):
|
class SalaryComponent(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
@ -13,12 +13,10 @@ class SalaryComponent(Document):
|
|||||||
|
|
||||||
def validate_abbr(self):
|
def validate_abbr(self):
|
||||||
if not self.salary_component_abbr:
|
if not self.salary_component_abbr:
|
||||||
self.salary_component_abbr = ''.join([c[0] for c in self.salary_component.split()]).upper()
|
self.salary_component_abbr = ''.join([c[0] for c in
|
||||||
|
self.salary_component.split()]).upper()
|
||||||
|
|
||||||
self.salary_component_abbr = self.salary_component_abbr.strip()
|
self.salary_component_abbr = self.salary_component_abbr.strip()
|
||||||
|
|
||||||
if self.get('__islocal') and len(self.salary_component_abbr) > 5:
|
self.salary_component_abbr = append_number_if_name_exists('Salary Component',
|
||||||
frappe.throw(_("Abbreviation cannot have more than 5 characters"))
|
self.salary_component_abbr, 'salary_component_abbr', separator='_')
|
||||||
|
|
||||||
if frappe.db.sql("select salary_component_abbr from `tabSalary Component` where name!=%s and salary_component_abbr=%s", (self.name, self.salary_component_abbr)):
|
|
||||||
frappe.throw(_("Abbreviation {0} already used for another salary component").format(self.salary_component_abbr))
|
|
@ -2,13 +2,12 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe, erpnext
|
||||||
|
|
||||||
from frappe.utils import add_days, cint, cstr, flt, getdate, rounded, date_diff, money_in_words
|
from frappe.utils import add_days, cint, cstr, flt, getdate, rounded, date_diff, money_in_words
|
||||||
from frappe.model.naming import make_autoname
|
from frappe.model.naming import make_autoname
|
||||||
|
|
||||||
from frappe import msgprint, _
|
from frappe import msgprint, _
|
||||||
from erpnext.setup.utils import get_company_currency
|
|
||||||
from erpnext.hr.doctype.process_payroll.process_payroll import get_start_end_dates
|
from erpnext.hr.doctype.process_payroll.process_payroll import get_start_end_dates
|
||||||
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
||||||
from erpnext.utilities.transaction_base import TransactionBase
|
from erpnext.utilities.transaction_base import TransactionBase
|
||||||
@ -33,7 +32,7 @@ class SalarySlip(TransactionBase):
|
|||||||
# if self.salary_slip_based_on_timesheet or not self.net_pay:
|
# if self.salary_slip_based_on_timesheet or not self.net_pay:
|
||||||
self.calculate_net_pay()
|
self.calculate_net_pay()
|
||||||
|
|
||||||
company_currency = get_company_currency(self.company)
|
company_currency = erpnext.get_company_currency(self.company)
|
||||||
self.total_in_words = money_in_words(self.rounded_total, company_currency)
|
self.total_in_words = money_in_words(self.rounded_total, company_currency)
|
||||||
|
|
||||||
if frappe.db.get_single_value("HR Settings", "max_working_hours_against_timesheet"):
|
if frappe.db.get_single_value("HR Settings", "max_working_hours_against_timesheet"):
|
||||||
|
@ -218,7 +218,7 @@ $.extend(cur_frm.cscript, {
|
|||||||
project: doc.project
|
project: doc.project
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
$.each(["description", "stock_uom", "bom_no"], function(i, field) {
|
$.each(["description", "stock_uom", "project", "bom_no"], function(i, field) {
|
||||||
cur_frm.set_value(field, r.message[field]);
|
cur_frm.set_value(field, r.message[field]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -498,6 +498,7 @@ def get_item_details(item, project = None):
|
|||||||
frappe.throw(_("Default BOM for {0} not found for Project {1}").format(item, project))
|
frappe.throw(_("Default BOM for {0} not found for Project {1}").format(item, project))
|
||||||
frappe.throw(_("Default BOM for {0} not found").format(item))
|
frappe.throw(_("Default BOM for {0} not found").format(item))
|
||||||
|
|
||||||
|
res['project'] = frappe.db.get_value('BOM', res['bom_no'], 'project')
|
||||||
res.update(check_if_scrap_warehouse_mandatory(res["bom_no"]))
|
res.update(check_if_scrap_warehouse_mandatory(res["bom_no"]))
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
@ -382,3 +382,4 @@ erpnext.patches.v7_2.make_all_assessment_group
|
|||||||
erpnext.patches.v8_0.manufacturer_childtable_migrate
|
erpnext.patches.v8_0.manufacturer_childtable_migrate
|
||||||
erpnext.patches.v8_0.repost_reserved_qty_for_multiple_sales_uom
|
erpnext.patches.v8_0.repost_reserved_qty_for_multiple_sales_uom
|
||||||
erpnext.patches.v8_0.addresses_linked_to_lead
|
erpnext.patches.v8_0.addresses_linked_to_lead
|
||||||
|
execute:frappe.delete_doc('DocType', 'Purchase Common')
|
@ -20,6 +20,5 @@ def execute():
|
|||||||
"manufacturer": item.manufacturer,
|
"manufacturer": item.manufacturer,
|
||||||
"manufacturer_part_no": item.manufacturer_part_no
|
"manufacturer_part_no": item.manufacturer_part_no
|
||||||
})
|
})
|
||||||
item_doc.flags.ignore_validate = True
|
|
||||||
item_doc.flags.ignore_mandatory = True
|
item_doc.get("manufacturers")[0].db_update()
|
||||||
item_doc.save()
|
|
@ -1,5 +1,5 @@
|
|||||||
frappe.listview_settings['Project'] = {
|
frappe.listview_settings['Project'] = {
|
||||||
add_fields: ["status", "priority", "is_active", "percent_complete", "expected_end_date"],
|
add_fields: ["status", "priority", "is_active", "percent_complete", "expected_end_date", "project_name"],
|
||||||
filters:[["status","=", "Open"]],
|
filters:[["status","=", "Open"]],
|
||||||
get_indicator: function(doc) {
|
get_indicator: function(doc) {
|
||||||
if(doc.status=="Open" && doc.percent_complete) {
|
if(doc.status=="Open" && doc.percent_complete) {
|
||||||
|
@ -97,7 +97,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if(this.frm.doc.company && !this.frm.doc.amended_from) {
|
if(this.frm.doc.company && !this.frm.doc.amended_from) {
|
||||||
this.frm.script_manager.trigger("company");
|
this.frm.trigger("company");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,7 +295,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
|
|
||||||
if (item.serial_no) {
|
if (item.serial_no) {
|
||||||
if (!item.item_code) {
|
if (!item.item_code) {
|
||||||
this.frm.script_manager.trigger("item_code", cdt, cdn);
|
this.frm.trigger("item_code", cdt, cdn);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var sr_no = [];
|
var sr_no = [];
|
||||||
|
@ -294,7 +294,3 @@ def get_name_with_abbr(name, company):
|
|||||||
parts.append(company_abbr)
|
parts.append(company_abbr)
|
||||||
|
|
||||||
return " - ".join(parts)
|
return " - ".join(parts)
|
||||||
|
|
||||||
def get_company_currency(company):
|
|
||||||
return frappe.local_cache("company_currency", company,
|
|
||||||
lambda: frappe.db.get_value("Company", company, "default_currency"))
|
|
||||||
|
@ -177,6 +177,7 @@ def set_defaults(args):
|
|||||||
selling_settings.cust_master_name = "Customer Name"
|
selling_settings.cust_master_name = "Customer Name"
|
||||||
selling_settings.so_required = "No"
|
selling_settings.so_required = "No"
|
||||||
selling_settings.dn_required = "No"
|
selling_settings.dn_required = "No"
|
||||||
|
selling_settings.allow_multiple_items = 1
|
||||||
selling_settings.save()
|
selling_settings.save()
|
||||||
|
|
||||||
buying_settings = frappe.get_doc("Buying Settings")
|
buying_settings = frappe.get_doc("Buying Settings")
|
||||||
@ -184,6 +185,7 @@ def set_defaults(args):
|
|||||||
buying_settings.po_required = "No"
|
buying_settings.po_required = "No"
|
||||||
buying_settings.pr_required = "No"
|
buying_settings.pr_required = "No"
|
||||||
buying_settings.maintain_same_rate = 1
|
buying_settings.maintain_same_rate = 1
|
||||||
|
buying_settings.allow_multiple_items = 1
|
||||||
buying_settings.save()
|
buying_settings.save()
|
||||||
|
|
||||||
notification_control = frappe.get_doc("Notification Control")
|
notification_control = frappe.get_doc("Notification Control")
|
||||||
|
@ -3,19 +3,10 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _, throw
|
from frappe import _
|
||||||
from frappe.utils import flt
|
from frappe.utils import flt
|
||||||
from frappe.utils import get_datetime_str, nowdate
|
from frappe.utils import get_datetime_str, nowdate
|
||||||
|
|
||||||
def get_company_currency(company):
|
|
||||||
currency = frappe.db.get_value("Company", company, "default_currency", cache=True)
|
|
||||||
if not currency:
|
|
||||||
currency = frappe.db.get_default("currency")
|
|
||||||
if not currency:
|
|
||||||
throw(_('Please specify Default Currency in Company Master and Global Defaults'))
|
|
||||||
|
|
||||||
return currency
|
|
||||||
|
|
||||||
def get_root_of(doctype):
|
def get_root_of(doctype):
|
||||||
"""Get root element of a DocType with a tree structure"""
|
"""Get root element of a DocType with a tree structure"""
|
||||||
result = frappe.db.sql_list("""select name from `tab%s`
|
result = frappe.db.sql_list("""select name from `tab%s`
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
{% include 'erpnext/buying/doctype/purchase_common/purchase_common.js' %};
|
{% include 'erpnext/public/js/controllers/buying.js' %};
|
||||||
|
|
||||||
frappe.ui.form.on('Material Request', {
|
frappe.ui.form.on('Material Request', {
|
||||||
setup: function(frm) {
|
setup: function(frm) {
|
||||||
|
@ -13,7 +13,7 @@ from frappe.model.mapper import get_mapped_doc
|
|||||||
from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty
|
from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty
|
||||||
from erpnext.controllers.buying_controller import BuyingController
|
from erpnext.controllers.buying_controller import BuyingController
|
||||||
from erpnext.manufacturing.doctype.production_order.production_order import get_item_details
|
from erpnext.manufacturing.doctype.production_order.production_order import get_item_details
|
||||||
|
from erpnext.buying.utils import check_for_closed_status, validate_for_items
|
||||||
|
|
||||||
form_grid_templates = {
|
form_grid_templates = {
|
||||||
"items": "templates/form_grid/material_request_grid.html"
|
"items": "templates/form_grid/material_request_grid.html"
|
||||||
@ -72,12 +72,9 @@ class MaterialRequest(BuyingController):
|
|||||||
from erpnext.controllers.status_updater import validate_status
|
from erpnext.controllers.status_updater import validate_status
|
||||||
validate_status(self.status, ["Draft", "Submitted", "Stopped", "Cancelled"])
|
validate_status(self.status, ["Draft", "Submitted", "Stopped", "Cancelled"])
|
||||||
|
|
||||||
pc_obj = frappe.get_doc('Purchase Common')
|
validate_for_items(self)
|
||||||
pc_obj.validate_for_items(self)
|
|
||||||
|
|
||||||
# self.set_title()
|
# self.set_title()
|
||||||
|
|
||||||
|
|
||||||
# self.validate_qty_against_so()
|
# self.validate_qty_against_so()
|
||||||
# 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
|
||||||
@ -112,9 +109,7 @@ class MaterialRequest(BuyingController):
|
|||||||
self.update_requested_qty()
|
self.update_requested_qty()
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
pc_obj = frappe.get_doc('Purchase Common')
|
check_for_closed_status(self.doctype, self.name)
|
||||||
|
|
||||||
pc_obj.check_for_closed_status(self.doctype, self.name)
|
|
||||||
|
|
||||||
self.update_requested_qty()
|
self.update_requested_qty()
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
{% include 'erpnext/buying/doctype/purchase_common/purchase_common.js' %};
|
{% include 'erpnext/public/js/controllers/buying.js' %};
|
||||||
|
|
||||||
frappe.provide("erpnext.stock");
|
frappe.provide("erpnext.stock");
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ from frappe.utils import getdate
|
|||||||
from erpnext.controllers.buying_controller import BuyingController
|
from erpnext.controllers.buying_controller import BuyingController
|
||||||
from erpnext.accounts.utils import get_account_currency
|
from erpnext.accounts.utils import get_account_currency
|
||||||
from frappe.desk.notifications import clear_doctype_notifications
|
from frappe.desk.notifications import clear_doctype_notifications
|
||||||
|
from erpnext.buying.utils import check_for_closed_status, update_last_purchase_rate
|
||||||
|
|
||||||
form_grid_templates = {
|
form_grid_templates = {
|
||||||
"items": "templates/form_grid/item_grid.html"
|
"items": "templates/form_grid/item_grid.html"
|
||||||
@ -56,8 +57,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
self.validate_uom_is_integer("uom", ["qty", "received_qty"])
|
self.validate_uom_is_integer("uom", ["qty", "received_qty"])
|
||||||
self.validate_uom_is_integer("stock_uom", "stock_qty")
|
self.validate_uom_is_integer("stock_uom", "stock_qty")
|
||||||
|
|
||||||
pc_obj = frappe.get_doc('Purchase Common')
|
self.check_for_closed_status()
|
||||||
self.check_for_closed_status(pc_obj)
|
|
||||||
|
|
||||||
if getdate(self.posting_date) > getdate(nowdate()):
|
if getdate(self.posting_date) > getdate(nowdate()):
|
||||||
throw(_("Posting Date cannot be future date"))
|
throw(_("Posting Date cannot be future date"))
|
||||||
@ -98,17 +98,16 @@ class PurchaseReceipt(BuyingController):
|
|||||||
return po_qty, po_warehouse
|
return po_qty, po_warehouse
|
||||||
|
|
||||||
# Check for Closed status
|
# Check for Closed status
|
||||||
def check_for_closed_status(self, pc_obj):
|
def check_for_closed_status(self):
|
||||||
check_list =[]
|
check_list =[]
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
if d.meta.get_field('purchase_order') and d.purchase_order and d.purchase_order not in check_list:
|
if (d.meta.get_field('purchase_order') and d.purchase_order
|
||||||
|
and d.purchase_order not in check_list):
|
||||||
check_list.append(d.purchase_order)
|
check_list.append(d.purchase_order)
|
||||||
pc_obj.check_for_closed_status('Purchase Order', d.purchase_order)
|
check_for_closed_status('Purchase Order', d.purchase_order)
|
||||||
|
|
||||||
# on submit
|
# on submit
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
purchase_controller = frappe.get_doc("Purchase Common")
|
|
||||||
|
|
||||||
# Check for Approving Authority
|
# Check for Approving Authority
|
||||||
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
|
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
|
||||||
self.company, self.base_grand_total)
|
self.company, self.base_grand_total)
|
||||||
@ -120,7 +119,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
self.update_billing_status()
|
self.update_billing_status()
|
||||||
|
|
||||||
if not self.is_return:
|
if not self.is_return:
|
||||||
purchase_controller.update_last_purchase_rate(self, 1)
|
update_last_purchase_rate(self, 1)
|
||||||
|
|
||||||
# Updating stock ledger should always be called after updating prevdoc status,
|
# Updating stock ledger should always be called after updating prevdoc status,
|
||||||
# because updating ordered qty in bin depends upon updated ordered qty in PO
|
# because updating ordered qty in bin depends upon updated ordered qty in PO
|
||||||
@ -140,9 +139,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
frappe.throw(_("Purchase Invoice {0} is already submitted").format(self.submit_rv[0][0]))
|
frappe.throw(_("Purchase Invoice {0} is already submitted").format(self.submit_rv[0][0]))
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
pc_obj = frappe.get_doc('Purchase Common')
|
self.check_for_closed_status()
|
||||||
|
|
||||||
self.check_for_closed_status(pc_obj)
|
|
||||||
# Check if Purchase Invoice has been submitted against current Purchase Order
|
# Check if Purchase Invoice has been submitted against current Purchase Order
|
||||||
submitted = frappe.db.sql("""select t1.name
|
submitted = frappe.db.sql("""select t1.name
|
||||||
from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2
|
from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2
|
||||||
@ -157,7 +154,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
self.update_billing_status()
|
self.update_billing_status()
|
||||||
|
|
||||||
if not self.is_return:
|
if not self.is_return:
|
||||||
pc_obj.update_last_purchase_rate(self, 0)
|
update_last_purchase_rate(self, 0)
|
||||||
|
|
||||||
# Updating stock ledger should always be called after updating prevdoc status,
|
# Updating stock ledger should always be called after updating prevdoc status,
|
||||||
# because updating ordered qty in bin depends upon updated ordered qty in PO
|
# because updating ordered qty in bin depends upon updated ordered qty in PO
|
||||||
@ -170,9 +167,6 @@ class PurchaseReceipt(BuyingController):
|
|||||||
bin = frappe.db.sql("select actual_qty from `tabBin` where item_code = %s and warehouse = %s", (d.rm_item_code, self.supplier_warehouse), as_dict = 1)
|
bin = frappe.db.sql("select actual_qty from `tabBin` where item_code = %s and warehouse = %s", (d.rm_item_code, self.supplier_warehouse), as_dict = 1)
|
||||||
d.current_stock = bin and flt(bin[0]['actual_qty']) or 0
|
d.current_stock = bin and flt(bin[0]['actual_qty']) or 0
|
||||||
|
|
||||||
def get_rate(self,arg):
|
|
||||||
return frappe.get_doc('Purchase Common').get_rate(arg,self)
|
|
||||||
|
|
||||||
def get_gl_entries(self, warehouse_account=None):
|
def get_gl_entries(self, warehouse_account=None):
|
||||||
from erpnext.accounts.general_ledger import process_gl_map
|
from erpnext.accounts.general_ledger import process_gl_map
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import frappe
|
import frappe, erpnext
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import cint, flt, cstr, now
|
from frappe.utils import cint, flt, cstr, now
|
||||||
from erpnext.stock.utils import get_valuation_method
|
from erpnext.stock.utils import get_valuation_method
|
||||||
@ -264,7 +264,8 @@ class update_entries_after(object):
|
|||||||
is_sample_item = self.check_if_sample_item(sle.voucher_type, sle.voucher_detail_no)
|
is_sample_item = self.check_if_sample_item(sle.voucher_type, sle.voucher_detail_no)
|
||||||
if not is_sample_item:
|
if not is_sample_item:
|
||||||
self.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
|
self.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
|
||||||
sle.voucher_type, sle.voucher_no, self.allow_zero_rate)
|
sle.voucher_type, sle.voucher_no, self.allow_zero_rate,
|
||||||
|
currency=erpnext.get_company_currency(sle.company))
|
||||||
|
|
||||||
def get_fifo_values(self, sle):
|
def get_fifo_values(self, sle):
|
||||||
incoming_rate = flt(sle.incoming_rate)
|
incoming_rate = flt(sle.incoming_rate)
|
||||||
@ -292,7 +293,8 @@ class update_entries_after(object):
|
|||||||
is_sample_item = self.check_if_sample_item(sle.voucher_type, sle.voucher_detail_no)
|
is_sample_item = self.check_if_sample_item(sle.voucher_type, sle.voucher_detail_no)
|
||||||
if not is_sample_item:
|
if not is_sample_item:
|
||||||
_rate = get_valuation_rate(sle.item_code, sle.warehouse,
|
_rate = get_valuation_rate(sle.item_code, sle.warehouse,
|
||||||
sle.voucher_type, sle.voucher_no, self.allow_zero_rate)
|
sle.voucher_type, sle.voucher_no, self.allow_zero_rate,
|
||||||
|
currency=erpnext.get_company_currency(sle.company))
|
||||||
else:
|
else:
|
||||||
_rate = 0
|
_rate = 0
|
||||||
|
|
||||||
@ -419,7 +421,8 @@ def get_stock_ledger_entries(previous_sle, operator=None, order="desc", limit=No
|
|||||||
"order": order
|
"order": order
|
||||||
}, previous_sle, as_dict=1, debug=debug)
|
}, previous_sle, as_dict=1, debug=debug)
|
||||||
|
|
||||||
def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no, allow_zero_rate=False):
|
def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no,
|
||||||
|
allow_zero_rate=False, currency=None):
|
||||||
# Get valuation rate from last sle for the same item and warehouse
|
# Get valuation rate from last sle for the same item and warehouse
|
||||||
last_valuation_rate = frappe.db.sql("""select valuation_rate
|
last_valuation_rate = frappe.db.sql("""select valuation_rate
|
||||||
from `tabStock Ledger Entry`
|
from `tabStock Ledger Entry`
|
||||||
@ -441,6 +444,11 @@ def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no, allow_zer
|
|||||||
# syste does not found any SLE, then take valuation rate from Item
|
# syste does not found any SLE, then take valuation rate from Item
|
||||||
valuation_rate = frappe.db.get_value("Item", item_code, "valuation_rate")
|
valuation_rate = frappe.db.get_value("Item", item_code, "valuation_rate")
|
||||||
|
|
||||||
|
if not valuation_rate:
|
||||||
|
# try in price list
|
||||||
|
valuation_rate = frappe.db.get_value('Item Price',
|
||||||
|
dict(item_code=item_code, buying=1, currency=currency), 'price_list_rate')
|
||||||
|
|
||||||
if not allow_zero_rate and not valuation_rate \
|
if not allow_zero_rate and not valuation_rate \
|
||||||
and cint(frappe.db.get_value("Accounts Settings", None, "auto_accounting_for_stock")):
|
and cint(frappe.db.get_value("Accounts Settings", None, "auto_accounting_for_stock")):
|
||||||
frappe.local.message_log = []
|
frappe.local.message_log = []
|
||||||
|