Merge branch 'develop' into lcv_multicurrency

This commit is contained in:
Marica
2021-01-28 13:29:36 +05:30
committed by GitHub
48 changed files with 835 additions and 361 deletions

View File

@@ -75,6 +75,9 @@ class AccountsController(TransactionBase):
self.ensure_supplier_is_not_blocked()
self.validate_date_with_fiscal_year()
self.validate_inter_company_reference()
self.set_incoming_rate()
if self.meta.get_field("currency"):
self.calculate_taxes_and_totals()
@@ -118,6 +121,12 @@ class AccountsController(TransactionBase):
def before_cancel(self):
validate_einvoice_fields(self)
def on_trash(self):
# delete sl and gl entries on deletion of transaction
if frappe.db.get_single_value('Accounts Settings', 'delete_linked_ledger_entries'):
frappe.db.sql("delete from `tabGL Entry` where voucher_type=%s and voucher_no=%s", (self.doctype, self.name))
frappe.db.sql("delete from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s", (self.doctype, self.name))
def validate_deferred_start_and_end_date(self):
for d in self.items:
@@ -206,6 +215,17 @@ class AccountsController(TransactionBase):
validate_fiscal_year(self.get(date_field), self.fiscal_year, self.company,
self.meta.get_label(date_field), self)
def validate_inter_company_reference(self):
if self.doctype not in ('Purchase Invoice', 'Purchase Receipt', 'Purchase Order'):
return
if self.is_internal_transfer():
if not (self.get('inter_company_reference') or self.get('inter_company_invoice_reference')
or self.get('inter_company_order_reference')):
msg = _("Internal Sale or Delivery Reference missing. ")
msg += _("Please create purchase from internal sale or delivery document itself")
frappe.throw(msg, title=_("Internal Sales Reference Missing"))
def validate_due_date(self):
if self.get('is_pos'): return
@@ -964,9 +984,9 @@ class AccountsController(TransactionBase):
It will an internal transfer if its an internal customer and representation
company is same as billing company
"""
if self.doctype == 'Sales Invoice':
if self.doctype in ('Sales Invoice', 'Delivery Note', 'Sales Order'):
internal_party_field = 'is_internal_customer'
else:
elif self.doctype in ('Purchase Invoice', 'Purchase Receipt', 'Purchase Order'):
internal_party_field = 'is_internal_supplier'
if self.get(internal_party_field) and (self.represents_company == self.company):

View File

@@ -44,7 +44,6 @@ class BuyingController(StockController):
self.validate_items()
self.set_qty_as_per_stock_uom()
self.validate_stock_or_nonstock_items()
self.update_tax_category_for_internal_transfer()
self.validate_warehouse()
self.validate_from_warehouse()
self.set_supplier_address()
@@ -100,11 +99,6 @@ class BuyingController(StockController):
msg = _('Tax Category has been changed to "Total" because all the Items are non-stock items')
self.update_tax_category(msg)
def update_tax_category_for_internal_transfer(self):
if self.doctype == 'Purchase Invoice' and self.is_internal_transfer():
msg = _('Tax Category has been changed to "Total" as its an internal purchase.')
self.update_tax_category(msg)
def update_tax_category(self, msg):
tax_for_valuation = [d for d in self.get("taxes")
if d.category in ["Valuation", "Valuation and Total"]]
@@ -224,6 +218,48 @@ class BuyingController(StockController):
else:
item.valuation_rate = 0.0
def set_incoming_rate(self):
if self.doctype not in ("Purchase Receipt", "Purchase Invoice", "Purchase Order"):
return
ref_doctype_map = {
"Purchase Order": "Sales Order Item",
"Purchase Receipt": "Delivery Note Item",
"Purchase Invoice": "Sales Invoice Item",
}
ref_doctype = ref_doctype_map.get(self.doctype)
items = self.get("items")
for d in items:
if not cint(self.get("is_return")):
# Get outgoing rate based on original item cost based on valuation method
if not d.get(frappe.scrub(ref_doctype)):
outgoing_rate = get_incoming_rate({
"item_code": d.item_code,
"warehouse": d.get('from_warehouse'),
"posting_date": self.get('posting_date') or self.get('transation_date'),
"posting_time": self.get('posting_time'),
"qty": -1 * flt(d.get('stock_qty')),
"serial_no": d.get('serial_no'),
"company": self.company,
"voucher_type": self.doctype,
"voucher_no": self.name,
"allow_zero_valuation": d.get("allow_zero_valuation")
}, raise_error_if_no_rate=False)
rate = flt(outgoing_rate * d.conversion_factor, d.precision('rate'))
else:
rate = frappe.db.get_value(ref_doctype, d.get(frappe.scrub(ref_doctype)), 'rate')
if self.is_internal_transfer():
if rate != d.rate:
d.rate = rate
d.discount_percentage = 0
d.discount_amount = 0
frappe.msgprint(_("Row {0}: Item rate has been updated as per valuation rate since its an internal stock transfer")
.format(d.idx), alert=1)
def get_supplied_items_cost(self, item_row_id, reset_outgoing_rate=True):
supplied_items_cost = 0.0
for d in self.get("supplied_items"):
@@ -243,7 +279,7 @@ class BuyingController(StockController):
d.amount = flt(flt(d.consumed_qty) * flt(d.rate), d.precision("amount"))
supplied_items_cost += flt(d.amount)
return supplied_items_cost
def validate_for_subcontracting(self):
@@ -559,6 +595,8 @@ class BuyingController(StockController):
from_warehouse_sle = self.get_sl_entries(d, {
"actual_qty": -1 * pr_qty,
"warehouse": d.from_warehouse,
"outgoing_rate": d.rate,
"recalculate_rate": 1,
"dependant_sle_voucher_detail_no": d.name
})

View File

@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cint, flt, cstr, comma_or, get_link_to_form
from frappe.utils import cint, flt, cstr, get_link_to_form, nowtime
from frappe import _, throw
from erpnext.stock.get_item_details import get_bin_details
from erpnext.stock.utils import get_incoming_rate
@@ -49,7 +49,6 @@ class SellingController(StockController):
self.set_customer_address()
self.validate_for_duplicate_items()
self.validate_target_warehouse()
self.set_incoming_rate()
def set_missing_values(self, for_validate=False):
@@ -191,7 +190,7 @@ class SellingController(StockController):
for it in self.get("items"):
if not it.item_code:
continue
last_purchase_rate, is_stock_item = frappe.get_cached_value("Item", it.item_code, ["last_purchase_rate", "is_stock_item"])
last_purchase_rate_in_sales_uom = last_purchase_rate * (it.conversion_factor or 1)
if flt(it.base_net_rate) < flt(last_purchase_rate_in_sales_uom):
@@ -312,7 +311,7 @@ class SellingController(StockController):
sales_order.update_reserved_qty(so_item_rows)
def set_incoming_rate(self):
if self.doctype not in ("Delivery Note", "Sales Invoice"):
if self.doctype not in ("Delivery Note", "Sales Invoice", "Sales Order"):
return
items = self.get("items") + (self.get("packed_items") or [])
@@ -322,15 +321,26 @@ class SellingController(StockController):
d.incoming_rate = get_incoming_rate({
"item_code": d.item_code,
"warehouse": d.warehouse,
"posting_date": self.posting_date,
"posting_time": self.posting_time,
"qty": -1*flt(d.qty),
"serial_no": d.serial_no,
"posting_date": self.get('posting_date') or self.get('transaction_date'),
"posting_time": self.get('posting_time') or nowtime(),
"qty": -1 * flt(d.get('stock_qty') or d.get('actual_qty')),
"serial_no": d.get('serial_no'),
"company": self.company,
"voucher_type": self.doctype,
"voucher_no": self.name,
"allow_zero_valuation": d.get("allow_zero_valuation")
}, raise_error_if_no_rate=False)
# For internal transfers use incoming rate as the valuation rate
if self.is_internal_transfer():
rate = flt(d.incoming_rate * d.conversion_factor, d.precision('rate'))
if d.rate != rate:
d.rate = rate
d.discount_percentage = 0
d.discount_amount = 0
frappe.msgprint(_("Row {0}: Item rate has been updated as per valuation rate since its an internal stock transfer")
.format(d.idx), alert=1)
elif self.get("return_against"):
# Get incoming rate of return entry from reference document
# based on original item cost as per valuation method
@@ -391,7 +401,7 @@ class SellingController(StockController):
})
if item_row.warehouse:
sle.dependant_sle_voucher_detail_no = item_row.name
return sle
def set_po_nos(self, for_validate=False):

View File

@@ -24,6 +24,7 @@ class StockController(AccountsController):
self.validate_inspection()
self.validate_serialized_batch()
self.validate_customer_provided_item()
self.validate_internal_transfer()
self.validate_putaway_capacity()
def make_gl_entries(self, gl_entries=None, from_repost=False):
@@ -74,6 +75,7 @@ class StockController(AccountsController):
warehouse_with_no_account = []
precision = frappe.get_precision("GL Entry", "debit_in_account_currency")
for item_row in voucher_details:
sle_list = sle_map.get(item_row.name)
if sle_list:
for sle in sle_list:
@@ -218,7 +220,7 @@ class StockController(AccountsController):
""", (self.doctype, self.name), as_dict=True)
for sle in stock_ledger_entries:
stock_ledger.setdefault(sle.voucher_detail_no, []).append(sle)
stock_ledger.setdefault(sle.voucher_detail_no, []).append(sle)
return stock_ledger
def make_batches(self, warehouse_field):
@@ -393,6 +395,32 @@ class StockController(AccountsController):
if frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item'):
d.allow_zero_valuation_rate = 1
def validate_internal_transfer(self):
if self.doctype in ('Sales Invoice', 'Delivery Note', 'Purchase Invoice', 'Purchase Receipt') \
and self.is_internal_transfer():
self.validate_in_transit_warehouses()
self.validate_multi_currency()
self.validate_packed_items()
def validate_in_transit_warehouses(self):
if (self.doctype == 'Sales Invoice' and self.get('update_stock')) or self.doctype == 'Delivery Note':
for item in self.get('items'):
if not item.target_warehouse:
frappe.throw(_("Row {0}: Target Warehouse is mandatory for internal transfers").format(item.idx))
if (self.doctype == 'Purchase Invoice' and self.get('update_stock')) or self.doctype == 'Purchase Receipt':
for item in self.get('items'):
if not item.from_warehouse:
frappe.throw(_("Row {0}: From Warehouse is mandatory for internal transfers").format(item.idx))
def validate_multi_currency(self):
if self.currency != self.company_currency:
frappe.throw(_("Internal transfers can only be done in company's default currency"))
def validate_packed_items(self):
if self.doctype in ('Sales Invoice', 'Delivery Note Item') and self.get('packed_items'):
frappe.throw(_("Packed Items cannot be transferred internally"))
def validate_putaway_capacity(self):
# if over receipt is attempted while 'apply putaway rule' is disabled
# and if rule was applied on the transaction, validate it.