mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-12 17:51:20 +00:00
Merge branch 'v11-pre-release' into version-11
This commit is contained in:
@@ -5,7 +5,7 @@ import frappe
|
|||||||
from erpnext.hooks import regional_overrides
|
from erpnext.hooks import regional_overrides
|
||||||
from frappe.utils import getdate
|
from frappe.utils import getdate
|
||||||
|
|
||||||
__version__ = '11.1.66'
|
__version__ = '11.1.67'
|
||||||
|
|
||||||
def get_default_company(user=None):
|
def get_default_company(user=None):
|
||||||
'''Get default company for user'''
|
'''Get default company for user'''
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ frappe.ui.form.on('Share Transfer', {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
if (frm.doc.docstatus == 1) {
|
if (frm.doc.docstatus == 1 && frm.doc.equity_or_liability_account && frm.doc.asset_account ) {
|
||||||
frm.add_custom_button(__('Make Journal Entry'), function () {
|
frm.add_custom_button(__('Make Journal Entry'), function () {
|
||||||
erpnext.share_transfer.make_jv(frm);
|
erpnext.share_transfer.make_jv(frm);
|
||||||
});
|
});
|
||||||
@@ -92,6 +92,7 @@ erpnext.share_transfer.make_jv = function (frm) {
|
|||||||
debit_applicant_type = "Shareholder";
|
debit_applicant_type = "Shareholder";
|
||||||
debit_applicant = frm.doc.from_shareholder;
|
debit_applicant = frm.doc.from_shareholder;
|
||||||
}
|
}
|
||||||
|
|
||||||
frappe.call({
|
frappe.call({
|
||||||
args: {
|
args: {
|
||||||
"company": frm.doc.company,
|
"company": frm.doc.company,
|
||||||
|
|||||||
@@ -292,11 +292,14 @@ def make_jv_entry( company, account, amount, payment_account,\
|
|||||||
"party_type": debit_applicant_type,
|
"party_type": debit_applicant_type,
|
||||||
"party": debit_applicant,
|
"party": debit_applicant,
|
||||||
})
|
})
|
||||||
|
|
||||||
account_amt_list.append({
|
account_amt_list.append({
|
||||||
"account": payment_account,
|
"account": payment_account,
|
||||||
"credit_in_account_currency": amount,
|
"credit_in_account_currency": amount,
|
||||||
"party_type": credit_applicant_type,
|
"party_type": credit_applicant_type,
|
||||||
"party": credit_applicant,
|
"party": credit_applicant,
|
||||||
})
|
})
|
||||||
|
|
||||||
journal_entry.set("accounts", account_amt_list)
|
journal_entry.set("accounts", account_amt_list)
|
||||||
|
|
||||||
return journal_entry.as_dict()
|
return journal_entry.as_dict()
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-xs-{{ "3" if df.fieldtype=="Check" else "7" }} value">
|
<div class="col-xs-{{ "3" if df.fieldtype=="Check" else "7" }} value">
|
||||||
{% if doc.get(df.fieldname) != None -%}
|
{% if doc.get(df.fieldname) != None -%}
|
||||||
{{ frappe.utils.fmt_money((doc[df.fieldname])|int|abs, currency=doc.currency) }}
|
{{ frappe.utils.fmt_money((doc[df.fieldname])|abs, currency=doc.currency) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
<div class="col-xs-5 {%- if doc.align_labels_right %} text-right{%- endif -%}">
|
<div class="col-xs-5 {%- if doc.align_labels_right %} text-right{%- endif -%}">
|
||||||
<label>{{ charge.get_formatted("description") }}</label></div>
|
<label>{{ charge.get_formatted("description") }}</label></div>
|
||||||
<div class="col-xs-7 text-right">
|
<div class="col-xs-7 text-right">
|
||||||
{{ frappe.utils.fmt_money((charge.tax_amount)|int|abs, currency=doc.currency) }}
|
{{ frappe.utils.fmt_money((charge.tax_amount)|abs, currency=doc.currency) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
@@ -65,8 +65,10 @@
|
|||||||
{% for tdf in visible_columns %}
|
{% for tdf in visible_columns %}
|
||||||
{% if not d.flags.compact_item_print or tdf.fieldname in doc.get(df.fieldname)[0].flags.compact_item_fields %}
|
{% if not d.flags.compact_item_print or tdf.fieldname in doc.get(df.fieldname)[0].flags.compact_item_fields %}
|
||||||
<td class="{{ get_align_class(tdf) }}" {{ fieldmeta(df) }}>
|
<td class="{{ get_align_class(tdf) }}" {{ fieldmeta(df) }}>
|
||||||
{% if tdf.fieldtype == 'Currency' %}
|
{% if tdf.fieldname == 'qty' %}
|
||||||
<div class="value">{{ frappe.utils.fmt_money((d[tdf.fieldname])|int|abs, currency=doc.currency) }}</div></td>
|
<div class="value">{{ (d[tdf.fieldname])|abs }}</div></td>
|
||||||
|
{% elif tdf.fieldtype == 'Currency' %}
|
||||||
|
<div class="value">{{ frappe.utils.fmt_money((d[tdf.fieldname])|abs, currency=doc.currency) }}</div></td>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="value">{{ print_value(tdf, d, doc, visible_columns) }}</div></td>
|
<div class="value">{{ print_value(tdf, d, doc, visible_columns) }}</div></td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -117,7 +119,7 @@
|
|||||||
{{ render_currency(df, doc) }}
|
{{ render_currency(df, doc) }}
|
||||||
{% elif df.fieldtype =='Table' %}
|
{% elif df.fieldtype =='Table' %}
|
||||||
{{ render_table(df, doc)}}
|
{{ render_table(df, doc)}}
|
||||||
{% elif doc[df.fieldname] %}
|
{% elif doc[df.fieldname] and df.fieldname != 'total_qty' %}
|
||||||
{{ render_field(df, doc) }}
|
{{ render_field(df, doc) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -1114,8 +1114,22 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name):
|
|||||||
else:
|
else:
|
||||||
child_item.rate = flt(d.get("rate"))
|
child_item.rate = flt(d.get("rate"))
|
||||||
if flt(child_item.price_list_rate):
|
if flt(child_item.price_list_rate):
|
||||||
child_item.discount_percentage = flt((1 - flt(child_item.rate) / flt(child_item.price_list_rate)) * 100.0, \
|
if flt(child_item.rate) > flt(child_item.price_list_rate):
|
||||||
child_item.precision("discount_percentage"))
|
# if rate is greater than price_list_rate, set margin
|
||||||
|
# or set discount
|
||||||
|
child_item.discount_percentage = 0
|
||||||
|
child_item.margin_type = "Amount"
|
||||||
|
child_item.margin_rate_or_amount = flt(child_item.rate - child_item.price_list_rate,
|
||||||
|
child_item.precision("margin_rate_or_amount"))
|
||||||
|
child_item.rate_with_margin = child_item.rate
|
||||||
|
else:
|
||||||
|
child_item.discount_percentage = flt((1 - flt(child_item.rate) / flt(child_item.price_list_rate)) * 100.0,
|
||||||
|
child_item.precision("discount_percentage"))
|
||||||
|
child_item.discount_amount = flt(
|
||||||
|
child_item.price_list_rate) - flt(child_item.rate)
|
||||||
|
child_item.margin_type = ""
|
||||||
|
child_item.margin_rate_or_amount = 0
|
||||||
|
child_item.rate_with_margin = 0
|
||||||
|
|
||||||
child_item.flags.ignore_validate_update_after_submit = True
|
child_item.flags.ignore_validate_update_after_submit = True
|
||||||
child_item.save()
|
child_item.save()
|
||||||
|
|||||||
@@ -306,8 +306,9 @@ class SellingController(StockController):
|
|||||||
if flt(d.conversion_factor)==0.0:
|
if flt(d.conversion_factor)==0.0:
|
||||||
d.conversion_factor = get_conversion_factor(d.item_code, d.uom).get("conversion_factor") or 1.0
|
d.conversion_factor = get_conversion_factor(d.item_code, d.uom).get("conversion_factor") or 1.0
|
||||||
return_rate = 0
|
return_rate = 0
|
||||||
if cint(self.is_return) and self.return_against and self.docstatus==1:
|
if cint(self.is_return) and self.docstatus==1:
|
||||||
return_rate = self.get_incoming_rate_for_sales_return(d.item_code, self.return_against)
|
return_rate = self.get_incoming_rate_for_sales_return(d.item_code,
|
||||||
|
d.warehouse, self.return_against)
|
||||||
|
|
||||||
# On cancellation or if return entry submission, make stock ledger entry for
|
# On cancellation or if return entry submission, make stock ledger entry for
|
||||||
# target warehouse first, to update serial no values properly
|
# target warehouse first, to update serial no values properly
|
||||||
|
|||||||
@@ -299,7 +299,7 @@ class StockController(AccountsController):
|
|||||||
|
|
||||||
return serialized_items
|
return serialized_items
|
||||||
|
|
||||||
def get_incoming_rate_for_sales_return(self, item_code, against_document):
|
def get_incoming_rate_for_sales_return(self, item_code, warehouse, against_document):
|
||||||
incoming_rate = 0.0
|
incoming_rate = 0.0
|
||||||
if against_document and item_code:
|
if against_document and item_code:
|
||||||
incoming_rate = frappe.db.sql("""select abs(stock_value_difference / actual_qty)
|
incoming_rate = frappe.db.sql("""select abs(stock_value_difference / actual_qty)
|
||||||
@@ -308,6 +308,9 @@ class StockController(AccountsController):
|
|||||||
and item_code = %s limit 1""",
|
and item_code = %s limit 1""",
|
||||||
(self.doctype, against_document, item_code))
|
(self.doctype, against_document, item_code))
|
||||||
incoming_rate = incoming_rate[0][0] if incoming_rate else 0.0
|
incoming_rate = incoming_rate[0][0] if incoming_rate else 0.0
|
||||||
|
else:
|
||||||
|
incoming_rate = get_valuation_rate(item_code, warehouse,
|
||||||
|
self.doctype, against_document, company=self.company, currency=self.currency)
|
||||||
|
|
||||||
return incoming_rate
|
return incoming_rate
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class Loan(AccountsController):
|
|||||||
def validate(self):
|
def validate(self):
|
||||||
validate_repayment_method(self.repayment_method, self.loan_amount, self.monthly_repayment_amount, self.repayment_periods)
|
validate_repayment_method(self.repayment_method, self.loan_amount, self.monthly_repayment_amount, self.repayment_periods)
|
||||||
self.set_missing_fields()
|
self.set_missing_fields()
|
||||||
|
self.validate_loan_application()
|
||||||
self.make_repayment_schedule()
|
self.make_repayment_schedule()
|
||||||
self.set_repayment_period()
|
self.set_repayment_period()
|
||||||
self.calculate_totals()
|
self.calculate_totals()
|
||||||
@@ -33,6 +34,13 @@ class Loan(AccountsController):
|
|||||||
if self.status == "Repaid/Closed":
|
if self.status == "Repaid/Closed":
|
||||||
self.total_amount_paid = self.total_payment
|
self.total_amount_paid = self.total_payment
|
||||||
|
|
||||||
|
def validate_loan_application(self):
|
||||||
|
if self.loan_application:
|
||||||
|
loan = frappe.db.get_value("Loan", {"loan_application": self.loan_application}, "name")
|
||||||
|
|
||||||
|
if loan and loan != self.name:
|
||||||
|
frappe.throw(_("Loan {0} already created for Loan Application {1}").format(frappe.bold(loan),
|
||||||
|
frappe.bold(self.loan_application)))
|
||||||
|
|
||||||
def make_jv_entry(self):
|
def make_jv_entry(self):
|
||||||
self.check_permission('write')
|
self.check_permission('write')
|
||||||
@@ -116,6 +124,7 @@ def update_disbursement_status(doc):
|
|||||||
""", (doc.payment_account, doc.name), as_dict=1)[0]
|
""", (doc.payment_account, doc.name), as_dict=1)[0]
|
||||||
|
|
||||||
disbursement_date = None
|
disbursement_date = None
|
||||||
|
status = ''
|
||||||
if not disbursement or disbursement.disbursed_amount == 0:
|
if not disbursement or disbursement.disbursed_amount == 0:
|
||||||
status = "Sanctioned"
|
status = "Sanctioned"
|
||||||
elif disbursement.disbursed_amount == doc.loan_amount:
|
elif disbursement.disbursed_amount == doc.loan_amount:
|
||||||
|
|||||||
@@ -23,20 +23,25 @@ frappe.ui.form.on('Loan Application', {
|
|||||||
},
|
},
|
||||||
add_toolbar_buttons: function(frm) {
|
add_toolbar_buttons: function(frm) {
|
||||||
if (frm.doc.status == "Approved") {
|
if (frm.doc.status == "Approved") {
|
||||||
frm.add_custom_button(__('Create Loan'), function() {
|
// show create loan button if loan not created against loan aplication
|
||||||
frappe.call({
|
frappe.db.get_value("Loan", {"loan_application": frm.doc.name}, "name", (r) => {
|
||||||
method: "erpnext.hr.doctype.loan_application.loan_application.make_loan",
|
if (!r) {
|
||||||
args: {
|
frm.add_custom_button(__('Create Loan'), function() {
|
||||||
"source_name": frm.doc.name
|
frappe.call({
|
||||||
},
|
method: "erpnext.hr.doctype.loan_application.loan_application.make_loan",
|
||||||
callback: function(r) {
|
args: {
|
||||||
if(!r.exc) {
|
"source_name": frm.doc.name
|
||||||
var doc = frappe.model.sync(r.message);
|
},
|
||||||
frappe.set_route("Form", r.message.doctype, r.message.name);
|
callback: function(r) {
|
||||||
}
|
if(!r.exc) {
|
||||||
}
|
var doc = frappe.model.sync(r.message);
|
||||||
});
|
frappe.set_route("Form", r.message.doctype, r.message.name);
|
||||||
}).addClass("btn-primary");
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).addClass("btn-primary");
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ frappe.ui.form.on("BOM", {
|
|||||||
args: {
|
args: {
|
||||||
update_parent: true,
|
update_parent: true,
|
||||||
from_child_bom:false,
|
from_child_bom:false,
|
||||||
save: false
|
save: frm.doc.docstatus === 1 ? true : false
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
refresh_field("items");
|
refresh_field("items");
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ class BOM(WebsiteGenerator):
|
|||||||
# name can be BOM/ITEM/001, BOM/ITEM/001-1, BOM-ITEM-001, BOM-ITEM-001-1
|
# name can be BOM/ITEM/001, BOM/ITEM/001-1, BOM-ITEM-001, BOM-ITEM-001-1
|
||||||
|
|
||||||
# split by item
|
# split by item
|
||||||
names = [name.split(self.item)[-1][1:] for name in names]
|
names = [name.split(self.item, 1) for name in names]
|
||||||
|
names = [d[-1][1:] for d in filter(lambda x: len(x) > 1 and x[-1], names)]
|
||||||
|
|
||||||
# split by (-) if cancelled
|
# split by (-) if cancelled
|
||||||
names = [cint(name.split('-')[-1]) for name in names]
|
names = [cint(name.split('-')[-1]) for name in names]
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{%- macro render_discount_or_margin(item) -%}
|
{%- macro render_discount_or_margin(item) -%}
|
||||||
{%- if item.discount_percentage > 0.0 or item.margin_type %}
|
{%- if (item.discount_percentage and item.discount_percentage > 0.0) or item.margin_type %}
|
||||||
<ScontoMaggiorazione>
|
<ScontoMaggiorazione>
|
||||||
{%- if item.discount_percentage > 0.0 %}
|
{%- if item.discount_percentage > 0.0 %}
|
||||||
<Tipo>SC</Tipo>
|
<Tipo>SC</Tipo>
|
||||||
|
|||||||
@@ -80,10 +80,14 @@ frappe.query_reports["Sales Analytics"] = {
|
|||||||
|
|
||||||
var tree_type = frappe.query_report.filters[0].value;
|
var tree_type = frappe.query_report.filters[0].value;
|
||||||
|
|
||||||
if(tree_type == "Customer" || tree_type == "Item") {
|
if(tree_type == "Customer") {
|
||||||
row_values = data.slice(4,length-1).map(function (column) {
|
row_values = data.slice(4,length-1).map(function (column) {
|
||||||
return column.content;
|
return column.content;
|
||||||
})
|
})
|
||||||
|
} else if (tree_type == "Item") {
|
||||||
|
row_values = data.slice(5,length-1).map(function (column) {
|
||||||
|
return column.content;
|
||||||
|
})
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
row_values = data.slice(3,length-1).map(function (column) {
|
row_values = data.slice(3,length-1).map(function (column) {
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ class Analytics(object):
|
|||||||
if self.filters["value_quantity"] == 'Value':
|
if self.filters["value_quantity"] == 'Value':
|
||||||
value_field = 'base_amount'
|
value_field = 'base_amount'
|
||||||
else:
|
else:
|
||||||
value_field = 'qty'
|
value_field = 'stock_qty'
|
||||||
|
|
||||||
self.entries = frappe.db.sql("""
|
self.entries = frappe.db.sql("""
|
||||||
select i.item_code as entity, i.item_name as entity_name, i.stock_uom, i.{value_field} as value_field, s.{date_field}
|
select i.item_code as entity, i.item_name as entity_name, i.stock_uom, i.{value_field} as value_field, s.{date_field}
|
||||||
@@ -301,8 +301,10 @@ class Analytics(object):
|
|||||||
def get_chart_data(self):
|
def get_chart_data(self):
|
||||||
length = len(self.columns)
|
length = len(self.columns)
|
||||||
|
|
||||||
if self.filters.tree_type in ["Customer", "Supplier", "Item"]:
|
if self.filters.tree_type in ["Customer", "Supplier"]:
|
||||||
labels = [d.get("label") for d in self.columns[2:length-1]]
|
labels = [d.get("label") for d in self.columns[2:length - 1]]
|
||||||
|
elif self.filters.tree_type == "Item":
|
||||||
|
labels = [d.get("label") for d in self.columns[3:length - 1]]
|
||||||
else:
|
else:
|
||||||
labels = [d.get("label") for d in self.columns[1:length-1]]
|
labels = [d.get("label") for d in self.columns[1:length-1]]
|
||||||
self.chart = {
|
self.chart = {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ def execute(filters=None):
|
|||||||
|
|
||||||
data = []
|
data = []
|
||||||
for item in items:
|
for item in items:
|
||||||
total_outgoing = consumed_item_map.get(item.name, 0) + delivered_item_map.get(item.name,0)
|
total_outgoing = flt(consumed_item_map.get(item.name, 0)) + flt(delivered_item_map.get(item.name,0))
|
||||||
avg_daily_outgoing = flt(total_outgoing / diff, float_preceision)
|
avg_daily_outgoing = flt(total_outgoing / diff, float_preceision)
|
||||||
reorder_level = (avg_daily_outgoing * flt(item.lead_time_days)) + flt(item.safety_stock)
|
reorder_level = (avg_daily_outgoing * flt(item.lead_time_days)) + flt(item.safety_stock)
|
||||||
|
|
||||||
@@ -55,18 +55,20 @@ def get_item_info(filters):
|
|||||||
|
|
||||||
|
|
||||||
def get_consumed_items(condition):
|
def get_consumed_items(condition):
|
||||||
cn_items = frappe.db.sql("""select se_item.item_code,
|
consumed_items = frappe.db.sql("""
|
||||||
sum(se_item.transfer_qty) as 'consume_qty'
|
select item_code, abs(sum(actual_qty)) as consumed_qty
|
||||||
from `tabStock Entry` se, `tabStock Entry Detail` se_item
|
from `tabStock Ledger Entry`
|
||||||
where se.name = se_item.parent and se.docstatus = 1
|
where actual_qty < 0
|
||||||
and (ifnull(se_item.t_warehouse, '') = '' or se.purpose = 'Subcontract') %s
|
and voucher_type not in ('Delivery Note', 'Sales Invoice')
|
||||||
group by se_item.item_code""" % (condition), as_dict=1)
|
%s
|
||||||
|
group by item_code
|
||||||
|
""" % condition, as_dict=1)
|
||||||
|
|
||||||
cn_items_map = {}
|
consumed_items_map = {}
|
||||||
for item in cn_items:
|
for item in consumed_items:
|
||||||
cn_items_map.setdefault(item.item_code, item.consume_qty)
|
consumed_items_map.setdefault(item.item_code, item.consumed_qty)
|
||||||
|
|
||||||
return cn_items_map
|
return consumed_items_map
|
||||||
|
|
||||||
def get_delivered_items(condition):
|
def get_delivered_items(condition):
|
||||||
dn_items = frappe.db.sql("""select dn_item.item_code, sum(dn_item.stock_qty) as dn_qty
|
dn_items = frappe.db.sql("""select dn_item.item_code, sum(dn_item.stock_qty) as dn_qty
|
||||||
|
|||||||
Reference in New Issue
Block a user