mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-09 00:01:18 +00:00
fix: Consider conversion factor for invoices
This commit is contained in:
@@ -89,6 +89,7 @@
|
||||
"po_detail",
|
||||
"purchase_receipt",
|
||||
"pr_detail",
|
||||
"sales_invoice_item",
|
||||
"item_weight_details",
|
||||
"weight_per_unit",
|
||||
"total_weight",
|
||||
@@ -787,12 +788,20 @@
|
||||
"fieldtype": "Currency",
|
||||
"label": "Outgoing Rate",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "sales_invoice_item",
|
||||
"fieldtype": "Data",
|
||||
"label": "Sales Invoice Item",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-12-23 17:30:57.458876",
|
||||
"modified": "2020-12-24 12:09:53.611463",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice Item",
|
||||
|
||||
@@ -180,7 +180,7 @@ class SalesInvoice(SellingController):
|
||||
|
||||
# this sequence because outstanding may get -ve
|
||||
self.make_gl_entries()
|
||||
|
||||
|
||||
if self.update_stock == 1:
|
||||
self.repost_future_sle_and_gle()
|
||||
|
||||
@@ -262,10 +262,10 @@ class SalesInvoice(SellingController):
|
||||
self.update_stock_ledger()
|
||||
|
||||
self.make_gl_entries_on_cancel()
|
||||
|
||||
|
||||
if self.update_stock == 1:
|
||||
self.repost_future_sle_and_gle()
|
||||
|
||||
|
||||
frappe.db.set(self, 'status', 'Cancelled')
|
||||
|
||||
if frappe.db.get_single_value('Selling Settings', 'sales_update_frequency') == "Each Transaction":
|
||||
@@ -1628,7 +1628,8 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
|
||||
'field_map': {
|
||||
source_document_warehouse_field: target_document_warehouse_field,
|
||||
'batch_no': 'batch_no',
|
||||
'serial_no': 'serial_no'
|
||||
'serial_no': 'serial_no',
|
||||
'name': 'sales_invoice_item'
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ class AccountsController(TransactionBase):
|
||||
self.ensure_supplier_is_not_blocked()
|
||||
|
||||
self.validate_date_with_fiscal_year()
|
||||
self.set_incoming_rate()
|
||||
|
||||
if self.meta.get_field("currency"):
|
||||
self.calculate_taxes_and_totals()
|
||||
|
||||
@@ -66,8 +66,6 @@ class BuyingController(StockController):
|
||||
if self.doctype in ("Purchase Receipt", "Purchase Invoice"):
|
||||
self.update_valuation_rate()
|
||||
|
||||
self.set_out_going_rate()
|
||||
|
||||
def set_missing_values(self, for_validate=False):
|
||||
super(BuyingController, self).set_missing_values(for_validate)
|
||||
|
||||
@@ -220,31 +218,39 @@ class BuyingController(StockController):
|
||||
else:
|
||||
item.valuation_rate = 0.0
|
||||
|
||||
def set_out_going_rate(self):
|
||||
def set_incoming_rate(self):
|
||||
if self.doctype not in ("Purchase Receipt", "Purchase Invoice"):
|
||||
return
|
||||
|
||||
ref_doctype = 'Delivery Note Item' if self.doctype == 'Purchase Receipt' else 'Sales Invoice Item'
|
||||
|
||||
items = self.get("items")
|
||||
for d in items:
|
||||
if not cint(self.get("is_return")) and d.get("target_warehouse"):
|
||||
if not cint(self.get("is_return")) and d.get("from_warehouse"):
|
||||
# Get outgoing rate based on original item cost based on valuation method
|
||||
d.outgoing_rate = get_incoming_rate({
|
||||
"item_code": d.item_code,
|
||||
"warehouse": d.target_warehouse,
|
||||
"posting_date": self.posting_date,
|
||||
"posting_time": self.posting_time,
|
||||
"qty": -1 * flt(d.qty),
|
||||
"serial_no": d.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)
|
||||
|
||||
elif self.get("return_against"):
|
||||
# Get incoming rate of return entry from reference document
|
||||
# based on original item cost as per valuation method
|
||||
d.outgoing_rate = get_rate_for_return(self.doctype, self.name, d.item_code, self.return_against, item_row=d)
|
||||
if not d.get('sales_invoice_item'):
|
||||
outgoing_rate = get_incoming_rate({
|
||||
"item_code": d.item_code,
|
||||
"warehouse": d.from_warehouse,
|
||||
"posting_date": self.posting_date,
|
||||
"posting_time": self.posting_time,
|
||||
"qty": -1 * flt(d.stock_qty),
|
||||
"serial_no": d.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)
|
||||
else:
|
||||
rate = frappe.db.get_value(ref_doctype, d.get(frappe.scrub(ref_doctype)), 'rate')
|
||||
|
||||
if rate != d.rate:
|
||||
frappe.msgprint(_("Row {0}: Item rate has been updated as per valuation rate since its an internal stock transfer")
|
||||
.format(d.idx), alert=1)
|
||||
d.rate = rate
|
||||
|
||||
def get_supplied_items_cost(self, item_row_id, reset_outgoing_rate=True):
|
||||
supplied_items_cost = 0.0
|
||||
@@ -581,7 +587,8 @@ class BuyingController(StockController):
|
||||
from_warehouse_sle = self.get_sl_entries(d, {
|
||||
"actual_qty": -1 * pr_qty,
|
||||
"warehouse": d.from_warehouse,
|
||||
"outgoing_rate": d.outgoing_rate,
|
||||
"outgoing_rate": d.rate,
|
||||
"recalculate_rate": 1,
|
||||
"dependant_sle_voucher_detail_no": d.name
|
||||
})
|
||||
|
||||
@@ -592,8 +599,10 @@ class BuyingController(StockController):
|
||||
"serial_no": cstr(d.serial_no).strip()
|
||||
})
|
||||
if self.is_return:
|
||||
outgoing_rate = get_rate_for_return(self.doctype, self.name, d.item_code, self.return_against, item_row=d)
|
||||
|
||||
sle.update({
|
||||
"outgoing_rate": d.outgoing_rate,
|
||||
"outgoing_rate": outgoing_rate,
|
||||
"recalculate_rate": 1
|
||||
})
|
||||
if d.from_warehouse:
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -324,7 +323,7 @@ class SellingController(StockController):
|
||||
"warehouse": d.warehouse,
|
||||
"posting_date": self.posting_date,
|
||||
"posting_time": self.posting_time,
|
||||
"qty": -1*flt(d.qty),
|
||||
"qty": -1*flt(d.stock_qty),
|
||||
"serial_no": d.serial_no,
|
||||
"company": self.company,
|
||||
"voucher_type": self.doctype,
|
||||
@@ -334,8 +333,9 @@ class SellingController(StockController):
|
||||
|
||||
# For internal transfers use incoming rate as the valuation rate
|
||||
if self.get('is_internal_customer') and d.get('target_warehouse'):
|
||||
d.rate = d.incoming_rate
|
||||
frappe.msgprint(_("Row {0}: Item rate updated as the valuation rate since its an internal transfer").format(d.idx))
|
||||
d.rate = flt(d.incoming_rate * d.conversion_factor)
|
||||
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
|
||||
|
||||
@@ -722,7 +722,8 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
|
||||
doctype +" Item": {
|
||||
"doctype": target_doctype + " Item",
|
||||
"field_map": {
|
||||
source_document_warehouse_field: target_document_warehouse_field
|
||||
source_document_warehouse_field: target_document_warehouse_field,
|
||||
'name': 'delivery_note_item'
|
||||
},
|
||||
"field_no_map": [
|
||||
"warehouse"
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
"purchase_order_item",
|
||||
"material_request_item",
|
||||
"purchase_receipt_item",
|
||||
"delivery_note_item",
|
||||
"section_break_45",
|
||||
"allow_zero_valuation_rate",
|
||||
"bom",
|
||||
@@ -868,12 +869,20 @@
|
||||
"fieldtype": "Currency",
|
||||
"label": "Outgoing Rate",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "delivery_note_item",
|
||||
"fieldtype": "Data",
|
||||
"label": "Delivery Note Item",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-12-23 17:33:19.479325",
|
||||
"modified": "2020-12-24 12:10:46.943722",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Purchase Receipt Item",
|
||||
|
||||
@@ -41,7 +41,7 @@ def make_sl_entries(sl_entries, allow_negative_stock=False, via_landed_cost_vouc
|
||||
|
||||
if sle.get("actual_qty") or sle.get("voucher_type")=="Stock Reconciliation":
|
||||
sle_doc = make_entry(sle, allow_negative_stock, via_landed_cost_voucher)
|
||||
|
||||
|
||||
args = sle_doc.as_dict()
|
||||
update_bin(args, allow_negative_stock, via_landed_cost_voucher)
|
||||
|
||||
@@ -65,7 +65,7 @@ def make_entry(args, allow_negative_stock=False, via_landed_cost_voucher=False):
|
||||
def repost_future_sle(args=None, voucher_type=None, voucher_no=None, allow_negative_stock=False, via_landed_cost_voucher=False):
|
||||
if not args and voucher_type and voucher_no:
|
||||
args = get_args_for_voucher(voucher_type, voucher_no)
|
||||
|
||||
|
||||
distinct_item_warehouses = [(d.item_code, d.warehouse) for d in args]
|
||||
|
||||
i = 0
|
||||
@@ -80,7 +80,7 @@ def repost_future_sle(args=None, voucher_type=None, voucher_no=None, allow_negat
|
||||
for item_wh, new_sle in iteritems(obj.new_items):
|
||||
if item_wh not in distinct_item_warehouses:
|
||||
args.append(new_sle)
|
||||
|
||||
|
||||
i += 1
|
||||
|
||||
def get_args_for_voucher(voucher_type, voucher_no):
|
||||
@@ -127,7 +127,7 @@ class update_entries_after(object):
|
||||
self.initialize_previous_data(self.args)
|
||||
|
||||
self.build()
|
||||
|
||||
|
||||
def get_precision(self):
|
||||
company_base_currency = frappe.get_cached_value('Company', self.company, "default_currency")
|
||||
self.precision = get_field_precision(frappe.get_meta("Stock Ledger Entry").get_field("stock_value"),
|
||||
@@ -213,13 +213,13 @@ class update_entries_after(object):
|
||||
# includes current entry!
|
||||
args = self.data[self.args.warehouse].previous_sle \
|
||||
or frappe._dict({"item_code": self.item_code, "warehouse": self.args.warehouse})
|
||||
|
||||
|
||||
return list(self.get_sle_after_datetime(args))
|
||||
|
||||
def get_dependent_entries_to_fix(self, entries_to_fix, sle):
|
||||
dependant_sle = get_sle_by_voucher_detail_no(sle.dependant_sle_voucher_detail_no,
|
||||
excluded_sle=sle.name)
|
||||
|
||||
|
||||
if not dependant_sle:
|
||||
return
|
||||
elif dependant_sle.item_code == self.item_code and dependant_sle.warehouse == self.args.warehouse:
|
||||
@@ -251,7 +251,7 @@ class update_entries_after(object):
|
||||
|
||||
# Get dynamic incoming/outgoing rate
|
||||
self.get_dynamic_incoming_outgoing_rate(sle)
|
||||
|
||||
|
||||
if sle.serial_no:
|
||||
self.get_serialized_values(sle)
|
||||
self.wh_data.qty_after_transaction += flt(sle.actual_qty)
|
||||
@@ -329,7 +329,7 @@ class update_entries_after(object):
|
||||
rate = get_rate_for_return(sle.voucher_type, sle.voucher_no, sle.item_code, voucher_detail_no=sle.voucher_detail_no)
|
||||
else:
|
||||
if sle.voucher_type in ("Purchase Receipt", "Purchase Invoice"):
|
||||
rate_field = "valuation_rate"
|
||||
rate_field = "valuation_rate"
|
||||
else:
|
||||
rate_field = "incoming_rate"
|
||||
|
||||
@@ -344,7 +344,7 @@ class update_entries_after(object):
|
||||
ref_doctype = "Packed Item"
|
||||
else:
|
||||
ref_doctype = "Purchase Receipt Item Supplied"
|
||||
|
||||
|
||||
rate = frappe.db.get_value(ref_doctype, {"parent_detail_docname": sle.voucher_detail_no,
|
||||
"item_code": sle.item_code}, rate_field)
|
||||
|
||||
@@ -374,8 +374,22 @@ class update_entries_after(object):
|
||||
stock_entry.db_update()
|
||||
for d in stock_entry.items:
|
||||
d.db_update()
|
||||
|
||||
|
||||
def update_rate_on_delivery_and_sales_return(self, sle, outgoing_rate):
|
||||
if frappe.db.get_value(sle.voucher_type, sle.voucher_no, 'is_internal_customer'):
|
||||
frappe.db.set_value(doctype + " Item", voucher_detail_no, "rate", rate)
|
||||
update_taxes_and_totals(sle.voucher_type, sle.voucher_no, outgoing_rate)
|
||||
|
||||
purchase_doctype = 'Purchase Invoice' if sle.voucher_type == 'Sales Invoice' else 'Purchase Receipt'
|
||||
ref_field = frappe.scrub(sle.voucher_type + ' Item')
|
||||
|
||||
purchase_document_list = frappe.db.get_all(purchase_doctype, {'inter_company_invoice_reference':
|
||||
sle.voucher_no}, ['name'], as_dict=1)
|
||||
|
||||
for d in purchase_document_list:
|
||||
frappe.db.set_value(purchase_doctype + ' Item', {ref_field: sle.voucher_detail_no}, 'rate', outgoing_rate)
|
||||
update_taxes_and_totals(purchase_doctype, d.name, outgoing_rate)
|
||||
|
||||
# Update item's incoming rate on transaction
|
||||
item_code = frappe.db.get_value(sle.voucher_type + " Item", sle.voucher_detail_no, "item_code")
|
||||
if item_code == sle.item_code:
|
||||
@@ -386,6 +400,13 @@ class update_entries_after(object):
|
||||
{"parent_detail_docname": sle.voucher_detail_no, "item_code": sle.item_code},
|
||||
"incoming_rate", outgoing_rate)
|
||||
|
||||
def update_taxes_and_totals(doctype, docname, rate):
|
||||
ref_doc = frappe.get_doc(doctype, docname)
|
||||
ref_doc.calculate_taxes_and_totals()
|
||||
ref_doc.db_update()
|
||||
for d in ref_doc.items:
|
||||
d.db_update()
|
||||
|
||||
def update_rate_on_purchase_receipt(self, sle, outgoing_rate):
|
||||
if frappe.db.exists(sle.voucher_type + " Item", sle.voucher_detail_no):
|
||||
frappe.db.set_value(sle.voucher_type + " Item", sle.voucher_detail_no, "base_net_rate", outgoing_rate)
|
||||
@@ -488,6 +509,7 @@ class update_entries_after(object):
|
||||
else:
|
||||
self.wh_data.valuation_rate = sle.outgoing_rate
|
||||
|
||||
print(self.wh_data.valuation_rate, "$#$#$#$#")
|
||||
else:
|
||||
if flt(self.wh_data.qty_after_transaction) >= 0 and sle.outgoing_rate:
|
||||
self.wh_data.valuation_rate = sle.outgoing_rate
|
||||
@@ -631,7 +653,7 @@ class update_entries_after(object):
|
||||
frappe.throw(message, NegativeStockError, title='Insufficient Stock')
|
||||
else:
|
||||
raise NegativeStockError(message)
|
||||
|
||||
|
||||
def update_bin(self):
|
||||
# update bin for each warehouse
|
||||
for warehouse, data in iteritems(self.data):
|
||||
@@ -766,7 +788,7 @@ def update_qty_in_future_sle(args, allow_negative_stock=None):
|
||||
frappe.db.sql("""
|
||||
update `tabStock Ledger Entry`
|
||||
set qty_after_transaction = qty_after_transaction + {qty}
|
||||
where
|
||||
where
|
||||
item_code = %(item_code)s
|
||||
and warehouse = %(warehouse)s
|
||||
and voucher_no != %(voucher_no)s
|
||||
@@ -794,7 +816,7 @@ def validate_negative_qty_in_future_sle(args, allow_negative_stock=None):
|
||||
frappe.get_desk_link('Warehouse', args.warehouse),
|
||||
sle[0]["posting_date"], sle[0]["posting_time"],
|
||||
frappe.get_desk_link(sle[0]["voucher_type"], sle[0]["voucher_no"]))
|
||||
|
||||
|
||||
frappe.throw(message, NegativeStockError, title='Insufficient Stock')
|
||||
|
||||
def get_future_sle_with_negative_qty(args):
|
||||
@@ -803,7 +825,7 @@ def get_future_sle_with_negative_qty(args):
|
||||
qty_after_transaction, posting_date, posting_time,
|
||||
voucher_type, voucher_no
|
||||
from `tabStock Ledger Entry`
|
||||
where
|
||||
where
|
||||
item_code = %(item_code)s
|
||||
and warehouse = %(warehouse)s
|
||||
and voucher_no != %(voucher_no)s
|
||||
|
||||
Reference in New Issue
Block a user