Merge pull request #24127 from deepeshgarg007/lcv_multicurrency
feat: Multi currency in landed cost voucher
This commit is contained in:
commit
a16ad3063f
@ -254,7 +254,8 @@ def create_account(**kwargs):
|
|||||||
account_name = kwargs.get('account_name'),
|
account_name = kwargs.get('account_name'),
|
||||||
account_type = kwargs.get('account_type'),
|
account_type = kwargs.get('account_type'),
|
||||||
parent_account = kwargs.get('parent_account'),
|
parent_account = kwargs.get('parent_account'),
|
||||||
company = kwargs.get('company')
|
company = kwargs.get('company'),
|
||||||
|
account_currency = kwargs.get('account_currency')
|
||||||
))
|
))
|
||||||
|
|
||||||
account.save()
|
account.save()
|
||||||
|
@ -159,8 +159,8 @@ class GLEntry(Document):
|
|||||||
|
|
||||||
if not self.flags.from_repost and not self.voucher_type == 'Period Closing Voucher' \
|
if not self.flags.from_repost and not self.voucher_type == 'Period Closing Voucher' \
|
||||||
and self.cost_center and _check_is_group():
|
and self.cost_center and _check_is_group():
|
||||||
frappe.throw(_("""{0} {1}: Cost Center {2} is a group cost center and group cost centers cannot
|
frappe.throw(_("""{0} {1}: Cost Center {2} is a group cost center and group cost centers cannot be used in transactions""").format(
|
||||||
be used in transactions""").format(self.voucher_type, self.voucher_no, frappe.bold(self.cost_center)))
|
self.voucher_type, self.voucher_no, frappe.bold(self.cost_center)))
|
||||||
|
|
||||||
def validate_party(self):
|
def validate_party(self):
|
||||||
validate_party_frozen_disabled(self.party_type, self.party)
|
validate_party_frozen_disabled(self.party_type, self.party)
|
||||||
@ -170,7 +170,7 @@ class GLEntry(Document):
|
|||||||
account_currency = get_account_currency(self.account)
|
account_currency = get_account_currency(self.account)
|
||||||
|
|
||||||
if not self.account_currency:
|
if not self.account_currency:
|
||||||
self.account_currency = company_currency
|
self.account_currency = account_currency or company_currency
|
||||||
|
|
||||||
if account_currency != self.account_currency:
|
if account_currency != self.account_currency:
|
||||||
frappe.throw(_("{0} {1}: Accounting Entry for {2} can only be made in currency: {3}")
|
frappe.throw(_("{0} {1}: Accounting Entry for {2} can only be made in currency: {3}")
|
||||||
|
@ -583,7 +583,8 @@ class PurchaseInvoice(BuyingController):
|
|||||||
"against": item.expense_account,
|
"against": item.expense_account,
|
||||||
"cost_center": item.cost_center,
|
"cost_center": item.cost_center,
|
||||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||||
"credit": flt(amount),
|
"credit": flt(amount["base_amount"]),
|
||||||
|
"credit_in_account_currency": flt(amount["amount"]),
|
||||||
"project": item.project or self.project
|
"project": item.project or self.project
|
||||||
}, item=item))
|
}, item=item))
|
||||||
|
|
||||||
|
@ -468,8 +468,10 @@ class AccountsController(TransactionBase):
|
|||||||
account_currency = get_account_currency(gl_dict.account)
|
account_currency = get_account_currency(gl_dict.account)
|
||||||
|
|
||||||
if gl_dict.account and self.doctype not in ["Journal Entry",
|
if gl_dict.account and self.doctype not in ["Journal Entry",
|
||||||
"Period Closing Voucher", "Payment Entry"]:
|
"Period Closing Voucher", "Payment Entry", "Purchase Receipt", "Purchase Invoice", "Stock Entry"]:
|
||||||
self.validate_account_currency(gl_dict.account, account_currency)
|
self.validate_account_currency(gl_dict.account, account_currency)
|
||||||
|
|
||||||
|
if gl_dict.account and self.doctype not in ["Journal Entry", "Period Closing Voucher", "Payment Entry"]:
|
||||||
set_balance_in_account_currency(gl_dict, account_currency, self.get("conversion_rate"),
|
set_balance_in_account_currency(gl_dict, account_currency, self.get("conversion_rate"),
|
||||||
self.company_currency)
|
self.company_currency)
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ from erpnext.controllers.accounts_controller import validate_conversion_rate, \
|
|||||||
validate_taxes_and_charges, validate_inclusive_tax
|
validate_taxes_and_charges, validate_inclusive_tax
|
||||||
from erpnext.stock.get_item_details import _get_item_tax_template
|
from erpnext.stock.get_item_details import _get_item_tax_template
|
||||||
from erpnext.accounts.doctype.pricing_rule.utils import get_applied_pricing_rules
|
from erpnext.accounts.doctype.pricing_rule.utils import get_applied_pricing_rules
|
||||||
|
from erpnext.accounts.doctype.journal_entry.journal_entry import get_exchange_rate
|
||||||
|
|
||||||
class calculate_taxes_and_totals(object):
|
class calculate_taxes_and_totals(object):
|
||||||
def __init__(self, doc):
|
def __init__(self, doc):
|
||||||
@ -758,3 +759,35 @@ def get_rounded_tax_amount(itemised_tax, precision):
|
|||||||
for taxes in itemised_tax.values():
|
for taxes in itemised_tax.values():
|
||||||
for tax_account in taxes:
|
for tax_account in taxes:
|
||||||
taxes[tax_account]["tax_amount"] = flt(taxes[tax_account]["tax_amount"], precision)
|
taxes[tax_account]["tax_amount"] = flt(taxes[tax_account]["tax_amount"], precision)
|
||||||
|
|
||||||
|
class init_landed_taxes_and_totals(object):
|
||||||
|
def __init__(self, doc):
|
||||||
|
self.doc = doc
|
||||||
|
self.tax_field = 'taxes' if self.doc.doctype == 'Landed Cost Voucher' else 'additional_costs'
|
||||||
|
self.set_account_currency()
|
||||||
|
self.set_exchange_rate()
|
||||||
|
self.set_amounts_in_company_currency()
|
||||||
|
|
||||||
|
def set_account_currency(self):
|
||||||
|
company_currency = erpnext.get_company_currency(self.doc.company)
|
||||||
|
for d in self.doc.get(self.tax_field):
|
||||||
|
if not d.account_currency:
|
||||||
|
account_currency = frappe.db.get_value('Account', d.expense_account, 'account_currency')
|
||||||
|
d.account_currency = account_currency or company_currency
|
||||||
|
|
||||||
|
def set_exchange_rate(self):
|
||||||
|
company_currency = erpnext.get_company_currency(self.doc.company)
|
||||||
|
for d in self.doc.get(self.tax_field):
|
||||||
|
if d.account_currency == company_currency:
|
||||||
|
d.exchange_rate = 1
|
||||||
|
elif not d.exchange_rate or d.exchange_rate == 1 or self.doc.posting_date:
|
||||||
|
d.exchange_rate = get_exchange_rate(self.doc.posting_date, account=d.expense_account,
|
||||||
|
account_currency=d.account_currency, company=self.doc.company)
|
||||||
|
|
||||||
|
if not d.exchange_rate:
|
||||||
|
frappe.throw(_("Row {0}: Exchange Rate is mandatory").format(d.idx))
|
||||||
|
|
||||||
|
def set_amounts_in_company_currency(self):
|
||||||
|
for d in self.doc.get(self.tax_field):
|
||||||
|
d.amount = flt(d.amount, d.precision("amount"))
|
||||||
|
d.base_amount = flt(d.amount * flt(d.exchange_rate), d.precision("base_amount"))
|
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"creation": "2013-02-22 01:28:02",
|
"creation": "2013-02-22 01:28:02",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Document",
|
"document_type": "Document",
|
||||||
@ -29,6 +30,8 @@
|
|||||||
"options": "Item",
|
"options": "Item",
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1,
|
||||||
"width": "100px"
|
"width": "100px"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -41,6 +44,8 @@
|
|||||||
"print_width": "300px",
|
"print_width": "300px",
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1,
|
||||||
"width": "120px"
|
"width": "120px"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -50,7 +55,9 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Purchase Invoice\nPurchase Receipt",
|
"options": "Purchase Invoice\nPurchase Receipt",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "receipt_document",
|
"fieldname": "receipt_document",
|
||||||
@ -59,25 +66,33 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "receipt_document_type",
|
"options": "receipt_document_type",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "col_break2",
|
"fieldname": "col_break2",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "qty",
|
"fieldname": "qty",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Qty",
|
"label": "Qty",
|
||||||
"read_only": 1
|
"read_only": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "rate",
|
"fieldname": "rate",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Rate",
|
"label": "Rate",
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"read_only": 1
|
"read_only": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "amount",
|
"fieldname": "amount",
|
||||||
@ -88,14 +103,19 @@
|
|||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
"reqd": 1
|
"reqd": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "applicable_charges",
|
"fieldname": "applicable_charges",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Applicable Charges",
|
"label": "Applicable Charges",
|
||||||
"options": "Company:company:default_currency"
|
"options": "Company:company:default_currency",
|
||||||
|
"read_only_depends_on": "eval:parent.distribute_charges_based_on != 'Distribute Manually'",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "purchase_receipt_item",
|
"fieldname": "purchase_receipt_item",
|
||||||
@ -104,22 +124,30 @@
|
|||||||
"label": "Purchase Receipt Item",
|
"label": "Purchase Receipt Item",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "cost_center",
|
"fieldname": "cost_center",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Cost Center",
|
"label": "Cost Center",
|
||||||
"options": "Cost Center"
|
"options": "Cost Center",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "accounting_dimensions_section",
|
"fieldname": "accounting_dimensions_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Accounting Dimensions"
|
"label": "Accounting Dimensions",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "dimension_col_break",
|
"fieldname": "dimension_col_break",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
@ -128,12 +156,15 @@
|
|||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"label": "Is Fixed Asset",
|
"label": "Is Fixed Asset",
|
||||||
"read_only": 1
|
"read_only": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2020-09-18 17:26:09.703215",
|
"links": [],
|
||||||
|
"modified": "2021-01-25 23:09:23.322282",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Landed Cost Item",
|
"name": "Landed Cost Item",
|
||||||
|
@ -6,8 +6,11 @@
|
|||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"expense_account",
|
"expense_account",
|
||||||
|
"account_currency",
|
||||||
|
"exchange_rate",
|
||||||
"description",
|
"description",
|
||||||
"col_break3",
|
"col_break3",
|
||||||
|
"base_amount",
|
||||||
"amount"
|
"amount"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
@ -28,7 +31,7 @@
|
|||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Amount",
|
"label": "Amount",
|
||||||
"options": "Company:company:default_currency",
|
"options": "account_currency",
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -38,13 +41,33 @@
|
|||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Expense Account",
|
"label": "Expense Account",
|
||||||
"mandatory_depends_on": "eval:cint(erpnext.is_perpetual_inventory_enabled(parent.company))",
|
"mandatory_depends_on": "eval:cint(erpnext.is_perpetual_inventory_enabled(parent.company))",
|
||||||
"options": "Account",
|
"options": "Account"
|
||||||
"print_hide": 1
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "account_currency",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Account Currency",
|
||||||
|
"options": "Currency",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "exchange_rate",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"label": "Exchange Rate",
|
||||||
|
"precision": "9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "base_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Base Amount",
|
||||||
|
"options": "Company:company:default_currency",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-12-04 00:22:14.373312",
|
"modified": "2020-12-26 01:07:23.233604",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Landed Cost Taxes and Charges",
|
"name": "Landed Cost Taxes and Charges",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
{% include 'erpnext/stock/landed_taxes_and_charges_common.js' %};
|
||||||
|
|
||||||
frappe.provide("erpnext.stock");
|
frappe.provide("erpnext.stock");
|
||||||
|
|
||||||
@ -29,20 +30,9 @@ erpnext.stock.LandedCostVoucher = erpnext.stock.StockController.extend({
|
|||||||
this.frm.add_fetch("receipt_document", "supplier", "supplier");
|
this.frm.add_fetch("receipt_document", "supplier", "supplier");
|
||||||
this.frm.add_fetch("receipt_document", "posting_date", "posting_date");
|
this.frm.add_fetch("receipt_document", "posting_date", "posting_date");
|
||||||
this.frm.add_fetch("receipt_document", "base_grand_total", "grand_total");
|
this.frm.add_fetch("receipt_document", "base_grand_total", "grand_total");
|
||||||
|
|
||||||
this.frm.set_query("expense_account", "taxes", function() {
|
|
||||||
return {
|
|
||||||
query: "erpnext.controllers.queries.tax_account_query",
|
|
||||||
filters: {
|
|
||||||
"account_type": ["Tax", "Chargeable", "Income Account", "Expenses Included In Valuation", "Expenses Included In Asset Valuation"],
|
|
||||||
"company": me.frm.doc.company
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function(frm) {
|
refresh: function() {
|
||||||
var help_content =
|
var help_content =
|
||||||
`<br><br>
|
`<br><br>
|
||||||
<table class="table table-bordered" style="background-color: #f9f9f9;">
|
<table class="table table-bordered" style="background-color: #f9f9f9;">
|
||||||
@ -72,6 +62,11 @@ erpnext.stock.LandedCostVoucher = erpnext.stock.StockController.extend({
|
|||||||
</table>`;
|
</table>`;
|
||||||
|
|
||||||
set_field_options("landed_cost_help", help_content);
|
set_field_options("landed_cost_help", help_content);
|
||||||
|
|
||||||
|
if (this.frm.doc.company) {
|
||||||
|
let company_currency = frappe.get_doc(":Company", this.frm.doc.company).default_currency;
|
||||||
|
this.frm.set_currency_labels(["total_taxes_and_charges"], company_currency);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
get_items_from_purchase_receipts: function() {
|
get_items_from_purchase_receipts: function() {
|
||||||
@ -97,34 +92,36 @@ erpnext.stock.LandedCostVoucher = erpnext.stock.StockController.extend({
|
|||||||
set_total_taxes_and_charges: function() {
|
set_total_taxes_and_charges: function() {
|
||||||
var total_taxes_and_charges = 0.0;
|
var total_taxes_and_charges = 0.0;
|
||||||
$.each(this.frm.doc.taxes || [], function(i, d) {
|
$.each(this.frm.doc.taxes || [], function(i, d) {
|
||||||
total_taxes_and_charges += flt(d.amount)
|
total_taxes_and_charges += flt(d.base_amount);
|
||||||
});
|
});
|
||||||
cur_frm.set_value("total_taxes_and_charges", total_taxes_and_charges);
|
this.frm.set_value("total_taxes_and_charges", total_taxes_and_charges);
|
||||||
},
|
},
|
||||||
|
|
||||||
set_applicable_charges_for_item: function() {
|
set_applicable_charges_for_item: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
|
|
||||||
if(this.frm.doc.taxes.length) {
|
if(this.frm.doc.taxes.length) {
|
||||||
|
|
||||||
var total_item_cost = 0.0;
|
var total_item_cost = 0.0;
|
||||||
var based_on = this.frm.doc.distribute_charges_based_on.toLowerCase();
|
var based_on = this.frm.doc.distribute_charges_based_on.toLowerCase();
|
||||||
$.each(this.frm.doc.items || [], function(i, d) {
|
|
||||||
total_item_cost += flt(d[based_on])
|
|
||||||
});
|
|
||||||
|
|
||||||
var total_charges = 0.0;
|
if (based_on != 'distribute manually') {
|
||||||
$.each(this.frm.doc.items || [], function(i, item) {
|
$.each(this.frm.doc.items || [], function(i, d) {
|
||||||
item.applicable_charges = flt(item[based_on]) * flt(me.frm.doc.total_taxes_and_charges) / flt(total_item_cost)
|
total_item_cost += flt(d[based_on])
|
||||||
item.applicable_charges = flt(item.applicable_charges, precision("applicable_charges", item))
|
});
|
||||||
total_charges += item.applicable_charges
|
|
||||||
});
|
|
||||||
|
|
||||||
if (total_charges != this.frm.doc.total_taxes_and_charges){
|
var total_charges = 0.0;
|
||||||
var diff = this.frm.doc.total_taxes_and_charges - flt(total_charges)
|
$.each(this.frm.doc.items || [], function(i, item) {
|
||||||
this.frm.doc.items.slice(-1)[0].applicable_charges += diff
|
item.applicable_charges = flt(item[based_on]) * flt(me.frm.doc.total_taxes_and_charges) / flt(total_item_cost)
|
||||||
|
item.applicable_charges = flt(item.applicable_charges, precision("applicable_charges", item))
|
||||||
|
total_charges += item.applicable_charges
|
||||||
|
});
|
||||||
|
|
||||||
|
if (total_charges != this.frm.doc.total_taxes_and_charges){
|
||||||
|
var diff = this.frm.doc.total_taxes_and_charges - flt(total_charges)
|
||||||
|
this.frm.doc.items.slice(-1)[0].applicable_charges += diff
|
||||||
|
}
|
||||||
|
refresh_field("items");
|
||||||
}
|
}
|
||||||
refresh_field("items");
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
distribute_charges_based_on: function (frm) {
|
distribute_charges_based_on: function (frm) {
|
||||||
@ -134,7 +131,16 @@ erpnext.stock.LandedCostVoucher = erpnext.stock.StockController.extend({
|
|||||||
items_remove: () => {
|
items_remove: () => {
|
||||||
this.trigger('set_applicable_charges_for_item');
|
this.trigger('set_applicable_charges_for_item');
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
cur_frm.script_manager.make(erpnext.stock.LandedCostVoucher);
|
cur_frm.script_manager.make(erpnext.stock.LandedCostVoucher);
|
||||||
|
|
||||||
|
frappe.ui.form.on('Landed Cost Taxes and Charges', {
|
||||||
|
expense_account: function(frm, cdt, cdn) {
|
||||||
|
frm.events.set_account_currency(frm, cdt, cdn);
|
||||||
|
},
|
||||||
|
|
||||||
|
amount: function(frm, cdt, cdn) {
|
||||||
|
frm.events.set_base_amount(frm, cdt, cdn);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"creation": "2014-07-11 11:33:42.547339",
|
"creation": "2014-07-11 11:33:42.547339",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
@ -7,6 +8,9 @@
|
|||||||
"field_order": [
|
"field_order": [
|
||||||
"naming_series",
|
"naming_series",
|
||||||
"company",
|
"company",
|
||||||
|
"column_break_2",
|
||||||
|
"posting_date",
|
||||||
|
"section_break_5",
|
||||||
"purchase_receipts",
|
"purchase_receipts",
|
||||||
"purchase_receipt_items",
|
"purchase_receipt_items",
|
||||||
"get_items_from_purchase_receipts",
|
"get_items_from_purchase_receipts",
|
||||||
@ -30,7 +34,9 @@
|
|||||||
"options": "MAT-LCV-.YYYY.-",
|
"options": "MAT-LCV-.YYYY.-",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"set_only_once": 1
|
"set_only_once": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "company",
|
"fieldname": "company",
|
||||||
@ -40,24 +46,32 @@
|
|||||||
"label": "Company",
|
"label": "Company",
|
||||||
"options": "Company",
|
"options": "Company",
|
||||||
"remember_last_selected_value": 1,
|
"remember_last_selected_value": 1,
|
||||||
"reqd": 1
|
"reqd": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "purchase_receipts",
|
"fieldname": "purchase_receipts",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"label": "Purchase Receipts",
|
"label": "Purchase Receipts",
|
||||||
"options": "Landed Cost Purchase Receipt",
|
"options": "Landed Cost Purchase Receipt",
|
||||||
"reqd": 1
|
"reqd": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "purchase_receipt_items",
|
"fieldname": "purchase_receipt_items",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Purchase Receipt Items"
|
"label": "Purchase Receipt Items",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "get_items_from_purchase_receipts",
|
"fieldname": "get_items_from_purchase_receipts",
|
||||||
"fieldtype": "Button",
|
"fieldtype": "Button",
|
||||||
"label": "Get Items From Purchase Receipts"
|
"label": "Get Items From Purchase Receipts",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "items",
|
"fieldname": "items",
|
||||||
@ -65,42 +79,56 @@
|
|||||||
"label": "Purchase Receipt Items",
|
"label": "Purchase Receipt Items",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Landed Cost Item",
|
"options": "Landed Cost Item",
|
||||||
"reqd": 1
|
"reqd": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "sec_break1",
|
"fieldname": "sec_break1",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Applicable Charges"
|
"label": "Applicable Charges",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "taxes",
|
"fieldname": "taxes",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"label": "Taxes and Charges",
|
"label": "Taxes and Charges",
|
||||||
"options": "Landed Cost Taxes and Charges",
|
"options": "Landed Cost Taxes and Charges",
|
||||||
"reqd": 1
|
"reqd": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "section_break_9",
|
"fieldname": "section_break_9",
|
||||||
"fieldtype": "Section Break"
|
"fieldtype": "Section Break",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "total_taxes_and_charges",
|
"fieldname": "total_taxes_and_charges",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Total Taxes and Charges",
|
"label": "Total Taxes and Charges (Company Currency)",
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
"reqd": 1
|
"reqd": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "col_break1",
|
"fieldname": "col_break1",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "distribute_charges_based_on",
|
"fieldname": "distribute_charges_based_on",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"label": "Distribute Charges Based On",
|
"label": "Distribute Charges Based On",
|
||||||
"options": "Qty\nAmount",
|
"options": "Qty\nAmount\nDistribute Manually",
|
||||||
"reqd": 1
|
"reqd": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "amended_from",
|
"fieldname": "amended_from",
|
||||||
@ -109,21 +137,51 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Landed Cost Voucher",
|
"options": "Landed Cost Voucher",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "sec_break2",
|
"fieldname": "sec_break2",
|
||||||
"fieldtype": "Section Break"
|
"fieldtype": "Section Break",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "landed_cost_help",
|
"fieldname": "landed_cost_help",
|
||||||
"fieldtype": "HTML",
|
"fieldtype": "HTML",
|
||||||
"label": "Landed Cost Help"
|
"label": "Landed Cost Help",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_2",
|
||||||
|
"fieldtype": "Column Break",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "Today",
|
||||||
|
"fieldname": "posting_date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"label": "Posting Date",
|
||||||
|
"reqd": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_5",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"hide_border": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "icon-usd",
|
"icon": "icon-usd",
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"modified": "2019-11-21 15:34:10.846093",
|
"links": [],
|
||||||
|
"modified": "2021-01-25 23:07:30.468423",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Landed Cost Voucher",
|
"name": "Landed Cost Voucher",
|
||||||
|
@ -9,6 +9,7 @@ from frappe.model.meta import get_field_precision
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||||
from erpnext.accounts.doctype.account.account import get_account_currency
|
from erpnext.accounts.doctype.account.account import get_account_currency
|
||||||
|
from erpnext.controllers.taxes_and_totals import init_landed_taxes_and_totals
|
||||||
|
|
||||||
class LandedCostVoucher(Document):
|
class LandedCostVoucher(Document):
|
||||||
def get_items_from_purchase_receipts(self):
|
def get_items_from_purchase_receipts(self):
|
||||||
@ -39,13 +40,15 @@ class LandedCostVoucher(Document):
|
|||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.check_mandatory()
|
self.check_mandatory()
|
||||||
|
self.validate_purchase_receipts()
|
||||||
|
init_landed_taxes_and_totals(self)
|
||||||
|
self.set_total_taxes_and_charges()
|
||||||
if not self.get("items"):
|
if not self.get("items"):
|
||||||
self.get_items_from_purchase_receipts()
|
self.get_items_from_purchase_receipts()
|
||||||
else:
|
|
||||||
self.validate_applicable_charges_for_item()
|
self.set_applicable_charges_on_item()
|
||||||
self.validate_purchase_receipts()
|
self.validate_applicable_charges_for_item()
|
||||||
self.validate_expense_accounts()
|
|
||||||
self.set_total_taxes_and_charges()
|
|
||||||
|
|
||||||
def check_mandatory(self):
|
def check_mandatory(self):
|
||||||
if not self.get("purchase_receipts"):
|
if not self.get("purchase_receipts"):
|
||||||
@ -73,21 +76,37 @@ class LandedCostVoucher(Document):
|
|||||||
frappe.throw(_("Row {0}: Cost center is required for an item {1}")
|
frappe.throw(_("Row {0}: Cost center is required for an item {1}")
|
||||||
.format(item.idx, item.item_code))
|
.format(item.idx, item.item_code))
|
||||||
|
|
||||||
def validate_expense_accounts(self):
|
|
||||||
company_currency = erpnext.get_company_currency(self.company)
|
|
||||||
for account in self.taxes:
|
|
||||||
if get_account_currency(account.expense_account) != company_currency:
|
|
||||||
frappe.throw(_("Row {}: Expense account currency should be same as company's default currency.").format(account.idx)
|
|
||||||
+ _("Please select expense account with account currency as {}.").format(frappe.bold(company_currency)),
|
|
||||||
title=_("Invalid Account Currency"))
|
|
||||||
|
|
||||||
def set_total_taxes_and_charges(self):
|
def set_total_taxes_and_charges(self):
|
||||||
self.total_taxes_and_charges = sum([flt(d.amount) for d in self.get("taxes")])
|
self.total_taxes_and_charges = sum([flt(d.base_amount) for d in self.get("taxes")])
|
||||||
|
|
||||||
|
def set_applicable_charges_on_item(self):
|
||||||
|
if self.get('taxes') and self.distribute_charges_based_on != 'Distribute Manually':
|
||||||
|
total_item_cost = 0.0
|
||||||
|
total_charges = 0.0
|
||||||
|
item_count = 0
|
||||||
|
based_on_field = frappe.scrub(self.distribute_charges_based_on)
|
||||||
|
|
||||||
|
for item in self.get('items'):
|
||||||
|
total_item_cost += item.get(based_on_field)
|
||||||
|
|
||||||
|
for item in self.get('items'):
|
||||||
|
item.applicable_charges = flt(flt(item.get(based_on_field)) * (flt(self.total_taxes_and_charges) / flt(total_item_cost)),
|
||||||
|
item.precision('applicable_charges'))
|
||||||
|
total_charges += item.applicable_charges
|
||||||
|
item_count += 1
|
||||||
|
|
||||||
|
if total_charges != self.total_taxes_and_charges:
|
||||||
|
diff = self.total_taxes_and_charges - total_charges
|
||||||
|
self.get('items')[item_count - 1].applicable_charges += diff
|
||||||
|
|
||||||
def validate_applicable_charges_for_item(self):
|
def validate_applicable_charges_for_item(self):
|
||||||
based_on = self.distribute_charges_based_on.lower()
|
based_on = self.distribute_charges_based_on.lower()
|
||||||
|
|
||||||
total = sum([flt(d.get(based_on)) for d in self.get("items")])
|
if based_on != 'distribute manually':
|
||||||
|
total = sum([flt(d.get(based_on)) for d in self.get("items")])
|
||||||
|
else:
|
||||||
|
# consider for proportion while distributing manually
|
||||||
|
total = sum([flt(d.get('applicable_charges')) for d in self.get("items")])
|
||||||
|
|
||||||
if not total:
|
if not total:
|
||||||
frappe.throw(_("Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'").format(based_on))
|
frappe.throw(_("Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'").format(based_on))
|
||||||
@ -153,13 +172,13 @@ class LandedCostVoucher(Document):
|
|||||||
docs = frappe.db.get_all('Asset', filters={ receipt_document_type: item.receipt_document,
|
docs = frappe.db.get_all('Asset', filters={ receipt_document_type: item.receipt_document,
|
||||||
'item_code': item.item_code }, fields=['name', 'docstatus'])
|
'item_code': item.item_code }, fields=['name', 'docstatus'])
|
||||||
if not docs or len(docs) != item.qty:
|
if not docs or len(docs) != item.qty:
|
||||||
frappe.throw(_('There are not enough asset created or linked to {0}.').format(item.receipt_document)
|
frappe.throw(_('There are not enough asset created or linked to {0}. Please create or link {1} Assets with respective document.').format(
|
||||||
+ _('Please create or link {0} Assets with respective document.').format(item.qty))
|
item.receipt_document, item.qty))
|
||||||
if docs:
|
if docs:
|
||||||
for d in docs:
|
for d in docs:
|
||||||
if d.docstatus == 1:
|
if d.docstatus == 1:
|
||||||
frappe.throw(_('{0} {1} has submitted Assets. Remove Item {2} from table to continue.')
|
frappe.throw(_('{2} <b>{0}</b> has submitted Assets. Remove Item <b>{1}</b> from table to continue.').format(
|
||||||
.format(item.receipt_document_type, frappe.bold(item.receipt_document), frappe.bold(item.item_code)))
|
item.receipt_document, item.item_code, item.receipt_document_type))
|
||||||
|
|
||||||
def update_rate_in_serial_no_for_non_asset_items(self, receipt_document):
|
def update_rate_in_serial_no_for_non_asset_items(self, receipt_document):
|
||||||
for item in receipt_document.get("items"):
|
for item in receipt_document.get("items"):
|
||||||
|
@ -10,6 +10,7 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \
|
|||||||
import get_gl_entries, test_records as pr_test_records, make_purchase_receipt
|
import get_gl_entries, test_records as pr_test_records, make_purchase_receipt
|
||||||
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
||||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||||
|
from erpnext.accounts.doctype.account.test_account import create_account
|
||||||
|
|
||||||
class TestLandedCostVoucher(unittest.TestCase):
|
class TestLandedCostVoucher(unittest.TestCase):
|
||||||
def test_landed_cost_voucher(self):
|
def test_landed_cost_voucher(self):
|
||||||
@ -162,8 +163,8 @@ class TestLandedCostVoucher(unittest.TestCase):
|
|||||||
|
|
||||||
lcv = create_landed_cost_voucher("Purchase Receipt", pr.name, pr.company, 123.22)
|
lcv = create_landed_cost_voucher("Purchase Receipt", pr.name, pr.company, 123.22)
|
||||||
|
|
||||||
self.assertEqual(lcv.items[0].applicable_charges, 41.07)
|
self.assertEqual(flt(lcv.items[0].applicable_charges, 2), 41.07)
|
||||||
self.assertEqual(lcv.items[2].applicable_charges, 41.08)
|
self.assertEqual(flt(lcv.items[2].applicable_charges, 2), 41.08)
|
||||||
|
|
||||||
def test_multiple_landed_cost_voucher_against_pr(self):
|
def test_multiple_landed_cost_voucher_against_pr(self):
|
||||||
pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1",
|
pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1",
|
||||||
@ -206,6 +207,46 @@ class TestLandedCostVoucher(unittest.TestCase):
|
|||||||
self.assertEqual(pr.items[0].landed_cost_voucher_amount, 100)
|
self.assertEqual(pr.items[0].landed_cost_voucher_amount, 100)
|
||||||
self.assertEqual(pr.items[1].landed_cost_voucher_amount, 100)
|
self.assertEqual(pr.items[1].landed_cost_voucher_amount, 100)
|
||||||
|
|
||||||
|
def test_multi_currency_lcv(self):
|
||||||
|
## Create USD Shipping charges_account
|
||||||
|
usd_shipping = create_account(account_name="Shipping Charges USD",
|
||||||
|
parent_account="Duties and Taxes - TCP1", company="_Test Company with perpetual inventory",
|
||||||
|
account_currency="USD")
|
||||||
|
|
||||||
|
pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1",
|
||||||
|
supplier_warehouse = "Stores - TCP1")
|
||||||
|
pr.submit()
|
||||||
|
|
||||||
|
lcv = make_landed_cost_voucher(company = pr.company, receipt_document_type = "Purchase Receipt",
|
||||||
|
receipt_document=pr.name, charges=100, do_not_save=True)
|
||||||
|
|
||||||
|
lcv.append("taxes", {
|
||||||
|
"description": "Shipping Charges",
|
||||||
|
"expense_account": usd_shipping,
|
||||||
|
"amount": 10
|
||||||
|
})
|
||||||
|
|
||||||
|
lcv.save()
|
||||||
|
lcv.submit()
|
||||||
|
pr.load_from_db()
|
||||||
|
|
||||||
|
# Considering exchange rate from USD to INR as 62.9
|
||||||
|
self.assertEqual(lcv.total_taxes_and_charges, 729)
|
||||||
|
self.assertEqual(pr.items[0].landed_cost_voucher_amount, 729)
|
||||||
|
|
||||||
|
gl_entries = frappe.get_all("GL Entry", fields=["account", "credit", "credit_in_account_currency"],
|
||||||
|
filters={"voucher_no": pr.name, "account": ("in", ["Shipping Charges USD - TCP1", "Expenses Included In Valuation - TCP1"])})
|
||||||
|
|
||||||
|
expected_gl_entries = {
|
||||||
|
"Shipping Charges USD - TCP1": [629, 10],
|
||||||
|
"Expenses Included In Valuation - TCP1": [100, 100]
|
||||||
|
}
|
||||||
|
|
||||||
|
for entry in gl_entries:
|
||||||
|
amounts = expected_gl_entries.get(entry.account)
|
||||||
|
self.assertEqual(entry.credit, amounts[0])
|
||||||
|
self.assertEqual(entry.credit_in_account_currency, amounts[1])
|
||||||
|
|
||||||
def make_landed_cost_voucher(** args):
|
def make_landed_cost_voucher(** args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
ref_doc = frappe.get_doc(args.receipt_document_type, args.receipt_document)
|
ref_doc = frappe.get_doc(args.receipt_document_type, args.receipt_document)
|
||||||
|
@ -288,12 +288,15 @@ class PurchaseReceipt(BuyingController):
|
|||||||
# Amount added through landed-cost-voucher
|
# Amount added through landed-cost-voucher
|
||||||
if d.landed_cost_voucher_amount and landed_cost_entries:
|
if d.landed_cost_voucher_amount and landed_cost_entries:
|
||||||
for account, amount in iteritems(landed_cost_entries[(d.item_code, d.name)]):
|
for account, amount in iteritems(landed_cost_entries[(d.item_code, d.name)]):
|
||||||
|
account_currency = get_account_currency(account)
|
||||||
gl_entries.append(self.get_gl_dict({
|
gl_entries.append(self.get_gl_dict({
|
||||||
"account": account,
|
"account": account,
|
||||||
|
"account_currency": account_currency,
|
||||||
"against": warehouse_account[d.warehouse]["account"],
|
"against": warehouse_account[d.warehouse]["account"],
|
||||||
"cost_center": d.cost_center,
|
"cost_center": d.cost_center,
|
||||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||||
"credit": flt(amount),
|
"credit": flt(amount["base_amount"]),
|
||||||
|
"credit_in_account_currency": flt(amount["amount"]),
|
||||||
"project": d.project
|
"project": d.project
|
||||||
}, item=d))
|
}, item=d))
|
||||||
|
|
||||||
@ -728,7 +731,13 @@ def get_item_account_wise_additional_cost(purchase_document):
|
|||||||
|
|
||||||
for lcv in landed_cost_vouchers:
|
for lcv in landed_cost_vouchers:
|
||||||
landed_cost_voucher_doc = frappe.get_doc("Landed Cost Voucher", lcv.parent)
|
landed_cost_voucher_doc = frappe.get_doc("Landed Cost Voucher", lcv.parent)
|
||||||
based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
|
|
||||||
|
#Use amount field for total item cost for manually cost distributed LCVs
|
||||||
|
if landed_cost_voucher_doc.distribute_charges_based_on == 'Distribute Manually':
|
||||||
|
based_on_field = 'amount'
|
||||||
|
else:
|
||||||
|
based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
|
||||||
|
|
||||||
total_item_cost = 0
|
total_item_cost = 0
|
||||||
|
|
||||||
for item in landed_cost_voucher_doc.items:
|
for item in landed_cost_voucher_doc.items:
|
||||||
@ -738,9 +747,16 @@ def get_item_account_wise_additional_cost(purchase_document):
|
|||||||
if item.receipt_document == purchase_document:
|
if item.receipt_document == purchase_document:
|
||||||
for account in landed_cost_voucher_doc.taxes:
|
for account in landed_cost_voucher_doc.taxes:
|
||||||
item_account_wise_cost.setdefault((item.item_code, item.purchase_receipt_item), {})
|
item_account_wise_cost.setdefault((item.item_code, item.purchase_receipt_item), {})
|
||||||
item_account_wise_cost[(item.item_code, item.purchase_receipt_item)].setdefault(account.expense_account, 0.0)
|
item_account_wise_cost[(item.item_code, item.purchase_receipt_item)].setdefault(account.expense_account, {
|
||||||
item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][account.expense_account] += \
|
"amount": 0.0,
|
||||||
|
"base_amount": 0.0
|
||||||
|
})
|
||||||
|
|
||||||
|
item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][account.expense_account]["amount"] += \
|
||||||
account.amount * item.get(based_on_field) / total_item_cost
|
account.amount * item.get(based_on_field) / total_item_cost
|
||||||
|
|
||||||
|
item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][account.expense_account]["base_amount"] += \
|
||||||
|
account.base_amount * item.get(based_on_field) / total_item_cost
|
||||||
|
|
||||||
return item_account_wise_cost
|
return item_account_wise_cost
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
frappe.provide("erpnext.stock");
|
frappe.provide("erpnext.stock");
|
||||||
frappe.provide("erpnext.accounts.dimensions");
|
frappe.provide("erpnext.accounts.dimensions");
|
||||||
|
|
||||||
|
{% include 'erpnext/stock/landed_taxes_and_charges_common.js' %};
|
||||||
|
|
||||||
frappe.ui.form.on('Stock Entry', {
|
frappe.ui.form.on('Stock Entry', {
|
||||||
setup: function(frm) {
|
setup: function(frm) {
|
||||||
frm.set_indicator_formatter('item_code', function(doc) {
|
frm.set_indicator_formatter('item_code', function(doc) {
|
||||||
@ -95,15 +97,6 @@ frappe.ui.form.on('Stock Entry', {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
frm.set_query("expense_account", "additional_costs", function() {
|
|
||||||
return {
|
|
||||||
query: "erpnext.controllers.queries.tax_account_query",
|
|
||||||
filters: {
|
|
||||||
"account_type": ["Tax", "Chargeable", "Income Account", "Expenses Included In Valuation", "Expenses Included In Asset Valuation"],
|
|
||||||
"company": frm.doc.company
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
frm.add_fetch("bom_no", "inspection_required", "inspection_required");
|
frm.add_fetch("bom_no", "inspection_required", "inspection_required");
|
||||||
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
|
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
|
||||||
@ -559,7 +552,7 @@ frappe.ui.form.on('Stock Entry', {
|
|||||||
|
|
||||||
calculate_total_additional_costs: function(frm) {
|
calculate_total_additional_costs: function(frm) {
|
||||||
const total_additional_costs = frappe.utils.sum(
|
const total_additional_costs = frappe.utils.sum(
|
||||||
(frm.doc.additional_costs || []).map(function(c) { return flt(c.amount); })
|
(frm.doc.additional_costs || []).map(function(c) { return flt(c.base_amount); })
|
||||||
);
|
);
|
||||||
|
|
||||||
frm.set_value("total_additional_costs",
|
frm.set_value("total_additional_costs",
|
||||||
@ -738,8 +731,18 @@ var validate_sample_quantity = function(frm, cdt, cdn) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
frappe.ui.form.on('Landed Cost Taxes and Charges', {
|
frappe.ui.form.on('Landed Cost Taxes and Charges', {
|
||||||
amount: function(frm) {
|
amount: function(frm, cdt, cdn) {
|
||||||
frm.events.calculate_amount(frm);
|
frm.events.set_base_amount(frm, cdt, cdn);
|
||||||
|
|
||||||
|
// Adding this check because same table in used in LCV
|
||||||
|
// This causes an error if you try to post an LCV immediately after a Stock Entry
|
||||||
|
if (frm.doc.doctype == 'Stock Entry') {
|
||||||
|
frm.events.calculate_amount(frm);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
expense_account: function(frm, cdt, cdn) {
|
||||||
|
frm.events.set_account_currency(frm, cdt, cdn);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ from frappe.model.mapper import get_mapped_doc
|
|||||||
from erpnext.stock.doctype.serial_no.serial_no import update_serial_nos_after_submit, get_serial_nos
|
from erpnext.stock.doctype.serial_no.serial_no import update_serial_nos_after_submit, get_serial_nos
|
||||||
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import OpeningEntryAccountError
|
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import OpeningEntryAccountError
|
||||||
from erpnext.accounts.general_ledger import process_gl_map
|
from erpnext.accounts.general_ledger import process_gl_map
|
||||||
|
from erpnext.controllers.taxes_and_totals import init_landed_taxes_and_totals
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from six import string_types, itervalues, iteritems
|
from six import string_types, itervalues, iteritems
|
||||||
@ -195,7 +196,7 @@ class StockEntry(StockController):
|
|||||||
and (sed.t_warehouse is null or sed.t_warehouse = '')""", self.project, as_list=1)
|
and (sed.t_warehouse is null or sed.t_warehouse = '')""", self.project, as_list=1)
|
||||||
|
|
||||||
amount = amount[0][0] if amount else 0
|
amount = amount[0][0] if amount else 0
|
||||||
additional_costs = frappe.db.sql(""" select ifnull(sum(sed.amount), 0)
|
additional_costs = frappe.db.sql(""" select ifnull(sum(sed.base_amount), 0)
|
||||||
from
|
from
|
||||||
`tabStock Entry` se, `tabLanded Cost Taxes and Charges` sed
|
`tabStock Entry` se, `tabLanded Cost Taxes and Charges` sed
|
||||||
where
|
where
|
||||||
@ -445,6 +446,7 @@ class StockEntry(StockController):
|
|||||||
|
|
||||||
def calculate_rate_and_amount(self, reset_outgoing_rate=True, raise_error_if_no_rate=True):
|
def calculate_rate_and_amount(self, reset_outgoing_rate=True, raise_error_if_no_rate=True):
|
||||||
self.set_basic_rate(reset_outgoing_rate, raise_error_if_no_rate)
|
self.set_basic_rate(reset_outgoing_rate, raise_error_if_no_rate)
|
||||||
|
init_landed_taxes_and_totals(self)
|
||||||
self.distribute_additional_costs()
|
self.distribute_additional_costs()
|
||||||
self.update_valuation_rate()
|
self.update_valuation_rate()
|
||||||
self.set_total_incoming_outgoing_value()
|
self.set_total_incoming_outgoing_value()
|
||||||
@ -533,7 +535,7 @@ class StockEntry(StockController):
|
|||||||
if not any([d.item_code for d in self.items if d.t_warehouse]):
|
if not any([d.item_code for d in self.items if d.t_warehouse]):
|
||||||
self.additional_costs = []
|
self.additional_costs = []
|
||||||
|
|
||||||
self.total_additional_costs = sum([flt(t.amount) for t in self.get("additional_costs")])
|
self.total_additional_costs = sum([flt(t.base_amount) for t in self.get("additional_costs")])
|
||||||
|
|
||||||
if self.purpose in ("Repack", "Manufacture"):
|
if self.purpose in ("Repack", "Manufacture"):
|
||||||
incoming_items_cost = sum([flt(t.basic_amount) for t in self.get("items") if t.is_finished_item])
|
incoming_items_cost = sum([flt(t.basic_amount) for t in self.get("items") if t.is_finished_item])
|
||||||
@ -773,13 +775,19 @@ class StockEntry(StockController):
|
|||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
if d.t_warehouse:
|
if d.t_warehouse:
|
||||||
item_account_wise_additional_cost.setdefault((d.item_code, d.name), {})
|
item_account_wise_additional_cost.setdefault((d.item_code, d.name), {})
|
||||||
item_account_wise_additional_cost[(d.item_code, d.name)].setdefault(t.expense_account, 0.0)
|
item_account_wise_additional_cost[(d.item_code, d.name)].setdefault(t.expense_account, {
|
||||||
|
"amount": 0.0,
|
||||||
|
"base_amount": 0.0
|
||||||
|
})
|
||||||
|
|
||||||
multiply_based_on = d.basic_amount if total_basic_amount else d.qty
|
multiply_based_on = d.basic_amount if total_basic_amount else d.qty
|
||||||
|
|
||||||
item_account_wise_additional_cost[(d.item_code, d.name)][t.expense_account] += \
|
item_account_wise_additional_cost[(d.item_code, d.name)][t.expense_account]["amount"] += \
|
||||||
flt(t.amount * multiply_based_on) / divide_based_on
|
flt(t.amount * multiply_based_on) / divide_based_on
|
||||||
|
|
||||||
|
item_account_wise_additional_cost[(d.item_code, d.name)][t.expense_account]["base_amount"] += \
|
||||||
|
flt(t.base_amount * multiply_based_on) / divide_based_on
|
||||||
|
|
||||||
if item_account_wise_additional_cost:
|
if item_account_wise_additional_cost:
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
for account, amount in iteritems(item_account_wise_additional_cost.get((d.item_code, d.name), {})):
|
for account, amount in iteritems(item_account_wise_additional_cost.get((d.item_code, d.name), {})):
|
||||||
@ -790,7 +798,8 @@ class StockEntry(StockController):
|
|||||||
"against": d.expense_account,
|
"against": d.expense_account,
|
||||||
"cost_center": d.cost_center,
|
"cost_center": d.cost_center,
|
||||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||||
"credit": amount
|
"credit_in_account_currency": flt(amount["amount"]),
|
||||||
|
"credit": flt(amount["base_amount"])
|
||||||
}, item=d))
|
}, item=d))
|
||||||
|
|
||||||
gl_entries.append(self.get_gl_dict({
|
gl_entries.append(self.get_gl_dict({
|
||||||
@ -798,7 +807,7 @@ class StockEntry(StockController):
|
|||||||
"against": account,
|
"against": account,
|
||||||
"cost_center": d.cost_center,
|
"cost_center": d.cost_center,
|
||||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||||
"credit": -1 * amount # put it as negative credit instead of debit purposefully
|
"credit": -1 * amount['base_amount'] # put it as negative credit instead of debit purposefully
|
||||||
}, item=d))
|
}, item=d))
|
||||||
|
|
||||||
return process_gl_map(gl_entries)
|
return process_gl_map(gl_entries)
|
||||||
|
62
erpnext/stock/landed_taxes_and_charges_common.js
Normal file
62
erpnext/stock/landed_taxes_and_charges_common.js
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
let document_list = ['Landed Cost Voucher', 'Stock Entry'];
|
||||||
|
|
||||||
|
document_list.forEach((doctype) => {
|
||||||
|
frappe.ui.form.on(doctype, {
|
||||||
|
refresh: function(frm) {
|
||||||
|
let tax_field = frm.doc.doctype == 'Landed Cost Voucher' ? 'taxes' : 'additional_costs';
|
||||||
|
frm.set_query("expense_account", tax_field, function() {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
"account_type": ['in', ["Tax", "Chargeable", "Income Account", "Expenses Included In Valuation", "Expenses Included In Asset Valuation"]],
|
||||||
|
"company": frm.doc.company
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
set_account_currency: function(frm, cdt, cdn) {
|
||||||
|
let row = locals[cdt][cdn];
|
||||||
|
if (row.expense_account) {
|
||||||
|
frappe.db.get_value('Account', row.expense_account, 'account_currency', function(value) {
|
||||||
|
frappe.model.set_value(cdt, cdn, "account_currency", value.account_currency);
|
||||||
|
frm.events.set_exchange_rate(frm, cdt, cdn);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
set_exchange_rate: function(frm, cdt, cdn) {
|
||||||
|
let row = locals[cdt][cdn];
|
||||||
|
let company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
|
||||||
|
|
||||||
|
if (row.account_currency == company_currency) {
|
||||||
|
row.exchange_rate = 1;
|
||||||
|
frm.set_df_property('taxes', 'hidden', 1, row.name, 'exchange_rate');
|
||||||
|
} else if (!row.exchange_rate || row.exchange_rate == 1) {
|
||||||
|
frm.set_df_property('taxes', 'hidden', 0, row.name, 'exchange_rate');
|
||||||
|
frappe.call({
|
||||||
|
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_exchange_rate",
|
||||||
|
args: {
|
||||||
|
posting_date: frm.doc.posting_date,
|
||||||
|
account: row.expense_account,
|
||||||
|
account_currency: row.account_currency,
|
||||||
|
company: frm.doc.company
|
||||||
|
},
|
||||||
|
callback: function(r) {
|
||||||
|
if (r.message) {
|
||||||
|
frappe.model.set_value(cdt, cdn, "exchange_rate", r.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
frm.refresh_field('taxes');
|
||||||
|
},
|
||||||
|
|
||||||
|
set_base_amount: function(frm, cdt, cdn) {
|
||||||
|
let row = locals[cdt][cdn];
|
||||||
|
frappe.model.set_value(cdt, cdn, "base_amount",
|
||||||
|
flt(flt(row.amount)*row.exchange_rate, precision("base_amount", row)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user