Merge branch 'develop' into manufacturing-work-order-closed
This commit is contained in:
commit
b8ef8bcde9
@ -176,7 +176,7 @@ frappe.treeview_settings["Account"] = {
|
||||
&& node.expandable && !node.hide_add;
|
||||
},
|
||||
click: function() {
|
||||
var me = frappe.treeview_settings['Account'].treeview;
|
||||
var me = frappe.views.trees['Account'];
|
||||
me.new_node();
|
||||
},
|
||||
btnClass: "hidden-xs"
|
||||
|
@ -19,6 +19,9 @@ class AccountsSettings(Document):
|
||||
frappe.db.set_default("add_taxes_from_item_tax_template",
|
||||
self.get("add_taxes_from_item_tax_template", 0))
|
||||
|
||||
frappe.db.set_default("enable_common_party_accounting",
|
||||
self.get("enable_common_party_accounting", 0))
|
||||
|
||||
self.validate_stale_days()
|
||||
self.enable_payment_schedule_in_print()
|
||||
self.toggle_discount_accounting_fields()
|
||||
|
@ -25,3 +25,17 @@ class PartyLink(Document):
|
||||
if existing_party_link:
|
||||
frappe.throw(_('{} {} is already linked with another {}')
|
||||
.format(self.primary_role, self.primary_party, existing_party_link[0]))
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def create_party_link(primary_role, primary_party, secondary_party):
|
||||
party_link = frappe.new_doc('Party Link')
|
||||
party_link.primary_role = primary_role
|
||||
party_link.primary_party = primary_party
|
||||
party_link.secondary_role = 'Customer' if primary_role == 'Supplier' else 'Supplier'
|
||||
party_link.secondary_party = secondary_party
|
||||
|
||||
party_link.save(ignore_permissions=True)
|
||||
|
||||
return party_link
|
||||
|
||||
|
@ -88,9 +88,10 @@ class PeriodClosingVoucher(AccountsController):
|
||||
|
||||
for acc in pl_accounts:
|
||||
if flt(acc.bal_in_company_currency):
|
||||
cost_center = acc.cost_center if self.cost_center_wise_pnl else company_cost_center
|
||||
gl_entry = self.get_gl_dict({
|
||||
"account": self.closing_account_head,
|
||||
"cost_center": acc.cost_center or company_cost_center,
|
||||
"cost_center": cost_center,
|
||||
"finance_book": acc.finance_book,
|
||||
"account_currency": acc.account_currency,
|
||||
"debit_in_account_currency": abs(flt(acc.bal_in_account_currency)) if flt(acc.bal_in_account_currency) > 0 else 0,
|
||||
|
@ -66,8 +66,8 @@ class TestPeriodClosingVoucher(unittest.TestCase):
|
||||
company = create_company()
|
||||
surplus_account = create_account()
|
||||
|
||||
cost_center1 = create_cost_center("Test Cost Center 1")
|
||||
cost_center2 = create_cost_center("Test Cost Center 2")
|
||||
cost_center1 = create_cost_center("Main")
|
||||
cost_center2 = create_cost_center("Western Branch")
|
||||
|
||||
create_sales_invoice(
|
||||
company=company,
|
||||
@ -86,7 +86,10 @@ class TestPeriodClosingVoucher(unittest.TestCase):
|
||||
debit_to="Debtors - TPC"
|
||||
)
|
||||
|
||||
pcv = self.make_period_closing_voucher()
|
||||
pcv = self.make_period_closing_voucher(submit=False)
|
||||
pcv.cost_center_wise_pnl = 1
|
||||
pcv.save()
|
||||
pcv.submit()
|
||||
surplus_account = pcv.closing_account_head
|
||||
|
||||
expected_gle = (
|
||||
@ -149,7 +152,7 @@ class TestPeriodClosingVoucher(unittest.TestCase):
|
||||
|
||||
self.assertEqual(pcv_gle, expected_gle)
|
||||
|
||||
def make_period_closing_voucher(self):
|
||||
def make_period_closing_voucher(self, submit=True):
|
||||
surplus_account = create_account()
|
||||
cost_center = create_cost_center("Test Cost Center 1")
|
||||
pcv = frappe.get_doc({
|
||||
@ -163,7 +166,8 @@ class TestPeriodClosingVoucher(unittest.TestCase):
|
||||
"remarks": "test"
|
||||
})
|
||||
pcv.insert()
|
||||
pcv.submit()
|
||||
if submit:
|
||||
pcv.submit()
|
||||
|
||||
return pcv
|
||||
|
||||
|
@ -2300,6 +2300,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
from erpnext.accounts.doctype.opening_invoice_creation_tool.test_opening_invoice_creation_tool import (
|
||||
make_customer,
|
||||
)
|
||||
from erpnext.accounts.doctype.party_link.party_link import create_party_link
|
||||
from erpnext.buying.doctype.supplier.test_supplier import create_supplier
|
||||
|
||||
# create a customer
|
||||
@ -2308,13 +2309,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
supplier = create_supplier(supplier_name="_Test Common Supplier").name
|
||||
|
||||
# create a party link between customer & supplier
|
||||
# set primary role as supplier
|
||||
party_link = frappe.new_doc("Party Link")
|
||||
party_link.primary_role = "Supplier"
|
||||
party_link.primary_party = supplier
|
||||
party_link.secondary_role = "Customer"
|
||||
party_link.secondary_party = customer
|
||||
party_link.save()
|
||||
party_link = create_party_link("Supplier", supplier, customer)
|
||||
|
||||
# enable common party accounting
|
||||
frappe.db.set_value('Accounts Settings', None, 'enable_common_party_accounting', 1)
|
||||
|
@ -44,7 +44,7 @@ frappe.query_reports["Gross Profit"] = {
|
||||
"formatter": function(value, row, column, data, default_formatter) {
|
||||
value = default_formatter(value, row, column, data);
|
||||
|
||||
if (data && data.indent == 0.0) {
|
||||
if (data && (data.indent == 0.0 || row[1].content == "Total")) {
|
||||
value = $(`<span>${value}</span>`);
|
||||
var $value = $(value).css("font-weight", "bold");
|
||||
value = $value.wrap("<p></p>").parent().html();
|
||||
|
@ -9,7 +9,7 @@
|
||||
"filters": [],
|
||||
"idx": 3,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2021-08-19 18:57:07.468202",
|
||||
"modified": "2021-11-13 19:14:23.730198",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Gross Profit",
|
||||
|
@ -19,7 +19,7 @@ def execute(filters=None):
|
||||
data = []
|
||||
|
||||
group_wise_columns = frappe._dict({
|
||||
"invoice": ["parent", "customer", "customer_group", "posting_date","item_code", "item_name","item_group", "brand", "description", \
|
||||
"invoice": ["invoice_or_item", "customer", "customer_group", "posting_date","item_code", "item_name","item_group", "brand", "description",
|
||||
"warehouse", "qty", "base_rate", "buying_rate", "base_amount",
|
||||
"buying_amount", "gross_profit", "gross_profit_percent", "project"],
|
||||
"item_code": ["item_code", "item_name", "brand", "description", "qty", "base_rate",
|
||||
@ -77,13 +77,15 @@ def get_data_when_not_grouped_by_invoice(gross_profit_data, filters, group_wise_
|
||||
|
||||
row.append(filters.currency)
|
||||
if idx == len(gross_profit_data.grouped_data)-1:
|
||||
row[0] = frappe.bold("Total")
|
||||
row[0] = "Total"
|
||||
|
||||
data.append(row)
|
||||
|
||||
def get_columns(group_wise_columns, filters):
|
||||
columns = []
|
||||
column_map = frappe._dict({
|
||||
"parent": _("Sales Invoice") + ":Link/Sales Invoice:120",
|
||||
"invoice_or_item": _("Sales Invoice") + ":Link/Sales Invoice:120",
|
||||
"posting_date": _("Posting Date") + ":Date:100",
|
||||
"posting_time": _("Posting Time") + ":Data:100",
|
||||
"item_code": _("Item Code") + ":Link/Item:100",
|
||||
@ -122,7 +124,7 @@ def get_columns(group_wise_columns, filters):
|
||||
|
||||
def get_column_names():
|
||||
return frappe._dict({
|
||||
'parent': 'sales_invoice',
|
||||
'invoice_or_item': 'sales_invoice',
|
||||
'customer': 'customer',
|
||||
'customer_group': 'customer_group',
|
||||
'posting_date': 'posting_date',
|
||||
@ -245,19 +247,28 @@ class GrossProfitGenerator(object):
|
||||
self.add_to_totals(new_row)
|
||||
else:
|
||||
for i, row in enumerate(self.grouped[key]):
|
||||
if row.parent in self.returned_invoices \
|
||||
and row.item_code in self.returned_invoices[row.parent]:
|
||||
returned_item_rows = self.returned_invoices[row.parent][row.item_code]
|
||||
for returned_item_row in returned_item_rows:
|
||||
row.qty += flt(returned_item_row.qty)
|
||||
row.base_amount += flt(returned_item_row.base_amount, self.currency_precision)
|
||||
row.buying_amount = flt(flt(row.qty) * flt(row.buying_rate), self.currency_precision)
|
||||
if (flt(row.qty) or row.base_amount) and self.is_not_invoice_row(row):
|
||||
row = self.set_average_rate(row)
|
||||
self.grouped_data.append(row)
|
||||
self.add_to_totals(row)
|
||||
if row.indent == 1.0:
|
||||
if row.parent in self.returned_invoices \
|
||||
and row.item_code in self.returned_invoices[row.parent]:
|
||||
returned_item_rows = self.returned_invoices[row.parent][row.item_code]
|
||||
for returned_item_row in returned_item_rows:
|
||||
row.qty += flt(returned_item_row.qty)
|
||||
row.base_amount += flt(returned_item_row.base_amount, self.currency_precision)
|
||||
row.buying_amount = flt(flt(row.qty) * flt(row.buying_rate), self.currency_precision)
|
||||
if (flt(row.qty) or row.base_amount):
|
||||
row = self.set_average_rate(row)
|
||||
self.grouped_data.append(row)
|
||||
self.add_to_totals(row)
|
||||
|
||||
self.set_average_gross_profit(self.totals)
|
||||
self.grouped_data.append(self.totals)
|
||||
|
||||
if self.filters.get("group_by") == "Invoice":
|
||||
self.totals.indent = 0.0
|
||||
self.totals.parent_invoice = ""
|
||||
self.totals.parent = "Total"
|
||||
self.si_list.append(self.totals)
|
||||
else:
|
||||
self.grouped_data.append(self.totals)
|
||||
|
||||
def is_not_invoice_row(self, row):
|
||||
return (self.filters.get("group_by") == "Invoice" and row.indent != 0.0) or self.filters.get("group_by") != "Invoice"
|
||||
@ -446,7 +457,7 @@ class GrossProfitGenerator(object):
|
||||
if not row.indent:
|
||||
row.indent = 1.0
|
||||
row.parent_invoice = row.parent
|
||||
row.parent = row.item_code
|
||||
row.invoice_or_item = row.item_code
|
||||
|
||||
if frappe.db.exists('Product Bundle', row.item_code):
|
||||
self.add_bundle_items(row, index)
|
||||
@ -455,7 +466,8 @@ class GrossProfitGenerator(object):
|
||||
return frappe._dict({
|
||||
'parent_invoice': "",
|
||||
'indent': 0.0,
|
||||
'parent': row.parent,
|
||||
'invoice_or_item': row.parent,
|
||||
'parent': None,
|
||||
'posting_date': row.posting_date,
|
||||
'posting_time': row.posting_time,
|
||||
'project': row.project,
|
||||
@ -499,7 +511,8 @@ class GrossProfitGenerator(object):
|
||||
return frappe._dict({
|
||||
'parent_invoice': product_bundle.item_code,
|
||||
'indent': product_bundle.indent + 1,
|
||||
'parent': item.item_code,
|
||||
'parent': None,
|
||||
'invoice_or_item': item.item_code,
|
||||
'posting_date': product_bundle.posting_date,
|
||||
'posting_time': product_bundle.posting_time,
|
||||
'project': product_bundle.project,
|
||||
|
@ -14,6 +14,14 @@ frappe.ui.form.on('Asset Value Adjustment', {
|
||||
}
|
||||
}
|
||||
});
|
||||
frm.set_query('asset', function() {
|
||||
return {
|
||||
filters: {
|
||||
calculate_depreciation: 1,
|
||||
docstatus: 1
|
||||
}
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
onload: function(frm) {
|
||||
|
@ -10,7 +10,11 @@ from frappe.utils import cint, date_diff, flt, formatdate, getdate
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
|
||||
get_checks_for_pl_and_bs_accounts,
|
||||
)
|
||||
from erpnext.assets.doctype.asset.asset import get_depreciation_amount
|
||||
from erpnext.assets.doctype.asset.depreciation import get_depreciation_accounts
|
||||
from erpnext.regional.india.utils import (
|
||||
get_depreciation_amount as get_depreciation_amount_for_india,
|
||||
)
|
||||
|
||||
|
||||
class AssetValueAdjustment(Document):
|
||||
@ -90,6 +94,7 @@ class AssetValueAdjustment(Document):
|
||||
|
||||
def reschedule_depreciations(self, asset_value):
|
||||
asset = frappe.get_doc('Asset', self.asset)
|
||||
country = frappe.get_value('Company', self.company, 'country')
|
||||
|
||||
for d in asset.finance_books:
|
||||
d.value_after_depreciation = asset_value
|
||||
@ -111,8 +116,10 @@ class AssetValueAdjustment(Document):
|
||||
depreciation_amount = days * rate_per_day
|
||||
from_date = data.schedule_date
|
||||
else:
|
||||
depreciation_amount = asset.get_depreciation_amount(value_after_depreciation,
|
||||
no_of_depreciations, d)
|
||||
if country == "India":
|
||||
depreciation_amount = get_depreciation_amount_for_india(asset, value_after_depreciation, d)
|
||||
else:
|
||||
depreciation_amount = get_depreciation_amount(asset, value_after_depreciation, d)
|
||||
|
||||
if depreciation_amount:
|
||||
value_after_depreciation -= flt(depreciation_amount)
|
||||
|
@ -83,6 +83,12 @@ frappe.ui.form.on("Supplier", {
|
||||
frm.trigger("get_supplier_group_details");
|
||||
}, __('Actions'));
|
||||
|
||||
if (cint(frappe.defaults.get_default("enable_common_party_accounting"))) {
|
||||
frm.add_custom_button(__('Link with Customer'), function () {
|
||||
frm.trigger('show_party_link_dialog');
|
||||
}, __('Actions'));
|
||||
}
|
||||
|
||||
// indicators
|
||||
erpnext.utils.set_party_dashboard_indicators(frm);
|
||||
}
|
||||
@ -128,5 +134,42 @@ frappe.ui.form.on("Supplier", {
|
||||
else {
|
||||
frm.toggle_reqd("represents_company", false);
|
||||
}
|
||||
},
|
||||
show_party_link_dialog: function(frm) {
|
||||
const dialog = new frappe.ui.Dialog({
|
||||
title: __('Select a Customer'),
|
||||
fields: [{
|
||||
fieldtype: 'Link', label: __('Customer'),
|
||||
options: 'Customer', fieldname: 'customer', reqd: 1
|
||||
}],
|
||||
primary_action: function({ customer }) {
|
||||
frappe.call({
|
||||
method: 'erpnext.accounts.doctype.party_link.party_link.create_party_link',
|
||||
args: {
|
||||
primary_role: 'Supplier',
|
||||
primary_party: frm.doc.name,
|
||||
secondary_party: customer
|
||||
},
|
||||
freeze: true,
|
||||
callback: function() {
|
||||
dialog.hide();
|
||||
frappe.msgprint({
|
||||
message: __('Successfully linked to Customer'),
|
||||
alert: true
|
||||
});
|
||||
},
|
||||
error: function() {
|
||||
dialog.hide();
|
||||
frappe.msgprint({
|
||||
message: __('Linking to Customer Failed. Please try again.'),
|
||||
title: __('Linking Failed'),
|
||||
indicator: 'red'
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
primary_action_label: __('Create Link')
|
||||
});
|
||||
dialog.show();
|
||||
}
|
||||
});
|
||||
|
@ -676,5 +676,6 @@ def create_repost_item_valuation_entry(args):
|
||||
repost_entry.company = args.company
|
||||
repost_entry.allow_zero_rate = args.allow_zero_rate
|
||||
repost_entry.flags.ignore_links = True
|
||||
repost_entry.flags.ignore_permissions = True
|
||||
repost_entry.save()
|
||||
repost_entry.submit()
|
||||
|
@ -28,14 +28,22 @@ def create_qr_code(doc, method):
|
||||
|
||||
for field in meta.get_image_fields():
|
||||
if field.fieldname == 'qr_code':
|
||||
from urllib.parse import urlencode
|
||||
|
||||
# Creating public url to print format
|
||||
default_print_format = frappe.db.get_value('Property Setter', dict(property='default_print_format', doc_type=doc.doctype), "value")
|
||||
|
||||
# System Language
|
||||
language = frappe.get_system_settings('language')
|
||||
|
||||
params = urlencode({
|
||||
'format': default_print_format or 'Standard',
|
||||
'_lang': language,
|
||||
'key': doc.get_signature()
|
||||
})
|
||||
|
||||
# creating qr code for the url
|
||||
url = f"{ frappe.utils.get_url() }/{ doc.doctype }/{ doc.name }?format={ default_print_format or 'Standard' }&_lang={ language }&key={ doc.get_signature() }"
|
||||
url = f"{ frappe.utils.get_url() }/{ doc.doctype }/{ doc.name }?{ params }"
|
||||
qr_image = io.BytesIO()
|
||||
url = qr_create(url, error='L')
|
||||
url.png(qr_image, scale=2, quiet_zone=1)
|
||||
|
@ -134,6 +134,12 @@ frappe.ui.form.on("Customer", {
|
||||
frm.trigger("get_customer_group_details");
|
||||
}, __('Actions'));
|
||||
|
||||
if (cint(frappe.defaults.get_default("enable_common_party_accounting"))) {
|
||||
frm.add_custom_button(__('Link with Supplier'), function () {
|
||||
frm.trigger('show_party_link_dialog');
|
||||
}, __('Actions'));
|
||||
}
|
||||
|
||||
// indicator
|
||||
erpnext.utils.set_party_dashboard_indicators(frm);
|
||||
|
||||
@ -158,5 +164,42 @@ frappe.ui.form.on("Customer", {
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
show_party_link_dialog: function(frm) {
|
||||
const dialog = new frappe.ui.Dialog({
|
||||
title: __('Select a Supplier'),
|
||||
fields: [{
|
||||
fieldtype: 'Link', label: __('Supplier'),
|
||||
options: 'Supplier', fieldname: 'supplier', reqd: 1
|
||||
}],
|
||||
primary_action: function({ supplier }) {
|
||||
frappe.call({
|
||||
method: 'erpnext.accounts.doctype.party_link.party_link.create_party_link',
|
||||
args: {
|
||||
primary_role: 'Customer',
|
||||
primary_party: frm.doc.name,
|
||||
secondary_party: supplier
|
||||
},
|
||||
freeze: true,
|
||||
callback: function() {
|
||||
dialog.hide();
|
||||
frappe.msgprint({
|
||||
message: __('Successfully linked to Supplier'),
|
||||
alert: true
|
||||
});
|
||||
},
|
||||
error: function() {
|
||||
dialog.hide();
|
||||
frappe.msgprint({
|
||||
message: __('Linking to Supplier Failed. Please try again.'),
|
||||
title: __('Linking Failed'),
|
||||
indicator: 'red'
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
primary_action_label: __('Create Link')
|
||||
});
|
||||
dialog.show();
|
||||
}
|
||||
});
|
||||
|
@ -177,10 +177,11 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-07-22 18:59:43.057878",
|
||||
"modified": "2021-11-18 02:18:10.524560",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Repost Item Valuation",
|
||||
"naming_rule": "Expression (old style)",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
@ -197,20 +198,6 @@
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Stock User",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
@ -226,7 +213,6 @@
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
@ -234,7 +220,7 @@
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"role": "Accounts Manager",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
|
@ -133,7 +133,7 @@ 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)
|
||||
doc = frappe.get_doc('Repost Item Valuation', row.name)
|
||||
repost(doc)
|
||||
|
||||
riv_entries = get_repost_item_valuation_entries()
|
||||
|
@ -111,6 +111,7 @@ def validate_cancellation(args):
|
||||
frappe.throw(_("Cannot cancel the transaction. Reposting of item valuation on submission is not completed yet."))
|
||||
if repost_entry.status == 'Queued':
|
||||
doc = frappe.get_doc("Repost Item Valuation", repost_entry.name)
|
||||
doc.flags.ignore_permissions = True
|
||||
doc.cancel()
|
||||
doc.delete()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user