Merge branch 'develop' into gross_profit_issue_v_8
This commit is contained in:
commit
b15d999147
@ -25,6 +25,14 @@ def get_default_currency():
|
||||
if company:
|
||||
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):
|
||||
accounts_settings = frappe.get_doc("Accounts Settings")
|
||||
accounts_settings.auto_accounting_for_stock = enable
|
||||
|
@ -2,13 +2,12 @@
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import frappe, erpnext
|
||||
from frappe import _
|
||||
from frappe.utils import flt, fmt_money, getdate, formatdate
|
||||
from frappe.model.document import Document
|
||||
from erpnext.accounts.party import validate_party_gle_currency, validate_party_frozen_disabled
|
||||
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.exceptions import InvalidAccountCurrency
|
||||
|
||||
@ -19,7 +18,7 @@ class GLEntry(Document):
|
||||
self.flags.ignore_submit_comment = True
|
||||
self.check_mandatory()
|
||||
self.validate_and_set_fiscal_year()
|
||||
|
||||
|
||||
if not self.flags.from_repost:
|
||||
self.pl_must_have_cost_center()
|
||||
self.check_pl_account()
|
||||
@ -32,7 +31,7 @@ class GLEntry(Document):
|
||||
if not from_repost:
|
||||
self.validate_account_details(adv_adj)
|
||||
check_freezing_date(self.posting_date, adv_adj)
|
||||
|
||||
|
||||
validate_frozen_account(self.account, adv_adj)
|
||||
validate_balance_type(self.account, adv_adj)
|
||||
|
||||
@ -56,7 +55,7 @@ class GLEntry(Document):
|
||||
elif account_type == "Payable":
|
||||
frappe.throw(_("{0} {1}: Supplier is required against Payable account {2}")
|
||||
.format(self.voucher_type, self.voucher_no, self.account))
|
||||
|
||||
|
||||
# Zero value transaction is not allowed
|
||||
if not (flt(self.debit) or flt(self.credit)):
|
||||
frappe.throw(_("{0} {1}: Either debit or credit amount is required for {2}")
|
||||
@ -116,7 +115,7 @@ class GLEntry(Document):
|
||||
validate_party_frozen_disabled(self.party_type, self.party)
|
||||
|
||||
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)
|
||||
|
||||
if not self.account_currency:
|
||||
@ -124,7 +123,7 @@ class GLEntry(Document):
|
||||
|
||||
if account_currency != self.account_currency:
|
||||
frappe.throw(_("{0} {1}: Accounting Entry for {2} can only be made in currency: {3}")
|
||||
.format(self.voucher_type, self.voucher_no, self.account,
|
||||
.format(self.voucher_type, self.voucher_no, self.account,
|
||||
(account_currency or company_currency)), InvalidAccountCurrency)
|
||||
|
||||
if self.party_type and self.party:
|
||||
|
@ -2,12 +2,11 @@
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe, json
|
||||
import frappe, erpnext, json
|
||||
from frappe.utils import cstr, flt, fmt_money, formatdate
|
||||
from frappe import msgprint, _, scrub
|
||||
from erpnext.controllers.accounts_controller import AccountsController
|
||||
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.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
|
||||
from erpnext.hr.doctype.employee_loan.employee_loan import update_disbursement_status
|
||||
@ -325,11 +324,11 @@ class JournalEntry(AccountsController):
|
||||
if d.account_currency == self.company_currency:
|
||||
d.exchange_rate = 1
|
||||
elif not d.exchange_rate or d.exchange_rate == 1 or \
|
||||
(d.reference_type in ("Sales Invoice", "Purchase Invoice")
|
||||
(d.reference_type in ("Sales Invoice", "Purchase Invoice")
|
||||
and d.reference_name and self.posting_date):
|
||||
|
||||
|
||||
# Modified to include the posting date for which to retreive the exchange rate
|
||||
d.exchange_rate = get_exchange_rate(self.posting_date, d.account, d.account_currency,
|
||||
d.exchange_rate = get_exchange_rate(self.posting_date, d.account, d.account_currency,
|
||||
self.company, d.reference_type, d.reference_name, d.debit, d.credit, d.exchange_rate)
|
||||
|
||||
if not d.exchange_rate:
|
||||
@ -656,7 +655,7 @@ def get_payment_entry(ref_doc, args):
|
||||
if args.get("party_account"):
|
||||
# Modified to include the posting date for which the exchange rate is required.
|
||||
# Assumed to be the posting date in the reference document
|
||||
exchange_rate = get_exchange_rate(ref_doc.get("posting_date") or ref_doc.get("transaction_date"),
|
||||
exchange_rate = get_exchange_rate(ref_doc.get("posting_date") or ref_doc.get("transaction_date"),
|
||||
args.get("party_account"), args.get("party_account_currency"),
|
||||
ref_doc.company, ref_doc.doctype, ref_doc.name)
|
||||
|
||||
@ -692,8 +691,8 @@ def get_payment_entry(ref_doc, args):
|
||||
bank_row.update(bank_account)
|
||||
# Modified to include the posting date for which the exchange rate is required.
|
||||
# Assumed to be the posting date of the reference date
|
||||
bank_row.exchange_rate = get_exchange_rate(ref_doc.get("posting_date")
|
||||
or ref_doc.get("transaction_date"), bank_account["account"],
|
||||
bank_row.exchange_rate = get_exchange_rate(ref_doc.get("posting_date")
|
||||
or ref_doc.get("transaction_date"), bank_account["account"],
|
||||
bank_account["account_currency"], ref_doc.company)
|
||||
|
||||
bank_row.cost_center = cost_center
|
||||
@ -746,7 +745,7 @@ def get_outstanding(args):
|
||||
if isinstance(args, basestring):
|
||||
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":
|
||||
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"):
|
||||
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)
|
||||
|
||||
if not account_details:
|
||||
@ -853,7 +852,7 @@ def get_exchange_rate(posting_date, account=None, account_currency=None, company
|
||||
if not 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 reference_type in ("Sales Invoice", "Purchase Invoice") and reference_name:
|
||||
|
@ -2,8 +2,7 @@
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
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({
|
||||
setup: function(doc) {
|
||||
|
@ -2,10 +2,9 @@
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import frappe, erpnext
|
||||
from frappe.utils import cint, formatdate, flt, getdate
|
||||
from frappe import _, throw
|
||||
from erpnext.setup.utils import get_company_currency
|
||||
import frappe.defaults
|
||||
|
||||
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.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.buying.utils import check_for_closed_status
|
||||
|
||||
form_grid_templates = {
|
||||
"items": "templates/form_grid/item_grid.html"
|
||||
@ -93,7 +93,7 @@ class PurchaseInvoice(BuyingController):
|
||||
super(PurchaseInvoice, self).set_missing_values(for_validate)
|
||||
|
||||
def check_conversion_rate(self):
|
||||
default_currency = get_company_currency(self.company)
|
||||
default_currency = erpnext.get_company_currency(self.company)
|
||||
if not default_currency:
|
||||
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):
|
||||
@ -113,12 +113,11 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
def check_for_closed_status(self):
|
||||
check_list = []
|
||||
pc_obj = frappe.get_doc('Purchase Common')
|
||||
|
||||
for d in self.get('items'):
|
||||
if d.purchase_order and not d.purchase_order in check_list and not d.purchase_receipt:
|
||||
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):
|
||||
super(PurchaseInvoice, self).validate_with_previous_doc({
|
||||
|
@ -4,11 +4,10 @@
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import frappe, erpnext
|
||||
from frappe import _, msgprint, throw
|
||||
from frappe.utils import flt, fmt_money
|
||||
from frappe.model.document import Document
|
||||
from erpnext.setup.utils import get_company_currency
|
||||
|
||||
class OverlappingConditionError(frappe.ValidationError): pass
|
||||
class FromGreaterThanToError(frappe.ValidationError): pass
|
||||
@ -77,7 +76,7 @@ class ShippingRule(Document):
|
||||
overlaps.append([d1, d2])
|
||||
|
||||
if overlaps:
|
||||
company_currency = get_company_currency(self.company)
|
||||
company_currency = erpnext.get_company_currency(self.company)
|
||||
msgprint(_("Overlapping conditions found between:"))
|
||||
messages = []
|
||||
for d1, d2 in overlaps:
|
||||
|
@ -151,13 +151,6 @@ def set_account_and_due_date(party, account, party_type, company, posting_date,
|
||||
}
|
||||
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()
|
||||
def get_party_account(party_type, party, company):
|
||||
"""Returns the account for the given `party`.
|
||||
|
@ -12,7 +12,7 @@ from frappe.utils import flt
|
||||
|
||||
def execute(filters=None):
|
||||
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)
|
||||
|
||||
@ -50,7 +50,7 @@ def execute(filters=None):
|
||||
for col in group_wise_columns.get(scrub(filters.group_by)):
|
||||
row.append(src.get(col))
|
||||
|
||||
row.append(company_currency)
|
||||
row.append(filters.currency)
|
||||
data.append(row)
|
||||
|
||||
return columns, data
|
||||
@ -224,8 +224,11 @@ class GrossProfitGenerator(object):
|
||||
else:
|
||||
average_buying_rate = get_incoming_rate(row)
|
||||
if not average_buying_rate:
|
||||
average_buying_rate = get_valuation_rate(item_code, row.warehouse, row.parenttype, row.parent, allow_zero_rate=True)
|
||||
self.average_buying_rate[item_code] = average_buying_rate
|
||||
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
|
||||
|
||||
return self.average_buying_rate[item_code]
|
||||
|
||||
@ -235,7 +238,7 @@ class GrossProfitGenerator(object):
|
||||
select (a.base_rate / a.conversion_factor)
|
||||
from `tabPurchase Invoice Item` a
|
||||
where a.item_code = %s and a.docstatus=1
|
||||
and modified <= %s
|
||||
and modified <= %s
|
||||
order by a.modified desc limit 1""", (item_code,self.filters.to_date))
|
||||
else:
|
||||
last_purchase_rate = frappe.db.sql("""
|
||||
@ -253,7 +256,7 @@ class GrossProfitGenerator(object):
|
||||
conditions += " and posting_date >= %(from_date)s"
|
||||
if self.filters.to_date:
|
||||
conditions += " and posting_date <= %(to_date)s"
|
||||
|
||||
|
||||
if self.filters.group_by=="Sales Person":
|
||||
sales_person_cols = ", sales.sales_person, sales.allocated_amount, sales.incentives"
|
||||
sales_team_table = "left join `tabSales Team` sales on sales.parent = `tabSales Invoice`.name"
|
||||
@ -269,7 +272,7 @@ class GrossProfitGenerator(object):
|
||||
`tabSales Invoice Item`.dn_detail, `tabSales Invoice Item`.delivery_note, `tabSales Invoice Item`.stock_qty as qty,
|
||||
`tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount, `tabSales Invoice Item`.name as "item_row"
|
||||
{sales_person_cols}
|
||||
from
|
||||
from
|
||||
`tabSales Invoice`
|
||||
inner join `tabSales Invoice Item` on `tabSales Invoice Item`.parent = `tabSales Invoice`.name
|
||||
{sales_team_table}
|
||||
@ -277,7 +280,7 @@ class GrossProfitGenerator(object):
|
||||
`tabSales Invoice`.docstatus = 1 and `tabSales Invoice`.is_return != 1 {conditions} {match_cond}
|
||||
order by
|
||||
`tabSales Invoice`.posting_date desc, `tabSales Invoice`.posting_time desc"""
|
||||
.format(conditions=conditions, sales_person_cols=sales_person_cols,
|
||||
.format(conditions=conditions, sales_person_cols=sales_person_cols,
|
||||
sales_team_table=sales_team_table, match_cond = get_match_cond('Sales Invoice')), self.filters, as_dict=1)
|
||||
|
||||
def load_stock_ledger_entries(self):
|
||||
|
@ -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");
|
||||
|
||||
{% include 'erpnext/buying/doctype/purchase_common/purchase_common.js' %};
|
||||
{% include 'erpnext/public/js/controllers/buying.js' %};
|
||||
|
||||
frappe.ui.form.on("Purchase Order", {
|
||||
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.stock_balance import update_bin_qty, get_ordered_qty
|
||||
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 = {
|
||||
@ -37,9 +39,8 @@ class PurchaseOrder(BuyingController):
|
||||
super(PurchaseOrder, self).validate()
|
||||
|
||||
self.set_status()
|
||||
pc_obj = frappe.get_doc('Purchase Common')
|
||||
pc_obj.validate_for_items(self)
|
||||
self.check_for_closed_status(pc_obj)
|
||||
validate_for_items(self)
|
||||
self.check_for_closed_status()
|
||||
|
||||
self.validate_uom_is_integer("uom", "qty")
|
||||
self.validate_uom_is_integer("stock_uom", ["qty", "required_qty"])
|
||||
@ -111,12 +112,12 @@ class PurchaseOrder(BuyingController):
|
||||
= d.rate = item_last_purchase_rate
|
||||
|
||||
# Check for Closed status
|
||||
def check_for_closed_status(self, pc_obj):
|
||||
def check_for_closed_status(self):
|
||||
check_list =[]
|
||||
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:
|
||||
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):
|
||||
material_request_map = {}
|
||||
@ -155,7 +156,7 @@ class PurchaseOrder(BuyingController):
|
||||
if date_diff and date_diff[0][0]:
|
||||
msgprint(_("{0} {1} has been modified. Please refresh.").format(self.doctype, self.name),
|
||||
raise_exception=True)
|
||||
|
||||
|
||||
def update_status(self, status):
|
||||
self.check_modified_date()
|
||||
self.set_status(update=True, status=status)
|
||||
@ -168,8 +169,6 @@ class PurchaseOrder(BuyingController):
|
||||
if self.is_against_so():
|
||||
self.update_status_updater()
|
||||
|
||||
purchase_controller = frappe.get_doc("Purchase Common")
|
||||
|
||||
self.update_prevdoc_status()
|
||||
self.update_requested_qty()
|
||||
self.update_ordered_qty()
|
||||
@ -177,7 +176,7 @@ class PurchaseOrder(BuyingController):
|
||||
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
|
||||
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):
|
||||
if self.is_against_so():
|
||||
@ -186,8 +185,7 @@ class PurchaseOrder(BuyingController):
|
||||
if self.has_drop_ship_item():
|
||||
self.update_delivered_qty_in_sales_order()
|
||||
|
||||
pc_obj = frappe.get_doc('Purchase Common')
|
||||
self.check_for_closed_status(pc_obj)
|
||||
self.check_for_closed_status()
|
||||
|
||||
frappe.db.set(self,'status','Cancelled')
|
||||
|
||||
@ -197,7 +195,7 @@ class PurchaseOrder(BuyingController):
|
||||
self.update_requested_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):
|
||||
pass
|
||||
@ -303,7 +301,7 @@ def make_purchase_invoice(source_name, target_doc=None):
|
||||
target.amount = flt(obj.amount) - flt(obj.billed_amt)
|
||||
target.base_amount = target.amount * flt(source_parent.conversion_rate)
|
||||
target.qty = target.amount / flt(obj.rate) if (flt(obj.rate) and flt(obj.billed_amt)) else flt(obj.qty)
|
||||
|
||||
|
||||
item = frappe.db.get_value("Item", target.item_code, ["item_group", "buying_cost_center"], as_dict=1)
|
||||
target.cost_center = frappe.db.get_value("Project", obj.project, "cost_center") \
|
||||
or item.buying_cost_center \
|
||||
|
@ -2,7 +2,7 @@
|
||||
// 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')
|
||||
|
||||
|
@ -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.stock.doctype.material_request.material_request import set_missing_values
|
||||
from erpnext.controllers.buying_controller import BuyingController
|
||||
from erpnext.buying.utils import validate_for_items
|
||||
|
||||
STANDARD_USERS = ("Guest", "Administrator")
|
||||
|
||||
class RequestforQuotation(BuyingController):
|
||||
def validate(self):
|
||||
self.validate_duplicate_supplier()
|
||||
self.validate_common()
|
||||
validate_for_items(self)
|
||||
self.update_email_id()
|
||||
|
||||
def validate_duplicate_supplier(self):
|
||||
@ -28,10 +29,6 @@ class RequestforQuotation(BuyingController):
|
||||
if len(supplier_list) != len(set(supplier_list)):
|
||||
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):
|
||||
for rfq_supplier in self.suppliers:
|
||||
if not rfq_supplier.email_id:
|
||||
@ -130,7 +127,7 @@ class RequestforQuotation(BuyingController):
|
||||
self.send_email(data, sender, subject, message, attachments)
|
||||
|
||||
def send_email(self, data, sender, subject, message, attachments):
|
||||
make(subject = subject, content=message,recipients=data.email_id,
|
||||
make(subject = subject, content=message,recipients=data.email_id,
|
||||
sender=sender,attachments = attachments, send_email=True,
|
||||
doctype=self.doctype, name=self.name)["name"]
|
||||
|
||||
@ -250,26 +247,26 @@ def get_rfq_doc(doctype, name, supplier_idx):
|
||||
args = doc.get('suppliers')[cint(supplier_idx) - 1]
|
||||
doc.update_supplier_part_no(args)
|
||||
return doc
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_item_from_material_requests_based_on_supplier(source_name, target_doc = None):
|
||||
mr_items_list = frappe.db.sql("""
|
||||
SELECT
|
||||
mr.name, mr_item.item_code
|
||||
FROM
|
||||
`tabItem` as item,
|
||||
`tabItem Supplier` as item_supp,
|
||||
`tabMaterial Request Item` as mr_item,
|
||||
`tabMaterial Request` as mr
|
||||
WHERE item_supp.supplier = %(supplier)s
|
||||
AND item.name = item_supp.parent
|
||||
AND mr_item.parent = mr.name
|
||||
AND mr_item.item_code = item.name
|
||||
AND mr.status != "Stopped"
|
||||
AND mr.material_request_type = "Purchase"
|
||||
AND mr.docstatus = 1
|
||||
`tabItem` as item,
|
||||
`tabItem Supplier` as item_supp,
|
||||
`tabMaterial Request Item` as mr_item,
|
||||
`tabMaterial Request` as mr
|
||||
WHERE item_supp.supplier = %(supplier)s
|
||||
AND item.name = item_supp.parent
|
||||
AND mr_item.parent = mr.name
|
||||
AND mr_item.item_code = item.name
|
||||
AND mr.status != "Stopped"
|
||||
AND mr.material_request_type = "Purchase"
|
||||
AND mr.docstatus = 1
|
||||
AND mr.per_ordered < 99.99""", {"supplier": source_name}, as_dict=1)
|
||||
|
||||
|
||||
material_requests = {}
|
||||
for d in mr_items_list:
|
||||
material_requests.setdefault(d.name, []).append(d.item_code)
|
||||
@ -293,5 +290,5 @@ def get_item_from_material_requests_based_on_supplier(source_name, target_doc =
|
||||
]
|
||||
}
|
||||
}, target_doc)
|
||||
|
||||
|
||||
return target_doc
|
||||
|
@ -2,7 +2,7 @@
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
// 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', {
|
||||
setup: function() {
|
||||
|
@ -8,6 +8,7 @@ from frappe.utils import flt
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
|
||||
from erpnext.controllers.buying_controller import BuyingController
|
||||
from erpnext.buying.utils import validate_for_items
|
||||
|
||||
form_grid_templates = {
|
||||
"items": "templates/form_grid/item_grid.html"
|
||||
@ -24,7 +25,7 @@ class SupplierQuotation(BuyingController):
|
||||
validate_status(self.status, ["Draft", "Submitted", "Stopped",
|
||||
"Cancelled"])
|
||||
|
||||
self.validate_common()
|
||||
validate_for_items(self)
|
||||
self.validate_with_previous_doc()
|
||||
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):
|
||||
from erpnext.controllers.website_list_for_contact import get_list_context
|
||||
list_context = get_list_context(context)
|
||||
|
80
erpnext/buying/utils.py
Normal file
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
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import frappe, erpnext
|
||||
from frappe import _, throw
|
||||
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.utilities.transaction_base import TransactionBase
|
||||
from erpnext.controllers.recurring_document import convert_to_recurring, validate_recurring_document
|
||||
@ -22,7 +22,7 @@ class AccountsController(TransactionBase):
|
||||
@property
|
||||
def company_currency(self):
|
||||
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
|
||||
|
||||
|
@ -6,9 +6,10 @@ import frappe
|
||||
from frappe import _, msgprint
|
||||
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.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
|
||||
|
||||
@ -40,9 +41,7 @@ class BuyingController(StockController):
|
||||
# self.validate_purchase_return()
|
||||
self.validate_rejected_warehouse()
|
||||
self.validate_accepted_rejected_qty()
|
||||
|
||||
pc_obj = frappe.get_doc('Purchase Common')
|
||||
pc_obj.validate_for_items(self)
|
||||
validate_for_items(self)
|
||||
|
||||
#sub-contracting
|
||||
self.validate_for_subcontracting()
|
||||
@ -88,9 +87,8 @@ class BuyingController(StockController):
|
||||
|
||||
def set_total_in_words(self):
|
||||
from frappe.utils import money_in_words
|
||||
company_currency = get_company_currency(self.company)
|
||||
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"):
|
||||
self.in_words = money_in_words(self.grand_total, self.currency)
|
||||
|
||||
@ -225,9 +223,8 @@ class BuyingController(StockController):
|
||||
"serial_no": rm.serial_no
|
||||
})
|
||||
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,
|
||||
self.doctype, self.name)
|
||||
rm.rate = get_valuation_rate(bom_item.item_code, self.supplier_warehouse,
|
||||
self.doctype, self.name, currency=self.company_currency)
|
||||
else:
|
||||
rm.rate = bom_item.rate
|
||||
|
||||
|
@ -4,11 +4,9 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.utils import cint, flt, cstr, comma_or
|
||||
from erpnext.setup.utils import get_company_currency
|
||||
from frappe import _, throw
|
||||
from erpnext.stock.get_item_details import get_bin_details
|
||||
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.controllers.stock_controller import StockController
|
||||
@ -113,13 +111,11 @@ class SellingController(StockController):
|
||||
|
||||
def set_total_in_words(self):
|
||||
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"))
|
||||
|
||||
if self.meta.get_field("base_in_words"):
|
||||
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"):
|
||||
self.in_words = money_in_words(disable_rounded_total and
|
||||
abs(self.grand_total) or abs(self.rounded_total), self.currency)
|
||||
@ -170,7 +166,7 @@ class SellingController(StockController):
|
||||
if d.meta.get_field("stock_qty"):
|
||||
if not d.conversion_factor:
|
||||
frappe.throw(_("Row {0}: Conversion Factor is mandatory").format(d.idx))
|
||||
d.stock_qty = flt(d.qty) * flt(d.conversion_factor)
|
||||
d.stock_qty = flt(d.qty) * flt(d.conversion_factor)
|
||||
|
||||
def validate_selling_price(self):
|
||||
def throw_message(item_name, rate, ref_rate_field):
|
||||
|
@ -54,9 +54,9 @@ class StockController(AccountsController):
|
||||
|
||||
self.check_expense_account(item_row)
|
||||
|
||||
# If item is not a sample item
|
||||
# If item is not a sample item
|
||||
# and ( valuation rate not mentioned in an incoming entry
|
||||
# or incoming entry not found while delivering the item),
|
||||
# or incoming entry not found while delivering the item),
|
||||
# try to pick valuation rate from previous sle or Item master and update in SLE
|
||||
# Otherwise, throw an exception
|
||||
|
||||
@ -96,25 +96,25 @@ class StockController(AccountsController):
|
||||
return process_gl_map(gl_list)
|
||||
|
||||
def update_stock_ledger_entries(self, sle):
|
||||
sle.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
|
||||
self.doctype, self.name)
|
||||
sle.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
|
||||
self.doctype, self.name, currency=self.company_currency)
|
||||
|
||||
sle.stock_value = flt(sle.qty_after_transaction) * flt(sle.valuation_rate)
|
||||
sle.stock_value_difference = flt(sle.actual_qty) * flt(sle.valuation_rate)
|
||||
|
||||
|
||||
if sle.name:
|
||||
frappe.db.sql("""
|
||||
update
|
||||
`tabStock Ledger Entry`
|
||||
set
|
||||
update
|
||||
`tabStock Ledger Entry`
|
||||
set
|
||||
stock_value = %(stock_value)s,
|
||||
valuation_rate = %(valuation_rate)s,
|
||||
stock_value_difference = %(stock_value_difference)s
|
||||
where
|
||||
valuation_rate = %(valuation_rate)s,
|
||||
stock_value_difference = %(stock_value_difference)s
|
||||
where
|
||||
name = %(name)s""", (sle))
|
||||
|
||||
|
||||
return sle
|
||||
|
||||
|
||||
def get_voucher_details(self, default_expense_account, default_cost_center, sle_map):
|
||||
if self.doctype == "Stock Reconciliation":
|
||||
return [frappe._dict({ "name": voucher_detail_no, "expense_account": default_expense_account,
|
||||
@ -163,9 +163,9 @@ class StockController(AccountsController):
|
||||
def get_stock_ledger_details(self):
|
||||
stock_ledger = {}
|
||||
stock_ledger_entries = frappe.db.sql("""
|
||||
select
|
||||
select
|
||||
name, warehouse, stock_value_difference, valuation_rate,
|
||||
voucher_detail_no, item_code, posting_date, posting_time,
|
||||
voucher_detail_no, item_code, posting_date, posting_time,
|
||||
actual_qty, qty_after_transaction
|
||||
from
|
||||
`tabStock Ledger Entry`
|
||||
|
@ -3,10 +3,9 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import json
|
||||
import frappe
|
||||
import frappe, erpnext
|
||||
from frappe import _, scrub
|
||||
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, \
|
||||
validate_taxes_and_charges, validate_inclusive_tax
|
||||
|
||||
@ -38,7 +37,7 @@ class calculate_taxes_and_totals(object):
|
||||
|
||||
def validate_conversion_rate(self):
|
||||
# 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:
|
||||
self.doc.currency = company_currency
|
||||
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.currency, self.doc.precision("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 = \
|
||||
round_based_on_smallest_currency_fraction(self.doc.base_grand_total,
|
||||
|
@ -194,11 +194,12 @@ def make_quotation(source_name, target_doc=None):
|
||||
quotation.transaction_date)
|
||||
|
||||
quotation.conversion_rate = exchange_rate
|
||||
|
||||
|
||||
# get default taxes
|
||||
taxes = get_default_taxes_and_charges("Sales Taxes and Charges Template")
|
||||
quotation.extend("taxes", taxes)
|
||||
|
||||
if taxes:
|
||||
quotation.extend("taxes", taxes)
|
||||
|
||||
quotation.run_method("set_missing_values")
|
||||
quotation.run_method("calculate_taxes_and_totals")
|
||||
|
||||
|
@ -63,6 +63,10 @@ def complete_setup(domain='Manufacturing'):
|
||||
"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():
|
||||
# home page should always be "start"
|
||||
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.create_salary_slips()
|
||||
process_payroll.submit_salary_slips()
|
||||
process_payroll.make_journal_entry(reference_date=frappe.flags.current_date,
|
||||
reference_number=random_string(10))
|
||||
process_payroll.make_accural_jv_entry()
|
||||
# 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.create_salary_slips()
|
||||
process_payroll.submit_salary_slips()
|
||||
process_payroll.make_journal_entry(reference_date=frappe.flags.current_date,
|
||||
reference_number=random_string(10))
|
||||
process_payroll.make_accural_jv_entry()
|
||||
# process_payroll.make_journal_entry(reference_date=frappe.flags.current_date,
|
||||
# reference_number=random_string(10))
|
||||
|
||||
if frappe.db.get_global('demo_hr_user'):
|
||||
make_timesheet_records()
|
||||
|
@ -5,7 +5,7 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe import _
|
||||
from frappe.model.naming import append_number_if_name_exists
|
||||
|
||||
class SalaryComponent(Document):
|
||||
def validate(self):
|
||||
@ -13,12 +13,10 @@ class SalaryComponent(Document):
|
||||
|
||||
def validate_abbr(self):
|
||||
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()
|
||||
|
||||
if self.get('__islocal') and len(self.salary_component_abbr) > 5:
|
||||
frappe.throw(_("Abbreviation cannot have more than 5 characters"))
|
||||
|
||||
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))
|
||||
self.salary_component_abbr = append_number_if_name_exists('Salary Component',
|
||||
self.salary_component_abbr, 'salary_component_abbr', separator='_')
|
@ -2,13 +2,12 @@
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
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.model.naming import make_autoname
|
||||
|
||||
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.employee.employee import get_holiday_list_for_employee
|
||||
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:
|
||||
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)
|
||||
|
||||
if frappe.db.get_single_value("HR Settings", "max_working_hours_against_timesheet"):
|
||||
@ -348,7 +347,7 @@ class SalarySlip(TransactionBase):
|
||||
|
||||
self.sum_components('earnings', 'gross_pay')
|
||||
self.sum_components('deductions', 'total_deduction')
|
||||
|
||||
|
||||
self.set_loan_repayment()
|
||||
|
||||
self.net_pay = flt(self.gross_pay) - (flt(self.total_deduction) + flt(self.total_loan_repayment))
|
||||
@ -356,11 +355,11 @@ class SalarySlip(TransactionBase):
|
||||
self.precision("net_pay") if disable_rounded_total else 0)
|
||||
|
||||
def set_loan_repayment(self):
|
||||
employee_loan = frappe.db.sql("""select sum(principal_amount) as principal_amount, sum(interest_amount) as interest_amount,
|
||||
employee_loan = frappe.db.sql("""select sum(principal_amount) as principal_amount, sum(interest_amount) as interest_amount,
|
||||
sum(total_payment) as total_loan_repayment from `tabRepayment Schedule`
|
||||
where payment_date between %s and %s and parent in (select name from `tabEmployee Loan`
|
||||
where employee = %s and repay_from_salary = 1 and docstatus = 1)""",
|
||||
(self.start_date, self.end_date, self.employee), as_dict=True)
|
||||
(self.start_date, self.end_date, self.employee), as_dict=True)
|
||||
if employee_loan:
|
||||
self.principal_amount = employee_loan[0].principal_amount
|
||||
self.interest_amount = employee_loan[0].interest_amount
|
||||
|
@ -381,4 +381,5 @@ erpnext.patches.v7_2.move_dates_from_salary_structure_to_employee
|
||||
erpnext.patches.v7_2.make_all_assessment_group
|
||||
erpnext.patches.v8_0.manufacturer_childtable_migrate
|
||||
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')
|
@ -113,7 +113,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
frappe.model.round_floats_in(item, ["qty", "received_qty"]);
|
||||
|
||||
if(!doc.is_return && this.validate_negative_quantity(cdt, cdn, item, ["qty", "received_qty"])){ return }
|
||||
|
||||
|
||||
if(!item.rejected_qty && item.qty) {
|
||||
item.received_qty = item.qty;
|
||||
}
|
||||
@ -138,14 +138,14 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
frappe.model.round_floats_in(item, ["received_qty", "rejected_qty"]);
|
||||
|
||||
if(!doc.is_return && this.validate_negative_quantity(cdt, cdn, item, ["received_qty", "rejected_qty"])){ return }
|
||||
|
||||
|
||||
item.qty = flt(item.received_qty - item.rejected_qty, precision("qty", item));
|
||||
this.qty(doc, cdt, cdn);
|
||||
},
|
||||
|
||||
validate_negative_quantity: function(cdt, cdn, item, fieldnames){
|
||||
if(!item || !fieldnames) { return }
|
||||
|
||||
|
||||
var is_negative_qty = false;
|
||||
for(var i = 0; i<fieldnames.length; i++) {
|
||||
if(item[fieldnames[i]] < 0){
|
||||
@ -219,12 +219,12 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
my_items.push(cur_frm.doc.items[i].item_code);
|
||||
}
|
||||
}
|
||||
frappe.call({
|
||||
frappe.call({
|
||||
method: "erpnext.buying.doctype.purchase_common.purchase_common.get_linked_material_requests",
|
||||
args:{
|
||||
items: my_items
|
||||
},
|
||||
callback: function(r) {
|
||||
items: my_items
|
||||
},
|
||||
callback: function(r) {
|
||||
var i = 0;
|
||||
var item_length = cur_frm.doc.items.length;
|
||||
while (i < item_length) {
|
||||
@ -239,32 +239,32 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
d.qty = d.qty - my_qty;
|
||||
cur_frm.doc.items[i].stock_qty = my_qty*cur_frm.doc.items[i].conversion_factor;
|
||||
cur_frm.doc.items[i].qty = my_qty;
|
||||
|
||||
|
||||
frappe.msgprint("Assigning " + d.mr_name + " to " + d.item_code + " (row " + cur_frm.doc.items[i].idx + ")");
|
||||
if (qty > 0)
|
||||
{
|
||||
frappe.msgprint("Splitting " + qty + " units of " + d.item_code);
|
||||
var newrow = frappe.model.add_child(cur_frm.doc, cur_frm.doc.items[i].doctype, "items");
|
||||
item_length++;
|
||||
|
||||
|
||||
for (key in cur_frm.doc.items[i])
|
||||
{
|
||||
newrow[key] = cur_frm.doc.items[i][key];
|
||||
}
|
||||
|
||||
|
||||
newrow.idx = item_length;
|
||||
newrow["stock_qty"] = newrow.conversion_factor*qty;
|
||||
newrow["qty"] = qty;
|
||||
|
||||
|
||||
newrow["material_request"] = "";
|
||||
newrow["material_request_item"] = "";
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
i++;
|
||||
}
|
@ -123,7 +123,7 @@ class Company(Document):
|
||||
{"company": self.name, "account_type": "Receivable", "is_group": 0}))
|
||||
frappe.db.set(self, "default_payable_account", frappe.db.get_value("Account",
|
||||
{"company": self.name, "account_type": "Payable", "is_group": 0}))
|
||||
|
||||
|
||||
def validate_coa_input(self):
|
||||
if self.create_chart_of_accounts_based_on == "Existing Company":
|
||||
self.chart_of_accounts = None
|
||||
@ -294,7 +294,3 @@ def get_name_with_abbr(name, company):
|
||||
parts.append(company_abbr)
|
||||
|
||||
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.so_required = "No"
|
||||
selling_settings.dn_required = "No"
|
||||
selling_settings.allow_multiple_items = 1
|
||||
selling_settings.save()
|
||||
|
||||
buying_settings = frappe.get_doc("Buying Settings")
|
||||
@ -184,6 +185,7 @@ def set_defaults(args):
|
||||
buying_settings.po_required = "No"
|
||||
buying_settings.pr_required = "No"
|
||||
buying_settings.maintain_same_rate = 1
|
||||
buying_settings.allow_multiple_items = 1
|
||||
buying_settings.save()
|
||||
|
||||
notification_control = frappe.get_doc("Notification Control")
|
||||
|
@ -3,19 +3,10 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _, throw
|
||||
from frappe import _
|
||||
from frappe.utils import flt
|
||||
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):
|
||||
"""Get root element of a DocType with a tree structure"""
|
||||
result = frappe.db.sql_list("""select name from `tab%s`
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// 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', {
|
||||
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.controllers.buying_controller import BuyingController
|
||||
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 = {
|
||||
"items": "templates/form_grid/material_request_grid.html"
|
||||
@ -72,12 +72,9 @@ class MaterialRequest(BuyingController):
|
||||
from erpnext.controllers.status_updater import validate_status
|
||||
validate_status(self.status, ["Draft", "Submitted", "Stopped", "Cancelled"])
|
||||
|
||||
pc_obj = frappe.get_doc('Purchase Common')
|
||||
pc_obj.validate_for_items(self)
|
||||
validate_for_items(self)
|
||||
|
||||
# self.set_title()
|
||||
|
||||
|
||||
# self.validate_qty_against_so()
|
||||
# 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
|
||||
@ -112,9 +109,7 @@ class MaterialRequest(BuyingController):
|
||||
self.update_requested_qty()
|
||||
|
||||
def on_cancel(self):
|
||||
pc_obj = frappe.get_doc('Purchase Common')
|
||||
|
||||
pc_obj.check_for_closed_status(self.doctype, self.name)
|
||||
check_for_closed_status(self.doctype, self.name)
|
||||
|
||||
self.update_requested_qty()
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// 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");
|
||||
|
||||
|
@ -12,6 +12,7 @@ from frappe.utils import getdate
|
||||
from erpnext.controllers.buying_controller import BuyingController
|
||||
from erpnext.accounts.utils import get_account_currency
|
||||
from frappe.desk.notifications import clear_doctype_notifications
|
||||
from erpnext.buying.utils import check_for_closed_status, update_last_purchase_rate
|
||||
|
||||
form_grid_templates = {
|
||||
"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("stock_uom", "stock_qty")
|
||||
|
||||
pc_obj = frappe.get_doc('Purchase Common')
|
||||
self.check_for_closed_status(pc_obj)
|
||||
self.check_for_closed_status()
|
||||
|
||||
if getdate(self.posting_date) > getdate(nowdate()):
|
||||
throw(_("Posting Date cannot be future date"))
|
||||
@ -98,17 +98,16 @@ class PurchaseReceipt(BuyingController):
|
||||
return po_qty, po_warehouse
|
||||
|
||||
# Check for Closed status
|
||||
def check_for_closed_status(self, pc_obj):
|
||||
def check_for_closed_status(self):
|
||||
check_list =[]
|
||||
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)
|
||||
pc_obj.check_for_closed_status('Purchase Order', d.purchase_order)
|
||||
check_for_closed_status('Purchase Order', d.purchase_order)
|
||||
|
||||
# on submit
|
||||
def on_submit(self):
|
||||
purchase_controller = frappe.get_doc("Purchase Common")
|
||||
|
||||
# Check for Approving Authority
|
||||
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
|
||||
self.company, self.base_grand_total)
|
||||
@ -120,7 +119,7 @@ class PurchaseReceipt(BuyingController):
|
||||
self.update_billing_status()
|
||||
|
||||
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,
|
||||
# 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]))
|
||||
|
||||
def on_cancel(self):
|
||||
pc_obj = frappe.get_doc('Purchase Common')
|
||||
|
||||
self.check_for_closed_status(pc_obj)
|
||||
self.check_for_closed_status()
|
||||
# Check if Purchase Invoice has been submitted against current Purchase Order
|
||||
submitted = frappe.db.sql("""select t1.name
|
||||
from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2
|
||||
@ -157,7 +154,7 @@ class PurchaseReceipt(BuyingController):
|
||||
self.update_billing_status()
|
||||
|
||||
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,
|
||||
# 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)
|
||||
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):
|
||||
from erpnext.accounts.general_ledger import process_gl_map
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import frappe, erpnext
|
||||
from frappe import _
|
||||
from frappe.utils import cint, flt, cstr, now
|
||||
from erpnext.stock.utils import get_valuation_method
|
||||
@ -258,14 +258,15 @@ class update_entries_after(object):
|
||||
|
||||
if not self.valuation_rate and actual_qty > 0:
|
||||
self.valuation_rate = sle.incoming_rate
|
||||
|
||||
|
||||
# Get valuation rate from previous SLE or Item master, if item is not a sample item
|
||||
if not self.valuation_rate and sle.voucher_detail_no:
|
||||
is_sample_item = self.check_if_sample_item(sle.voucher_type, sle.voucher_detail_no)
|
||||
if not is_sample_item:
|
||||
self.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
|
||||
sle.voucher_type, sle.voucher_no, self.allow_zero_rate)
|
||||
|
||||
self.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
|
||||
sle.voucher_type, sle.voucher_no, self.allow_zero_rate,
|
||||
currency=erpnext.get_company_currency(sle.company))
|
||||
|
||||
def get_fifo_values(self, sle):
|
||||
incoming_rate = flt(sle.incoming_rate)
|
||||
actual_qty = flt(sle.actual_qty)
|
||||
@ -291,11 +292,12 @@ class update_entries_after(object):
|
||||
# Get valuation rate from last sle if exists or from valuation rate field in item master
|
||||
is_sample_item = self.check_if_sample_item(sle.voucher_type, sle.voucher_detail_no)
|
||||
if not is_sample_item:
|
||||
_rate = get_valuation_rate(sle.item_code, sle.warehouse,
|
||||
sle.voucher_type, sle.voucher_no, self.allow_zero_rate)
|
||||
_rate = get_valuation_rate(sle.item_code, sle.warehouse,
|
||||
sle.voucher_type, sle.voucher_no, self.allow_zero_rate,
|
||||
currency=erpnext.get_company_currency(sle.company))
|
||||
else:
|
||||
_rate = 0
|
||||
|
||||
|
||||
self.stock_queue.append([0, _rate])
|
||||
|
||||
index = None
|
||||
@ -341,11 +343,11 @@ class update_entries_after(object):
|
||||
|
||||
if not self.stock_queue:
|
||||
self.stock_queue.append([0, sle.incoming_rate or sle.outgoing_rate or self.valuation_rate])
|
||||
|
||||
|
||||
def check_if_sample_item(self, voucher_type, voucher_detail_no):
|
||||
ref_item_dt = voucher_type + (" Detail" if voucher_type == "Stock Entry" else " Item")
|
||||
return frappe.db.get_value(ref_item_dt, voucher_detail_no, "is_sample_item")
|
||||
|
||||
|
||||
def get_sle_before_datetime(self):
|
||||
"""get previous stock ledger entry before current time-bucket"""
|
||||
return get_stock_ledger_entries(self.args, "<", "desc", "limit 1", for_update=False)
|
||||
@ -419,7 +421,8 @@ def get_stock_ledger_entries(previous_sle, operator=None, order="desc", limit=No
|
||||
"order": order
|
||||
}, 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
|
||||
last_valuation_rate = frappe.db.sql("""select valuation_rate
|
||||
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
|
||||
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 \
|
||||
and cint(frappe.db.get_value("Accounts Settings", None, "auto_accounting_for_stock")):
|
||||
frappe.local.message_log = []
|
||||
|
Loading…
Reference in New Issue
Block a user