Merge branch 'develop' into planning
This commit is contained in:
commit
d1bbb4c311
@ -524,7 +524,7 @@ frappe.ui.form.on("Purchase Invoice", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
if(frm.doc.__onload) {
|
if(frm.doc.__onload && frm.is_new()) {
|
||||||
if(frm.doc.supplier) {
|
if(frm.doc.supplier) {
|
||||||
frm.doc.apply_tds = frm.doc.__onload.supplier_tds ? 1 : 0;
|
frm.doc.apply_tds = frm.doc.__onload.supplier_tds ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,11 @@ def get_period_list(from_fiscal_year, to_fiscal_year, period_start_date, period_
|
|||||||
"from_date": start_date
|
"from_date": start_date
|
||||||
})
|
})
|
||||||
|
|
||||||
to_date = add_months(start_date, months_to_add)
|
if i==0 and filter_based_on == 'Date Range':
|
||||||
|
to_date = add_months(get_first_day(start_date), months_to_add)
|
||||||
|
else:
|
||||||
|
to_date = add_months(start_date, months_to_add)
|
||||||
|
|
||||||
start_date = to_date
|
start_date = to_date
|
||||||
|
|
||||||
# Subtract one day from to_date, as it may be first day in next fiscal year or month
|
# Subtract one day from to_date, as it may be first day in next fiscal year or month
|
||||||
|
@ -829,10 +829,10 @@ class AccountsController(TransactionBase):
|
|||||||
party_account_currency = get_party_account_currency(party_type, party, self.company)
|
party_account_currency = get_party_account_currency(party_type, party, self.company)
|
||||||
|
|
||||||
if (party_account_currency
|
if (party_account_currency
|
||||||
and party_account_currency != self.company_currency
|
and (self.currency != party_account_currency
|
||||||
and self.currency != party_account_currency):
|
and self.currency != self.company_currency)):
|
||||||
frappe.throw(_("Accounting Entry for {0}: {1} can only be made in currency: {2}")
|
frappe.throw(_("Accounting Entry for {0}: {1} can only be made in currency: {2}")
|
||||||
.format(party_type, party, party_account_currency), InvalidCurrency)
|
.format(party_type, party, frappe.bold(party_account_currency), InvalidCurrency))
|
||||||
|
|
||||||
# Note: not validating with gle account because we don't have the account
|
# Note: not validating with gle account because we don't have the account
|
||||||
# at quotation / sales order level and we shouldn't stop someone
|
# at quotation / sales order level and we shouldn't stop someone
|
||||||
@ -898,7 +898,7 @@ class AccountsController(TransactionBase):
|
|||||||
date = self.get("due_date")
|
date = self.get("due_date")
|
||||||
due_date = date or posting_date
|
due_date = date or posting_date
|
||||||
|
|
||||||
if party_account_currency == self.company_currency:
|
if self.company_currency == self.currency:
|
||||||
grand_total = self.get("base_rounded_total") or self.base_grand_total
|
grand_total = self.get("base_rounded_total") or self.base_grand_total
|
||||||
else:
|
else:
|
||||||
grand_total = self.get("rounded_total") or self.grand_total
|
grand_total = self.get("rounded_total") or self.grand_total
|
||||||
@ -959,7 +959,7 @@ class AccountsController(TransactionBase):
|
|||||||
for d in self.get("payment_schedule"):
|
for d in self.get("payment_schedule"):
|
||||||
total += flt(d.payment_amount)
|
total += flt(d.payment_amount)
|
||||||
|
|
||||||
if party_account_currency == self.company_currency:
|
if self.company_currency == self.currency:
|
||||||
total = flt(total, self.precision("base_grand_total"))
|
total = flt(total, self.precision("base_grand_total"))
|
||||||
grand_total = flt(self.get("base_rounded_total") or self.base_grand_total, self.precision('base_grand_total'))
|
grand_total = flt(self.get("base_rounded_total") or self.base_grand_total, self.precision('base_grand_total'))
|
||||||
else:
|
else:
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
"discharge_ordered_date",
|
"discharge_ordered_date",
|
||||||
"discharge_practitioner",
|
"discharge_practitioner",
|
||||||
"discharge_encounter",
|
"discharge_encounter",
|
||||||
"discharge_date",
|
"discharge_datetime",
|
||||||
"cb_discharge",
|
"cb_discharge",
|
||||||
"discharge_instructions",
|
"discharge_instructions",
|
||||||
"followup_date",
|
"followup_date",
|
||||||
@ -404,14 +404,15 @@
|
|||||||
"permlevel": 1
|
"permlevel": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "discharge_date",
|
"fieldname": "discharge_datetime",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Datetime",
|
||||||
"label": "Discharge Date",
|
"label": "Discharge Date",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-05-21 02:26:22.144575",
|
"modified": "2021-03-18 14:44:11.689956",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Healthcare",
|
"module": "Healthcare",
|
||||||
"name": "Inpatient Record",
|
"name": "Inpatient Record",
|
||||||
|
@ -151,7 +151,7 @@ def check_out_inpatient(inpatient_record):
|
|||||||
|
|
||||||
def discharge_patient(inpatient_record):
|
def discharge_patient(inpatient_record):
|
||||||
validate_inpatient_invoicing(inpatient_record)
|
validate_inpatient_invoicing(inpatient_record)
|
||||||
inpatient_record.discharge_date = today()
|
inpatient_record.discharge_datetime = now_datetime()
|
||||||
inpatient_record.status = "Discharged"
|
inpatient_record.status = "Discharged"
|
||||||
|
|
||||||
inpatient_record.save(ignore_permissions = True)
|
inpatient_record.save(ignore_permissions = True)
|
||||||
|
@ -324,6 +324,7 @@ scheduler_events = {
|
|||||||
"erpnext.hr.doctype.shift_type.shift_type.process_auto_attendance_for_all_shifts",
|
"erpnext.hr.doctype.shift_type.shift_type.process_auto_attendance_for_all_shifts",
|
||||||
"erpnext.support.doctype.issue.issue.set_service_level_agreement_variance",
|
"erpnext.support.doctype.issue.issue.set_service_level_agreement_variance",
|
||||||
"erpnext.erpnext_integrations.connectors.shopify_connection.sync_old_orders",
|
"erpnext.erpnext_integrations.connectors.shopify_connection.sync_old_orders",
|
||||||
|
"erpnext.stock.doctype.repost_item_valuation.repost_item_valuation.repost_entries"
|
||||||
],
|
],
|
||||||
"daily": [
|
"daily": [
|
||||||
"erpnext.stock.reorder_item.reorder_item",
|
"erpnext.stock.reorder_item.reorder_item",
|
||||||
|
@ -275,6 +275,11 @@ class TestLoan(unittest.TestCase):
|
|||||||
frappe.db.sql(""" UPDATE `tabLoan Security Price` SET loan_security_price = 250
|
frappe.db.sql(""" UPDATE `tabLoan Security Price` SET loan_security_price = 250
|
||||||
where loan_security='Test Security 2'""")
|
where loan_security='Test Security 2'""")
|
||||||
|
|
||||||
|
create_process_loan_security_shortfall()
|
||||||
|
loan_security_shortfall = frappe.get_doc("Loan Security Shortfall", {"loan": loan.name})
|
||||||
|
self.assertEquals(loan_security_shortfall.status, "Completed")
|
||||||
|
self.assertEquals(loan_security_shortfall.shortfall_amount, 0)
|
||||||
|
|
||||||
def test_loan_security_unpledge(self):
|
def test_loan_security_unpledge(self):
|
||||||
pledge = [{
|
pledge = [{
|
||||||
"loan_security": "Test Security 1",
|
"loan_security": "Test Security 1",
|
||||||
|
@ -55,6 +55,9 @@ def check_for_ltv_shortfall(process_loan_security_shortfall):
|
|||||||
'total_interest_payable', 'disbursed_amount', 'status'],
|
'total_interest_payable', 'disbursed_amount', 'status'],
|
||||||
filters={'status': ('in',['Disbursed','Partially Disbursed']), 'is_secured_loan': 1})
|
filters={'status': ('in',['Disbursed','Partially Disbursed']), 'is_secured_loan': 1})
|
||||||
|
|
||||||
|
loan_shortfall_map = frappe._dict(frappe.get_all("Loan Security Shortfall",
|
||||||
|
fields=["loan", "name"], filters={"status": "Pending"}, as_list=1))
|
||||||
|
|
||||||
loan_security_map = {}
|
loan_security_map = {}
|
||||||
|
|
||||||
for loan in loans:
|
for loan in loans:
|
||||||
@ -71,14 +74,19 @@ def check_for_ltv_shortfall(process_loan_security_shortfall):
|
|||||||
for security, qty in pledged_securities.items():
|
for security, qty in pledged_securities.items():
|
||||||
if not ltv_ratio:
|
if not ltv_ratio:
|
||||||
ltv_ratio = get_ltv_ratio(security)
|
ltv_ratio = get_ltv_ratio(security)
|
||||||
security_value += loan_security_price_map.get(security) * qty
|
security_value += flt(loan_security_price_map.get(security)) * flt(qty)
|
||||||
|
|
||||||
current_ratio = (outstanding_amount/security_value) * 100
|
current_ratio = (outstanding_amount/security_value) * 100 if security_value else 0
|
||||||
|
|
||||||
if current_ratio > ltv_ratio:
|
if current_ratio > ltv_ratio:
|
||||||
shortfall_amount = outstanding_amount - ((security_value * ltv_ratio) / 100)
|
shortfall_amount = outstanding_amount - ((security_value * ltv_ratio) / 100)
|
||||||
create_loan_security_shortfall(loan.name, outstanding_amount, security_value, shortfall_amount,
|
create_loan_security_shortfall(loan.name, outstanding_amount, security_value, shortfall_amount,
|
||||||
process_loan_security_shortfall)
|
process_loan_security_shortfall)
|
||||||
|
elif loan_shortfall_map.get(loan.name):
|
||||||
|
shortfall_amount = outstanding_amount - ((security_value * ltv_ratio) / 100)
|
||||||
|
if shortfall_amount <= 0:
|
||||||
|
shortfall = loan_shortfall_map.get(loan.name)
|
||||||
|
update_pending_shortfall(shortfall)
|
||||||
|
|
||||||
def create_loan_security_shortfall(loan, loan_amount, security_value, shortfall_amount, process_loan_security_shortfall):
|
def create_loan_security_shortfall(loan, loan_amount, security_value, shortfall_amount, process_loan_security_shortfall):
|
||||||
existing_shortfall = frappe.db.get_value("Loan Security Shortfall", {"loan": loan, "status": "Pending"}, "name")
|
existing_shortfall = frappe.db.get_value("Loan Security Shortfall", {"loan": loan, "status": "Pending"}, "name")
|
||||||
@ -101,3 +109,11 @@ def get_ltv_ratio(loan_security):
|
|||||||
ltv_ratio = frappe.db.get_value('Loan Security Type', loan_security_type, 'loan_to_value_ratio')
|
ltv_ratio = frappe.db.get_value('Loan Security Type', loan_security_type, 'loan_to_value_ratio')
|
||||||
return ltv_ratio
|
return ltv_ratio
|
||||||
|
|
||||||
|
def update_pending_shortfall(shortfall):
|
||||||
|
# Get all pending loan security shortfall
|
||||||
|
frappe.db.set_value("Loan Security Shortfall", shortfall,
|
||||||
|
{
|
||||||
|
"status": "Completed",
|
||||||
|
"shortfall_amount": 0
|
||||||
|
})
|
||||||
|
|
||||||
|
@ -255,6 +255,9 @@ class JobCard(Document):
|
|||||||
data.actual_operation_time = time_in_mins
|
data.actual_operation_time = time_in_mins
|
||||||
data.actual_start_time = time_data[0].start_time if time_data else None
|
data.actual_start_time = time_data[0].start_time if time_data else None
|
||||||
data.actual_end_time = time_data[0].end_time if time_data else None
|
data.actual_end_time = time_data[0].end_time if time_data else None
|
||||||
|
if data.get("workstation") != self.workstation:
|
||||||
|
# workstations can change in a job card
|
||||||
|
data.workstation = self.workstation
|
||||||
|
|
||||||
wo.flags.ignore_validate_update_after_submit = True
|
wo.flags.ignore_validate_update_after_submit = True
|
||||||
wo.update_operation_status()
|
wo.update_operation_status()
|
||||||
|
@ -333,8 +333,7 @@
|
|||||||
"fieldname": "operations",
|
"fieldname": "operations",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"label": "Operations",
|
"label": "Operations",
|
||||||
"options": "Work Order Operation",
|
"options": "Work Order Operation"
|
||||||
"read_only": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "operations",
|
"depends_on": "operations",
|
||||||
@ -496,7 +495,7 @@
|
|||||||
"image_field": "image",
|
"image_field": "image",
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-05-05 19:32:43.323054",
|
"modified": "2021-03-16 13:27:51.116484",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "Work Order",
|
"name": "Work Order",
|
||||||
|
@ -61,7 +61,7 @@ class ForecastingReport(ExponentialSmoothingForecast):
|
|||||||
|
|
||||||
from_date = add_years(self.filters.from_date, cint(self.filters.no_of_years) * -1)
|
from_date = add_years(self.filters.from_date, cint(self.filters.no_of_years) * -1)
|
||||||
self.period_list = get_period_list(from_date, self.filters.to_date,
|
self.period_list = get_period_list(from_date, self.filters.to_date,
|
||||||
from_date, self.filters.to_date, None, self.filters.periodicity, ignore_fiscal_year=True)
|
from_date, self.filters.to_date, "Date Range", self.filters.periodicity, ignore_fiscal_year=True)
|
||||||
|
|
||||||
order_data = self.get_data_for_forecast() or []
|
order_data = self.get_data_for_forecast() or []
|
||||||
|
|
||||||
|
@ -760,3 +760,4 @@ erpnext.patches.v13_0.setup_fields_for_80g_certificate_and_donation
|
|||||||
erpnext.patches.v13_0.rename_membership_settings_to_non_profit_settings
|
erpnext.patches.v13_0.rename_membership_settings_to_non_profit_settings
|
||||||
erpnext.patches.v13_0.setup_gratuity_rule_for_india_and_uae
|
erpnext.patches.v13_0.setup_gratuity_rule_for_india_and_uae
|
||||||
execute:frappe.db.set_value('System Settings', None, 'app_name', 'ERPNext')
|
execute:frappe.db.set_value('System Settings', None, 'app_name', 'ERPNext')
|
||||||
|
erpnext.patches.v13_0.rename_discharge_date_in_ip_record
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from frappe.model.utils.rename_field import rename_field
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
frappe.reload_doc("Healthcare", "doctype", "Inpatient Record")
|
||||||
|
if frappe.db.has_column("Inpatient Record", "discharge_date"):
|
||||||
|
rename_field("Inpatient Record", "discharge_date", "discharge_datetime")
|
@ -738,21 +738,15 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var valid_serial_nos = [];
|
var valid_serial_nos = [];
|
||||||
|
var serialnos = [];
|
||||||
// Replacing all occurences of comma with carriage return
|
// Replacing all occurences of comma with carriage return
|
||||||
var serial_nos = item.serial_no.trim().replace(/,/g, '\n');
|
item.serial_no = item.serial_no.replace(/,/g, '\n');
|
||||||
|
serialnos = item.serial_no.split("\n");
|
||||||
serial_nos = serial_nos.trim().split('\n');
|
for (var i = 0; i < serialnos.length; i++) {
|
||||||
|
if (serialnos[i] != "") {
|
||||||
// Trim each string and push unique string to new list
|
valid_serial_nos.push(serialnos[i]);
|
||||||
for (var x=0; x<=serial_nos.length - 1; x++) {
|
|
||||||
if (serial_nos[x].trim() != "" && valid_serial_nos.indexOf(serial_nos[x].trim()) == -1) {
|
|
||||||
valid_serial_nos.push(serial_nos[x].trim());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the new list to the serial no. field in grid with each in new line
|
|
||||||
item.serial_no = valid_serial_nos.join('\n');
|
|
||||||
item.conversion_factor = item.conversion_factor || 1;
|
item.conversion_factor = item.conversion_factor || 1;
|
||||||
|
|
||||||
refresh_field("serial_no", item.name, item.parentfield);
|
refresh_field("serial_no", item.name, item.parentfield);
|
||||||
|
@ -10,6 +10,7 @@ from frappe import msgprint, throw, _
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.model.naming import parse_naming_series
|
from frappe.model.naming import parse_naming_series
|
||||||
from frappe.permissions import get_doctypes_with_read
|
from frappe.permissions import get_doctypes_with_read
|
||||||
|
from frappe.core.doctype.doctype.doctype import validate_series
|
||||||
|
|
||||||
class NamingSeriesNotSetError(frappe.ValidationError): pass
|
class NamingSeriesNotSetError(frappe.ValidationError): pass
|
||||||
|
|
||||||
@ -126,7 +127,7 @@ class NamingSeries(Document):
|
|||||||
dt = frappe.get_doc("DocType", self.select_doc_for_series)
|
dt = frappe.get_doc("DocType", self.select_doc_for_series)
|
||||||
options = self.scrub_options_list(self.set_options.split("\n"))
|
options = self.scrub_options_list(self.set_options.split("\n"))
|
||||||
for series in options:
|
for series in options:
|
||||||
dt.validate_series(series)
|
validate_series(dt, series)
|
||||||
for i in sr:
|
for i in sr:
|
||||||
if i[0]:
|
if i[0]:
|
||||||
existing_series = [d.split('.')[0] for d in i[0].split("\n")]
|
existing_series = [d.split('.')[0] for d in i[0].split("\n")]
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe, erpnext
|
import frappe, erpnext
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import cint, get_link_to_form
|
from frappe.utils import cint, get_link_to_form, add_to_date, today
|
||||||
from erpnext.stock.stock_ledger import repost_future_sle
|
from erpnext.stock.stock_ledger import repost_future_sle
|
||||||
from erpnext.accounts.utils import update_gl_entries_after, check_if_stock_and_account_balance_synced
|
from erpnext.accounts.utils import update_gl_entries_after, check_if_stock_and_account_balance_synced
|
||||||
from frappe.utils.user import get_users_with_role
|
from frappe.utils.user import get_users_with_role
|
||||||
@ -54,7 +54,6 @@ def repost(doc):
|
|||||||
|
|
||||||
repost_sl_entries(doc)
|
repost_sl_entries(doc)
|
||||||
repost_gl_entries(doc)
|
repost_gl_entries(doc)
|
||||||
check_if_stock_and_account_balance_synced(doc.posting_date, doc.company)
|
|
||||||
|
|
||||||
doc.set_status('Completed')
|
doc.set_status('Completed')
|
||||||
except Exception:
|
except Exception:
|
||||||
@ -112,4 +111,24 @@ def notify_error_to_stock_managers(doc, traceback):
|
|||||||
)
|
)
|
||||||
frappe.sendmail(recipients=recipients, subject=subject, message=message)
|
frappe.sendmail(recipients=recipients, subject=subject, message=message)
|
||||||
|
|
||||||
|
def repost_entries():
|
||||||
|
riv_entries = get_repost_item_valuation_entries()
|
||||||
|
|
||||||
|
for row in riv_entries:
|
||||||
|
doc = frappe.get_cached_doc('Repost Item Valuation', row.name)
|
||||||
|
repost(doc)
|
||||||
|
|
||||||
|
riv_entries = get_repost_item_valuation_entries()
|
||||||
|
if riv_entries:
|
||||||
|
return
|
||||||
|
|
||||||
|
for d in frappe.get_all('Company', filters= {'enable_perpetual_inventory': 1}):
|
||||||
|
check_if_stock_and_account_balance_synced(today(), d.company)
|
||||||
|
|
||||||
|
def get_repost_item_valuation_entries():
|
||||||
|
date = add_to_date(today(), hours=-12)
|
||||||
|
|
||||||
|
return frappe.db.sql(""" SELECT name from `tabRepost Item Valuation`
|
||||||
|
WHERE status != 'Completed' and creation <= %s and docstatus = 1
|
||||||
|
ORDER BY timestamp(posting_date, posting_time) asc, creation asc
|
||||||
|
""", date, as_dict=1)
|
@ -29,6 +29,8 @@ class StockReconciliation(StockController):
|
|||||||
self.remove_items_with_no_change()
|
self.remove_items_with_no_change()
|
||||||
self.validate_data()
|
self.validate_data()
|
||||||
self.validate_expense_account()
|
self.validate_expense_account()
|
||||||
|
self.validate_customer_provided_item()
|
||||||
|
self.set_zero_value_for_customer_provided_items()
|
||||||
self.set_total_qty_and_amount()
|
self.set_total_qty_and_amount()
|
||||||
self.validate_putaway_capacity()
|
self.validate_putaway_capacity()
|
||||||
|
|
||||||
@ -217,7 +219,7 @@ class StockReconciliation(StockController):
|
|||||||
if row.valuation_rate in ("", None):
|
if row.valuation_rate in ("", None):
|
||||||
row.valuation_rate = previous_sle.get("valuation_rate", 0)
|
row.valuation_rate = previous_sle.get("valuation_rate", 0)
|
||||||
|
|
||||||
if row.qty and not row.valuation_rate:
|
if row.qty and not row.valuation_rate and not row.allow_zero_valuation_rate:
|
||||||
frappe.throw(_("Valuation Rate required for Item {0} at row {1}").format(row.item_code, row.idx))
|
frappe.throw(_("Valuation Rate required for Item {0} at row {1}").format(row.item_code, row.idx))
|
||||||
|
|
||||||
if ((previous_sle and row.qty == previous_sle.get("qty_after_transaction")
|
if ((previous_sle and row.qty == previous_sle.get("qty_after_transaction")
|
||||||
@ -436,6 +438,20 @@ class StockReconciliation(StockController):
|
|||||||
if frappe.db.get_value("Account", self.expense_account, "report_type") == "Profit and Loss":
|
if frappe.db.get_value("Account", self.expense_account, "report_type") == "Profit and Loss":
|
||||||
frappe.throw(_("Difference Account must be a Asset/Liability type account, since this Stock Reconciliation is an Opening Entry"), OpeningEntryAccountError)
|
frappe.throw(_("Difference Account must be a Asset/Liability type account, since this Stock Reconciliation is an Opening Entry"), OpeningEntryAccountError)
|
||||||
|
|
||||||
|
def set_zero_value_for_customer_provided_items(self):
|
||||||
|
changed_any_values = False
|
||||||
|
|
||||||
|
for d in self.get('items'):
|
||||||
|
is_customer_item = frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item')
|
||||||
|
if is_customer_item and d.valuation_rate:
|
||||||
|
d.valuation_rate = 0.0
|
||||||
|
changed_any_values = True
|
||||||
|
|
||||||
|
if changed_any_values:
|
||||||
|
msgprint(_("Valuation rate for customer provided items has been set to zero."),
|
||||||
|
title=_("Note"), indicator="blue")
|
||||||
|
|
||||||
|
|
||||||
def set_total_qty_and_amount(self):
|
def set_total_qty_and_amount(self):
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
d.amount = flt(d.qty, d.precision("qty")) * flt(d.valuation_rate, d.precision("valuation_rate"))
|
d.amount = flt(d.qty, d.precision("qty")) * flt(d.valuation_rate, d.precision("valuation_rate"))
|
||||||
|
@ -193,6 +193,16 @@ class TestStockReconciliation(unittest.TestCase):
|
|||||||
stock_doc = frappe.get_doc("Stock Reconciliation", d)
|
stock_doc = frappe.get_doc("Stock Reconciliation", d)
|
||||||
stock_doc.cancel()
|
stock_doc.cancel()
|
||||||
|
|
||||||
|
def test_customer_provided_items(self):
|
||||||
|
item_code = 'Stock-Reco-customer-Item-100'
|
||||||
|
create_item(item_code, is_customer_provided_item = 1,
|
||||||
|
customer = '_Test Customer', is_purchase_item = 0)
|
||||||
|
|
||||||
|
sr = create_stock_reconciliation(item_code = item_code, qty = 10, rate = 420)
|
||||||
|
|
||||||
|
self.assertEqual(sr.get("items")[0].allow_zero_valuation_rate, 1)
|
||||||
|
self.assertEqual(sr.get("items")[0].valuation_rate, 0)
|
||||||
|
self.assertEqual(sr.get("items")[0].amount, 0)
|
||||||
|
|
||||||
def insert_existing_sle(warehouse):
|
def insert_existing_sle(warehouse):
|
||||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
"qty",
|
"qty",
|
||||||
"valuation_rate",
|
"valuation_rate",
|
||||||
"amount",
|
"amount",
|
||||||
|
"allow_zero_valuation_rate",
|
||||||
"serial_no_and_batch_section",
|
"serial_no_and_batch_section",
|
||||||
"serial_no",
|
"serial_no",
|
||||||
"column_break_11",
|
"column_break_11",
|
||||||
@ -166,10 +167,19 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Batch No",
|
"label": "Batch No",
|
||||||
"options": "Batch"
|
"options": "Batch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "allow_zero_valuation_rate",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Allow Zero Valuation Rate",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2019-06-14 17:10:53.188305",
|
"links": [],
|
||||||
|
"modified": "2021-03-23 11:09:44.407157",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Stock Reconciliation Item",
|
"name": "Stock Reconciliation Item",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user