mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-26 00:14:50 +00:00
Fixed version conflict
This commit is contained in:
@@ -63,6 +63,11 @@ class AccountsController(TransactionBase):
|
||||
if self.doctype == 'Purchase Invoice':
|
||||
self.validate_paid_amount()
|
||||
|
||||
def before_print(self):
|
||||
if self.doctype in ['Purchase Order', 'Sales Order']:
|
||||
if self.get("group_same_items"):
|
||||
self.group_similar_items()
|
||||
|
||||
def validate_paid_amount(self):
|
||||
if hasattr(self, "is_pos") or hasattr(self, "is_paid"):
|
||||
is_paid = self.get("is_pos") or self.get("is_paid")
|
||||
@@ -122,6 +127,11 @@ class AccountsController(TransactionBase):
|
||||
validate_due_date(self.posting_date, self.due_date, "Supplier", self.supplier, self.company)
|
||||
|
||||
def set_price_list_currency(self, buying_or_selling):
|
||||
if self.meta.get_field("posting_date"):
|
||||
transaction_date = self.posting_date
|
||||
else:
|
||||
transaction_date = self.transaction_date
|
||||
|
||||
if self.meta.get_field("currency"):
|
||||
# price list part
|
||||
fieldname = "selling_price_list" if buying_or_selling.lower() == "selling" \
|
||||
@@ -134,8 +144,8 @@ class AccountsController(TransactionBase):
|
||||
self.plc_conversion_rate = 1.0
|
||||
|
||||
elif not self.plc_conversion_rate:
|
||||
self.plc_conversion_rate = get_exchange_rate(
|
||||
self.price_list_currency, self.company_currency)
|
||||
self.plc_conversion_rate = get_exchange_rate(self.price_list_currency,
|
||||
self.company_currency, transaction_date)
|
||||
|
||||
# currency
|
||||
if not self.currency:
|
||||
@@ -145,7 +155,7 @@ class AccountsController(TransactionBase):
|
||||
self.conversion_rate = 1.0
|
||||
elif not self.conversion_rate:
|
||||
self.conversion_rate = get_exchange_rate(self.currency,
|
||||
self.company_currency)
|
||||
self.company_currency, transaction_date)
|
||||
|
||||
def set_missing_item_details(self, for_validate=False):
|
||||
"""set missing item values"""
|
||||
@@ -576,6 +586,27 @@ class AccountsController(TransactionBase):
|
||||
frappe.db.set_value(self.doctype, self.name, "total_advance",
|
||||
total_allocated_amount, update_modified=False)
|
||||
|
||||
def group_similar_items(self):
|
||||
group_item_qty = {}
|
||||
group_item_amount = {}
|
||||
|
||||
for item in self.items:
|
||||
group_item_qty[item.item_code] = group_item_qty.get(item.item_code, 0) + item.qty
|
||||
group_item_amount[item.item_code] = group_item_amount.get(item.item_code, 0) + item.amount
|
||||
|
||||
duplicate_list = []
|
||||
|
||||
for item in self.items:
|
||||
if item.item_code in group_item_qty:
|
||||
item.qty = group_item_qty[item.item_code]
|
||||
item.amount = group_item_amount[item.item_code]
|
||||
del group_item_qty[item.item_code]
|
||||
else:
|
||||
duplicate_list.append(item)
|
||||
|
||||
for item in duplicate_list:
|
||||
self.remove(item)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_tax_rate(account_head):
|
||||
return frappe.db.get_value("Account", account_head, ["tax_rate", "account_name"], as_dict=True)
|
||||
|
||||
@@ -14,15 +14,17 @@ def validate_status(status, options):
|
||||
|
||||
status_map = {
|
||||
"Lead": [
|
||||
["Converted", "has_customer"],
|
||||
["Lost Quotation", "has_lost_quotation"],
|
||||
["Opportunity", "has_opportunity"],
|
||||
["Quotation", "has_quotation"],
|
||||
["Converted", "has_customer"],
|
||||
],
|
||||
"Opportunity": [
|
||||
["Quotation", "has_quotation"],
|
||||
["Converted", "has_ordered_quotation"],
|
||||
["Lost", "eval:self.status=='Lost'"],
|
||||
["Lost", "has_lost_quotation"],
|
||||
["Closed", "eval:self.status=='Closed'"]
|
||||
|
||||
],
|
||||
"Quotation": [
|
||||
["Draft", None],
|
||||
|
||||
@@ -11,6 +11,10 @@ from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries,
|
||||
from erpnext.controllers.accounts_controller import AccountsController
|
||||
|
||||
class StockController(AccountsController):
|
||||
def validate(self):
|
||||
super(StockController, self).validate()
|
||||
self.validate_inspection()
|
||||
|
||||
def make_gl_entries(self, repost_future_gle=True):
|
||||
if self.docstatus == 2:
|
||||
delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
||||
@@ -39,31 +43,34 @@ class StockController(AccountsController):
|
||||
gl_list = []
|
||||
warehouse_with_no_account = []
|
||||
|
||||
for detail in voucher_details:
|
||||
sle_list = sle_map.get(detail.name)
|
||||
for item_row in voucher_details:
|
||||
sle_list = sle_map.get(item_row.name)
|
||||
if sle_list:
|
||||
for sle in sle_list:
|
||||
if warehouse_account.get(sle.warehouse):
|
||||
# from warehouse account
|
||||
|
||||
self.check_expense_account(detail)
|
||||
|
||||
self.check_expense_account(item_row)
|
||||
|
||||
if not sle.stock_value_difference:
|
||||
self.validate_negative_stock(sle)
|
||||
|
||||
gl_list.append(self.get_gl_dict({
|
||||
"account": warehouse_account[sle.warehouse]["name"],
|
||||
"against": detail.expense_account,
|
||||
"cost_center": detail.cost_center,
|
||||
"against": item_row.expense_account,
|
||||
"cost_center": item_row.cost_center,
|
||||
"remarks": self.get("remarks") or "Accounting Entry for Stock",
|
||||
"debit": flt(sle.stock_value_difference, 2),
|
||||
}, warehouse_account[sle.warehouse]["account_currency"]))
|
||||
|
||||
# to target warehouse / expense account
|
||||
gl_list.append(self.get_gl_dict({
|
||||
"account": detail.expense_account,
|
||||
"account": item_row.expense_account,
|
||||
"against": warehouse_account[sle.warehouse]["name"],
|
||||
"cost_center": detail.cost_center,
|
||||
"cost_center": item_row.cost_center,
|
||||
"remarks": self.get("remarks") or "Accounting Entry for Stock",
|
||||
"credit": flt(sle.stock_value_difference, 2),
|
||||
"project": detail.get("project") or self.get("project")
|
||||
"project": item_row.get("project") or self.get("project")
|
||||
}))
|
||||
elif sle.warehouse not in warehouse_with_no_account:
|
||||
warehouse_with_no_account.append(sle.warehouse)
|
||||
@@ -77,6 +84,12 @@ class StockController(AccountsController):
|
||||
"\n".join(warehouse_with_no_account))
|
||||
|
||||
return process_gl_map(gl_list)
|
||||
|
||||
def validate_negative_stock(self, sle):
|
||||
if sle.qty_after_transaction < 0 and sle.actual_qty < 0:
|
||||
frappe.throw(_("For the Item {0}, valuation rate not found for warehouse {1}. To be able to do accounting entries (for booking expenses), we need valuation rate for item {2}. Please create an incoming stock transaction, on or before {3} {4}, and then try submiting {5}")
|
||||
.format(sle.item_code, sle.warehouse,
|
||||
sle.item_code, sle.posting_date, sle.posting_time, self.name))
|
||||
|
||||
def get_voucher_details(self, default_expense_account, default_cost_center, sle_map):
|
||||
if self.doctype == "Stock Reconciliation":
|
||||
@@ -126,7 +139,7 @@ class StockController(AccountsController):
|
||||
def get_stock_ledger_details(self):
|
||||
stock_ledger = {}
|
||||
for sle in frappe.db.sql("""select warehouse, stock_value_difference,
|
||||
voucher_detail_no, item_code, posting_date, actual_qty
|
||||
voucher_detail_no, item_code, posting_date, posting_time, actual_qty, qty_after_transaction
|
||||
from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s""",
|
||||
(self.doctype, self.name), as_dict=True):
|
||||
stock_ledger.setdefault(sle.voucher_detail_no, []).append(sle)
|
||||
@@ -254,6 +267,28 @@ class StockController(AccountsController):
|
||||
"name": self.name,
|
||||
}, update_modified)
|
||||
|
||||
def validate_inspection(self):
|
||||
'''Checks if quality inspection is set for Items that require inspection.
|
||||
On submit, throw an exception'''
|
||||
|
||||
inspection_required_fieldname = None
|
||||
if self.doctype in ["Purchase Receipt", "Purchase Invoice"]:
|
||||
inspection_required_fieldname = "inspection_required_before_purchase"
|
||||
elif self.doctype in ["Delivery Note", "Sales Invoice"]:
|
||||
inspection_required_fieldname = "inspection_required_before_delivery"
|
||||
|
||||
if not inspection_required_fieldname or \
|
||||
(self.doctype in ["Sales Invoice", "Purchase Invoice"] and not self.update_stock):
|
||||
return
|
||||
|
||||
for d in self.get('items'):
|
||||
if (frappe.db.get_value("Item", d.item_code, inspection_required_fieldname)
|
||||
and not d.quality_inspection):
|
||||
|
||||
frappe.msgprint(_("Quality Inspection required for Item {0}").format(d.item_code))
|
||||
if self.docstatus==1:
|
||||
raise frappe.ValidationError
|
||||
|
||||
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
|
||||
warehouse_account=None):
|
||||
def _delete_gl_entries(voucher_type, voucher_no):
|
||||
|
||||
Reference in New Issue
Block a user