Merge branch 'hotfix' into hotfix-customer-item-price-report

This commit is contained in:
Suraj Shetty
2019-07-17 17:29:27 +05:30
committed by GitHub
22 changed files with 143 additions and 84 deletions

View File

@@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
__version__ = '11.1.46'
__version__ = '11.1.47'
def get_default_company(user=None):
'''Get default company for user'''

View File

@@ -121,7 +121,7 @@ frappe.treeview_settings["Account"] = {
},
onrender: function(node) {
if(frappe.boot.user.can_read.indexOf("GL Entry") !== -1){
var dr_or_cr = node.data.balance < 0 ? "Cr" : "Dr";
var dr_or_cr = in_list(["Liability", "Income", "Equity"], node.data.root_type) ? "Cr" : "Dr";
if (node.data && node.data.balance!==undefined) {
$('<span class="balance-area pull-right text-muted small">'
+ (node.data.balance_in_account_currency ?

View File

@@ -38,7 +38,7 @@ def get_loyalty_details(customer, loyalty_program, expiry_date=None, company=Non
@frappe.whitelist()
def get_loyalty_program_details_with_points(customer, loyalty_program=None, expiry_date=None, company=None, silent=False, include_expired_entry=False, current_transaction_amount=0):
lp_details = get_loyalty_program_details(customer, loyalty_program, company=company, silent=silent)
loyalty_program = frappe.get_doc("Loyalty Program", loyalty_program)
loyalty_program = frappe.get_doc("Loyalty Program", loyalty_program or lp_details.loyalty_program)
lp_details.update(get_loyalty_details(customer, loyalty_program.name, expiry_date, company, include_expired_entry))
tier_spent_level = sorted([d.as_dict() for d in loyalty_program.collection_rules],

View File

@@ -558,7 +558,7 @@ def get_outstanding_reference_documents(args):
# Get negative outstanding sales /purchase invoices
negative_outstanding_invoices = []
if args.get("party_type") not in ["Student", "Employee"] and not args.get("voucher_no"):
if args.get("party_type") in ("Supplier", "Customer") and not args.get("voucher_no"):
negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"),
args.get("party"), args.get("party_account"), party_account_currency, company_currency)
@@ -589,7 +589,7 @@ def get_outstanding_reference_documents(args):
# Get all SO / PO which are not fully billed or aginst which full advance not paid
orders_to_be_billed = []
if (args.get("party_type") != "Student"):
if (args.get("party_type") in ("Supplier", "Customer")):
orders_to_be_billed = get_orders_to_be_billed(args.get("posting_date"),args.get("party_type"),
args.get("party"), party_account_currency, company_currency)
@@ -601,7 +601,7 @@ def get_orders_to_be_billed(posting_date, party_type, party, party_account_curre
voucher_type = 'Sales Order'
elif party_type == "Supplier":
voucher_type = 'Purchase Order'
elif party_type == "Employee":
else:
voucher_type = None
# Add cost center condition

View File

@@ -73,6 +73,12 @@ frappe.query_reports["Accounts Payable"] = {
}
}
},
{
"fieldname":"payment_terms_template",
"label": __("Payment Terms Template"),
"fieldtype": "Link",
"options": "Payment Terms Template"
},
{
"fieldname":"supplier_group",
"label": __("Supplier Group"),

View File

@@ -63,6 +63,12 @@ frappe.query_reports["Accounts Payable Summary"] = {
"fieldtype": "Link",
"options": "Supplier"
},
{
"fieldname":"payment_terms_template",
"label": __("Payment Terms Template"),
"fieldtype": "Link",
"options": "Payment Terms Template"
},
{
"fieldname":"supplier_group",
"label": __("Supplier Group"),

View File

@@ -540,6 +540,10 @@ class ReceivablePayableReport(object):
where supplier_group=%s)""")
values.append(self.filters.get("supplier_group"))
if self.filters.get("payment_terms_template"):
conditions.append("party in (select name from tabSupplier where payment_terms=%s)")
values.append(self.filters.get("payment_terms_template"))
accounts = [d.name for d in frappe.get_all("Account",
filters={"account_type": account_type, "company": self.filters.company})]
conditions.append("account in (%s)" % ','.join(['%s'] *len(accounts)))

View File

@@ -12,11 +12,11 @@ def execute(filters=None):
columns = get_columns()
if not filters.get("account"): return columns, []
account_currency = frappe.db.get_value("Account", filters.account, "account_currency")
data = get_entries(filters)
from erpnext.accounts.utils import get_balance_on
balance_as_per_system = get_balance_on(filters["account"], filters["report_date"])
@@ -24,7 +24,7 @@ def execute(filters=None):
for d in data:
total_debit += flt(d.debit)
total_credit += flt(d.credit)
amounts_not_reflected_in_system = get_amounts_not_reflected_in_system(filters)
bank_bal = flt(balance_as_per_system) - flt(total_debit) + flt(total_credit) \
@@ -39,7 +39,7 @@ def execute(filters=None):
"credit": total_credit,
"account_currency": account_currency
},
get_balance_row(_("Cheques and Deposits incorrectly cleared"), amounts_not_reflected_in_system,
get_balance_row(_("Cheques and Deposits incorrectly cleared"), amounts_not_reflected_in_system,
account_currency),
{},
get_balance_row(_("Calculated Bank Statement balance"), bank_bal, account_currency)
@@ -58,8 +58,8 @@ def get_columns():
{
"fieldname": "payment_entry",
"label": _("Payment Entry"),
"fieldtype": "Dynamic Link",
"options": "payment_document",
"fieldtype": "Link",
"options": "Payment Entry",
"width": 220
},
{
@@ -100,7 +100,7 @@ def get_columns():
"label": _("Clearance Date"),
"fieldtype": "Date",
"width": 110
},
},
{
"fieldname": "account_currency",
"label": _("Currency"),
@@ -112,9 +112,9 @@ def get_columns():
def get_entries(filters):
journal_entries = frappe.db.sql("""
select "Journal Entry" as payment_document, jv.posting_date,
jv.name as payment_entry, jvd.debit_in_account_currency as debit,
jvd.credit_in_account_currency as credit, jvd.against_account,
select "Journal Entry" as payment_document, jv.posting_date,
jv.name as payment_entry, jvd.debit_in_account_currency as debit,
jvd.credit_in_account_currency as credit, jvd.against_account,
jv.cheque_no as reference_no, jv.cheque_date as ref_date, jv.clearance_date, jvd.account_currency
from
`tabJournal Entry Account` jvd, `tabJournal Entry` jv
@@ -122,13 +122,13 @@ def get_entries(filters):
and jvd.account = %(account)s and jv.posting_date <= %(report_date)s
and ifnull(jv.clearance_date, '4000-01-01') > %(report_date)s
and ifnull(jv.is_opening, 'No') = 'No'""", filters, as_dict=1)
payment_entries = frappe.db.sql("""
select
"Payment Entry" as payment_document, name as payment_entry,
reference_no, reference_date as ref_date,
if(paid_to=%(account)s, received_amount, 0) as debit,
if(paid_from=%(account)s, paid_amount, 0) as credit,
select
"Payment Entry" as payment_document, name as payment_entry,
reference_no, reference_date as ref_date,
if(paid_to=%(account)s, received_amount, 0) as debit,
if(paid_from=%(account)s, paid_amount, 0) as credit,
posting_date, ifnull(party,if(paid_from=%(account)s,paid_to,paid_from)) as against_account, clearance_date,
if(paid_to=%(account)s, paid_to_account_currency, paid_from_account_currency) as account_currency
from `tabPayment Entry`
@@ -156,25 +156,25 @@ def get_entries(filters):
return sorted(list(payment_entries)+list(journal_entries+list(pos_entries)),
key=lambda k: k['posting_date'] or getdate(nowdate()))
def get_amounts_not_reflected_in_system(filters):
je_amount = frappe.db.sql("""
select sum(jvd.debit_in_account_currency - jvd.credit_in_account_currency)
from `tabJournal Entry Account` jvd, `tabJournal Entry` jv
where jvd.parent = jv.name and jv.docstatus=1 and jvd.account=%(account)s
and jv.posting_date > %(report_date)s and jv.clearance_date <= %(report_date)s
and jv.posting_date > %(report_date)s and jv.clearance_date <= %(report_date)s
and ifnull(jv.is_opening, 'No') = 'No' """, filters)
je_amount = flt(je_amount[0][0]) if je_amount else 0.0
pe_amount = frappe.db.sql("""
select sum(if(paid_from=%(account)s, paid_amount, received_amount))
from `tabPayment Entry`
where (paid_from=%(account)s or paid_to=%(account)s) and docstatus=1
where (paid_from=%(account)s or paid_to=%(account)s) and docstatus=1
and posting_date > %(report_date)s and clearance_date <= %(report_date)s""", filters)
pe_amount = flt(pe_amount[0][0]) if pe_amount else 0.0
return je_amount + pe_amount
def get_balance_row(label, amount, account_currency):

View File

@@ -10,6 +10,7 @@ from frappe import _, _dict
from erpnext.accounts.utils import get_account_currency
from erpnext.accounts.report.financial_statements import get_cost_centers_with_children
from six import iteritems
from collections import OrderedDict
def execute(filters=None):
if not filters:
@@ -269,7 +270,7 @@ def group_by_field(group_by):
return 'voucher_no'
def initialize_gle_map(gl_entries, filters):
gle_map = frappe._dict()
gle_map = OrderedDict()
group_by = group_by_field(filters.get('group_by'))
for gle in gl_entries:

View File

@@ -104,6 +104,9 @@ def get_balance_on(account=None, date=None, party_type=None, party=None, company
# get balance of all entries that exist
date = nowdate()
if account:
acc = frappe.get_doc("Account", account)
try:
year_start_date = get_fiscal_year(date, verbose=0)[1]
except FiscalYearError:
@@ -118,7 +121,7 @@ def get_balance_on(account=None, date=None, party_type=None, party=None, company
allow_cost_center_in_entry_of_bs_account = get_allow_cost_center_in_entry_of_bs_account()
if cost_center and allow_cost_center_in_entry_of_bs_account:
if cost_center and (allow_cost_center_in_entry_of_bs_account or acc.report_type =='Profit and Loss'):
cc = frappe.get_doc("Cost Center", cost_center)
if cc.is_group:
cond.append(""" exists (
@@ -132,20 +135,13 @@ def get_balance_on(account=None, date=None, party_type=None, party=None, company
if account:
acc = frappe.get_doc("Account", account)
if not frappe.flags.ignore_account_permission:
acc.check_permission("read")
if not allow_cost_center_in_entry_of_bs_account and acc.report_type == 'Profit and Loss':
if acc.report_type == 'Profit and Loss':
# for pl accounts, get balance within a fiscal year
cond.append("posting_date >= '%s' and voucher_type != 'Period Closing Voucher'" \
% year_start_date)
elif allow_cost_center_in_entry_of_bs_account:
# for all accounts, get balance within a fiscal year if maintain cost center in balance account is checked
cond.append("posting_date >= '%s' and voucher_type != 'Period Closing Voucher'" \
% year_start_date)
# different filter for group and ledger - improved performance
if acc.is_group:
cond.append("""exists (
@@ -721,6 +717,7 @@ def get_children(doctype, parent, company, is_root=False):
parent_fieldname = 'parent_' + doctype.lower().replace(' ', '_')
fields = [
'name as value',
'root_type',
'is_group as expandable'
]
filters = [['docstatus', '<', 2]]
@@ -728,7 +725,7 @@ def get_children(doctype, parent, company, is_root=False):
filters.append(['ifnull(`{0}`,"")'.format(parent_fieldname), '=', '' if is_root else parent])
if is_root:
fields += ['root_type', 'report_type', 'account_currency'] if doctype == 'Account' else []
fields += ['report_type', 'account_currency'] if doctype == 'Account' else []
filters.append(['company', '=', company])
else:

View File

@@ -15,6 +15,9 @@ class calculate_taxes_and_totals(object):
self.calculate()
def calculate(self):
if not len(self.doc.get("items")):
return
self.discount_amount_applied = False
self._calculate()

View File

@@ -18,6 +18,10 @@ frappe.ui.form.on("Opportunity", {
}
}
});
if (frm.doc.opportunity_from && frm.doc.party_name){
frm.trigger('set_contact_link');
}
},
onload_post_render: function(frm) {

View File

@@ -7,7 +7,9 @@ import frappe
from frappe import _
from frappe.model.document import Document
from requests_oauthlib import OAuth2Session
import json, requests
import json
import requests
import traceback
from erpnext import encode_company_abbr
# QuickBooks requires a redirect URL, User will be redirect to this URL
@@ -32,7 +34,6 @@ def callback(*args, **kwargs):
class QuickBooksMigrator(Document):
def __init__(self, *args, **kwargs):
super(QuickBooksMigrator, self).__init__(*args, **kwargs)
from pprint import pprint
self.oauth = OAuth2Session(
client_id=self.client_id,
redirect_uri=self.redirect_url,
@@ -46,7 +47,9 @@ class QuickBooksMigrator(Document):
if self.company:
# We need a Cost Center corresponding to the selected erpnext Company
self.default_cost_center = frappe.db.get_value('Company', self.company, 'cost_center')
self.default_warehouse = frappe.get_all('Warehouse', filters={"company": self.company, "is_group": 0})[0]["name"]
company_warehouses = frappe.get_all('Warehouse', filters={"company": self.company, "is_group": 0})
if company_warehouses:
self.default_warehouse = company_warehouses[0].name
if self.authorization_endpoint:
self.authorization_url = self.oauth.authorization_url(self.authorization_endpoint)[0]
@@ -218,7 +221,7 @@ class QuickBooksMigrator(Document):
def _fetch_general_ledger(self):
try:
query_uri = "{}/company/{}/reports/GeneralLedger".format(self.api_endpoint ,self.quickbooks_company_id)
query_uri = "{}/company/{}/reports/GeneralLedger".format(self.api_endpoint, self.quickbooks_company_id)
response = self._get(query_uri,
params={
"columns": ",".join(["tx_date", "txn_type", "credit_amt", "debt_amt"]),
@@ -493,17 +496,17 @@ class QuickBooksMigrator(Document):
"account_currency": customer["CurrencyRef"]["value"],
"company": self.company,
})[0]["name"]
except Exception as e:
except Exception:
receivable_account = None
erpcustomer = frappe.get_doc({
"doctype": "Customer",
"quickbooks_id": customer["Id"],
"customer_name" : encode_company_abbr(customer["DisplayName"], self.company),
"customer_type" : "Individual",
"customer_group" : "Commercial",
"customer_name": encode_company_abbr(customer["DisplayName"], self.company),
"customer_type": "Individual",
"customer_group": "Commercial",
"default_currency": customer["CurrencyRef"]["value"],
"accounts": [{"company": self.company, "account": receivable_account}],
"territory" : "All Territories",
"territory": "All Territories",
"company": self.company,
}).insert()
if "BillAddr" in customer:
@@ -521,7 +524,7 @@ class QuickBooksMigrator(Document):
item_dict = {
"doctype": "Item",
"quickbooks_id": item["Id"],
"item_code" : encode_company_abbr(item["Name"], self.company),
"item_code": encode_company_abbr(item["Name"], self.company),
"stock_uom": "Unit",
"is_stock_item": 0,
"item_group": "All Item Groups",
@@ -549,14 +552,14 @@ class QuickBooksMigrator(Document):
erpsupplier = frappe.get_doc({
"doctype": "Supplier",
"quickbooks_id": vendor["Id"],
"supplier_name" : encode_company_abbr(vendor["DisplayName"], self.company),
"supplier_group" : "All Supplier Groups",
"supplier_name": encode_company_abbr(vendor["DisplayName"], self.company),
"supplier_group": "All Supplier Groups",
"company": self.company,
}).insert()
if "BillAddr" in vendor:
self._create_address(erpsupplier, "Supplier", vendor["BillAddr"], "Billing")
if "ShipAddr" in vendor:
self._create_address(erpsupplier, "Supplier",vendor["ShipAddr"], "Shipping")
self._create_address(erpsupplier, "Supplier", vendor["ShipAddr"], "Shipping")
except Exception as e:
self._log_error(e)
@@ -829,7 +832,7 @@ class QuickBooksMigrator(Document):
"currency": invoice["CurrencyRef"]["value"],
"conversion_rate": invoice.get("ExchangeRate", 1),
"posting_date": invoice["TxnDate"],
"due_date": invoice.get("DueDate", invoice["TxnDate"]),
"due_date": invoice.get("DueDate", invoice["TxnDate"]),
"credit_to": credit_to_account,
"supplier": frappe.get_all("Supplier",
filters={
@@ -1200,7 +1203,7 @@ class QuickBooksMigrator(Document):
def _create_address(self, entity, doctype, address, address_type):
try :
try:
if not frappe.db.exists({"doctype": "Address", "quickbooks_id": address["Id"]}):
frappe.get_doc({
"doctype": "Address",
@@ -1252,8 +1255,6 @@ class QuickBooksMigrator(Document):
def _log_error(self, execption, data=""):
import json, traceback
traceback.print_exc()
frappe.log_error(title="QuickBooks Migration Error",
message="\n".join([
"Data",

View File

@@ -29,9 +29,12 @@ class LoanApplication(Document):
if self.repayment_method == "Repay Fixed Amount per Period":
monthly_interest_rate = flt(self.rate_of_interest) / (12 *100)
if monthly_interest_rate:
self.repayment_periods = math.ceil((math.log(self.repayment_amount) -
math.log(self.repayment_amount - (self.loan_amount*monthly_interest_rate))) /
(math.log(1 + monthly_interest_rate)))
min_repayment_amount = self.loan_amount*monthly_interest_rate
if self.repayment_amount - min_repayment_amount < 0:
frappe.throw(_("Repayment Amount must be greater than " \
+ str(flt(min_repayment_amount, 2))))
self.repayment_periods = math.ceil(math.log(self.repayment_amount) -
math.log(self.repayment_amount - min_repayment_amount) /(math.log(1 + monthly_interest_rate)))
else:
self.repayment_periods = self.loan_amount / self.repayment_amount

View File

@@ -31,21 +31,22 @@ class TestLoanApplication(unittest.TestCase):
"rate_of_interest": 9.2,
"loan_amount": 250000,
"repayment_method": "Repay Over Number of Periods",
"repayment_periods": 24
"repayment_periods": 18
})
loan_application.insert()
def test_loan_totals(self):
loan_application = frappe.get_doc("Loan Application", {"applicant":self.applicant})
self.assertEquals(loan_application.repayment_amount, 11445)
self.assertEquals(loan_application.total_payable_interest, 24657)
self.assertEquals(loan_application.total_payable_amount, 274657)
loan_application.repayment_method = "Repay Fixed Amount per Period"
loan_application.repayment_amount = 15000
self.assertEqual(loan_application.total_payable_interest, 18599)
self.assertEqual(loan_application.total_payable_amount, 268599)
self.assertEqual(loan_application.repayment_amount, 14923)
loan_application.repayment_periods = 24
loan_application.save()
loan_application.reload()
self.assertEqual(loan_application.repayment_periods, 18)
self.assertEqual(loan_application.total_payable_interest, 18506)
self.assertEqual(loan_application.total_payable_amount, 268506)
self.assertEqual(loan_application.total_payable_interest, 24657)
self.assertEqual(loan_application.total_payable_amount, 274657)
self.assertEqual(loan_application.repayment_amount, 11445)

View File

@@ -506,6 +506,7 @@ erpnext.patches.v10_0.update_hub_connector_domain
erpnext.patches.v10_0.set_student_party_type
erpnext.patches.v10_0.update_project_in_sle
erpnext.patches.v10_0.fix_reserved_qty_for_sub_contract
erpnext.patches.v10_0.repost_requested_qty_for_non_stock_uom_items
erpnext.patches.v11_0.merge_land_unit_with_location
erpnext.patches.v11_0.add_index_on_nestedset_doctypes
erpnext.patches.v11_0.remove_modules_setup_page
@@ -603,4 +604,4 @@ erpnext.patches.v11_1.update_bank_transaction_status
erpnext.patches.v11_1.renamed_delayed_item_report
erpnext.patches.v11_1.set_missing_opportunity_from
erpnext.patches.v11_1.set_quotation_status
erpnext.patches.v11_1.update_default_supplier_in_item_defaults
erpnext.patches.v11_1.update_default_supplier_in_item_defaults

View File

@@ -0,0 +1,21 @@
# Copyright (c) 2019, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
def execute():
from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty
count=0
for item_code, warehouse in frappe.db.sql("""select distinct item_code, warehouse
from `tabMaterial Request Item` where docstatus = 1 and stock_uom<>uom"""):
try:
count += 1
update_bin_qty(item_code, warehouse, {
"indented_qty": get_indented_qty(item_code, warehouse),
})
if count % 200 == 0:
frappe.db.commit()
except:
frappe.db.rollback()

View File

@@ -1290,11 +1290,14 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
},
callback: function(r) {
if(!r.exc) {
me.frm.set_value("taxes", r.message);
if(me.frm.doc.shipping_rule && me.frm.doc.taxes) {
for (let tax of r.message) {
me.frm.add_child("taxes", tax);
}
if(me.frm.doc.shipping_rule) {
me.frm.script_manager.trigger("shipping_rule");
refresh_field("taxes");
} else {
me.frm.set_value("taxes", r.message);
me.calculate_taxes_and_totals();
}
}

View File

@@ -155,7 +155,7 @@ erpnext.pos.PointOfSale = class PointOfSale {
var me = this;
if (this.frm.doc.customer) {
frappe.call({
method: "erpnext.accounts.doctype.loyalty_program.loyalty_program.get_loyalty_program_details",
method: "erpnext.accounts.doctype.loyalty_program.loyalty_program.get_loyalty_program_details_with_points",
args: {
"customer": me.frm.doc.customer,
"expiry_date": me.frm.doc.posting_date,
@@ -1694,7 +1694,13 @@ class Payment {
fieldtype: 'Check',
label: 'Redeem Loyalty Points',
fieldname: 'redeem_loyalty_points',
onchange: () => {
onchange: async function () {
if (!cint(me.dialog.get_value('redeem_loyalty_points'))) {
await Promise.all([
me.frm.set_value('loyalty_points', 0),
me.dialog.set_value('loyalty_points', 0)
]);
}
me.update_cur_frm_value("redeem_loyalty_points", () => {
frappe.flags.redeem_loyalty_points = false;
me.update_loyalty_points();
@@ -1838,13 +1844,14 @@ class Payment {
});
}
update_loyalty_points() {
if (this.dialog.get_value("redeem_loyalty_points")) {
this.dialog.set_value("loyalty_points", this.frm.doc.loyalty_points);
this.dialog.set_value("loyalty_amount", this.frm.doc.loyalty_amount);
this.update_payment_amount();
this.show_paid_amount();
}
async update_loyalty_points() {
const { loyalty_points, loyalty_amount } = this.frm.doc;
await Promise.all([
this.dialog.set_value("loyalty_points", loyalty_points),
this.dialog.set_value("loyalty_amount", loyalty_amount)
]);
this.update_payment_amount();
this.show_paid_amount();
}
}

View File

@@ -60,7 +60,7 @@ def place_order():
quotation.flags.ignore_permissions = True
quotation.submit()
if quotation.lead:
if quotation.quotation_to == 'Lead' and quotation.party_name:
# company used to create customer accounts
frappe.defaults.set_user_default("company", quotation.company)

View File

@@ -177,7 +177,8 @@ class StockEntry(StockController):
item.set(f, item_details.get(f))
if not item.transfer_qty and item.qty:
item.transfer_qty = item.qty * item.conversion_factor
item.transfer_qty = ( flt(item.qty, item.precision("qty"))
* flt(item.conversion_factor, item.precision("conversion_factor")) )
if (self.purpose in ("Material Transfer", "Material Transfer for Manufacture")
and not item.serial_no

View File

@@ -110,7 +110,7 @@ def get_reserved_qty(item_code, warehouse):
return flt(reserved_qty[0][0]) if reserved_qty else 0
def get_indented_qty(item_code, warehouse):
indented_qty = frappe.db.sql("""select sum(mr_item.qty - mr_item.ordered_qty)
indented_qty = frappe.db.sql("""select sum((mr_item.qty - mr_item.ordered_qty) * mr_item.conversion_factor)
from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
where mr_item.item_code=%s and mr_item.warehouse=%s
and mr_item.qty > mr_item.ordered_qty and mr_item.parent=mr.name