Merge branch 'develop' of https://github.com/frappe/erpnext into so-on-hold
This commit is contained in:
commit
16c4fd6733
@ -5,7 +5,7 @@ import frappe
|
||||
from erpnext.hooks import regional_overrides
|
||||
from frappe.utils import getdate
|
||||
|
||||
__version__ = '11.1.16'
|
||||
__version__ = '11.1.17'
|
||||
|
||||
def get_default_company(user=None):
|
||||
'''Get default company for user'''
|
||||
|
@ -0,0 +1,45 @@
|
||||
frappe.dashboard_chart_sources["Account Balance Timeline"] = {
|
||||
method_path: "erpnext.accounts.dashboard_chart_source.account_balance_timeline.account_balance_timeline.get",
|
||||
filters: [
|
||||
{
|
||||
fieldname: "company",
|
||||
label: __("Company"),
|
||||
fieldtype: "Link",
|
||||
options: "Company",
|
||||
default: frappe.defaults.get_user_default("Company"),
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "account",
|
||||
label: __("Account"),
|
||||
fieldtype: "Link",
|
||||
options: "Account",
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "timespan",
|
||||
label: __("Period"),
|
||||
fieldtype: "Select",
|
||||
options: [
|
||||
{value: "Last Year", label: __("Last Year")},
|
||||
{value: "Last Quarter", label: __("Last Quarter")},
|
||||
{value: "Last Month", label: __("Last Month")},
|
||||
{value: "Last Week", label: __("Last Week")}
|
||||
],
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "timegrain",
|
||||
label: __("Periodicity"),
|
||||
fieldtype: "Select",
|
||||
options: [
|
||||
{value: "Quarterly", label: __("Quarterly")},
|
||||
{value: "Monthly", label: __("Monthly")},
|
||||
{value: "Weekly", label: __("Weekly")},
|
||||
{value: "Daily", label: __("Daily")}
|
||||
],
|
||||
reqd: 1
|
||||
},
|
||||
],
|
||||
is_time_series: true
|
||||
};
|
@ -0,0 +1,13 @@
|
||||
{
|
||||
"config": "{\n \"method_path\": \"erpnext.accounts.dashboard_chart_source.account_balance_timeline.account_balance_timeline.get\",\n\t\"filters\": [\n\t\t{\n\t\t\t\"fieldname\": \"company\",\n\t\t\t\"label\": \"Company\",\n\t\t\t\"fieldtype\": \"Link\",\n\t\t\t\"options\": \"Company\",\n\t\t\t\"reqd\": 1\n\t\t},\n\t\t{\n\t\t\t\"fieldname\": \"account\",\n\t\t\t\"label\": \"Account\",\n\t\t\t\"fieldtype\": \"Link\",\n\t\t\t\"options\": \"Account\",\n\t\t\t\"reqd\": 1\n\t\t},\n\t\t{\n\t\t\t\"fieldname\": \"timespan\",\n\t\t\t\"label\": \"Period\",\n\t\t\t\"fieldtype\": \"Select\",\n\t\t\t\"options\": [\n\t\t\t\t{\"value\": \"Last Year\", \"label\": \"Last Year\"},\n\t\t\t\t{\"value\": \"Last Quarter\", \"label\": \"Last Quarter\"},\n\t\t\t\t{\"value\": \"Last Month\", \"label\": \"Last Month\"},\n\t\t\t\t{\"value\": \"Last Week\", \"label\": \"Last Week\"}\n\t\t\t],\n\t\t\t\"reqd\": 1\n\t\t},\n\t\t{\n\t\t\t\"fieldname\": \"timegrain\",\n\t\t\t\"label\": \"Periodicity\",\n\t\t\t\"fieldtype\": \"Select\",\n\t\t\t\"options\": [\n\t\t\t\t{\"value\": \"Quarterly\", \"label\": \"Quarterly\"},\n\t\t\t\t{\"value\": \"Monthly\", \"label\": \"Monthly\"},\n\t\t\t\t{\"value\": \"Weekly\", \"label\": \"Weekly\"},\n\t\t\t\t{\"value\": \"Daily\", \"label\": \"Daily\"}\n\t\t\t],\n\t\t\t\"reqd\": 1\n\t\t}\n\t],\n\t\"is_time_series\": true\n}\n",
|
||||
"creation": "2019-02-06 07:57:10.377718",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart Source",
|
||||
"idx": 0,
|
||||
"modified": "2019-03-15 16:14:26.505986",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Account Balance Timeline",
|
||||
"owner": "Administrator",
|
||||
"source_name": "Account Balance Timeline"
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from itertools import groupby
|
||||
from operator import itemgetter
|
||||
import frappe
|
||||
from frappe.core.page.dashboard.dashboard import cache_source
|
||||
from frappe.utils import add_to_date, date_diff, getdate, nowdate
|
||||
from erpnext.accounts.report.general_ledger.general_ledger import execute
|
||||
|
||||
from frappe.utils.nestedset import get_descendants_of
|
||||
|
||||
@frappe.whitelist()
|
||||
@cache_source
|
||||
def get(filters=None):
|
||||
timespan = filters.get("timespan")
|
||||
timegrain = filters.get("timegrain")
|
||||
account = filters.get("account")
|
||||
company = filters.get("company")
|
||||
|
||||
from_date = get_from_date_from_timespan(timespan)
|
||||
to_date = nowdate()
|
||||
|
||||
# fetch dates to plot
|
||||
dates = get_dates_from_timegrain(from_date, to_date, timegrain)
|
||||
|
||||
# get all the entries for this account and its descendants
|
||||
gl_entries = get_gl_entries(account, to_date)
|
||||
|
||||
# compile balance values
|
||||
result = build_result(account, dates, gl_entries)
|
||||
|
||||
return {
|
||||
"labels": [r[0].strftime('%Y-%m-%d') for r in result],
|
||||
"datasets": [{
|
||||
"name": account,
|
||||
"values": [r[1] for r in result]
|
||||
}]
|
||||
}
|
||||
|
||||
def build_result(account, dates, gl_entries):
|
||||
result = [[getdate(date), 0.0] for date in dates]
|
||||
root_type = frappe.db.get_value('Account', account, 'root_type')
|
||||
|
||||
# start with the first date
|
||||
date_index = 0
|
||||
|
||||
# get balances in debit
|
||||
for entry in gl_entries:
|
||||
|
||||
# entry date is after the current pointer, so move the pointer forward
|
||||
while getdate(entry.posting_date) > result[date_index][0]:
|
||||
date_index += 1
|
||||
|
||||
result[date_index][1] += entry.debit - entry.credit
|
||||
|
||||
# if account type is credit, switch balances
|
||||
if root_type not in ('Asset', 'Expense'):
|
||||
for r in result:
|
||||
r[1] = -1 * r[1]
|
||||
|
||||
# for balance sheet accounts, the totals are cumulative
|
||||
if root_type in ('Asset', 'Liability', 'Equity'):
|
||||
for i, r in enumerate(result):
|
||||
if i < 0:
|
||||
r[1] = r[1] + result[i-1][1]
|
||||
|
||||
return result
|
||||
|
||||
def get_gl_entries(account, to_date):
|
||||
child_accounts = get_descendants_of('Account', account, ignore_permissions=True)
|
||||
child_accounts.append(account)
|
||||
|
||||
return frappe.db.get_all('GL Entry',
|
||||
fields = ['posting_date', 'debit', 'credit'],
|
||||
filters = [
|
||||
dict(posting_date = ('<', to_date)),
|
||||
dict(account = ('in', child_accounts))
|
||||
],
|
||||
order_by = 'posting_date asc')
|
||||
|
||||
def get_from_date_from_timespan(timespan):
|
||||
days = months = years = 0
|
||||
if "Last Week" == timespan:
|
||||
days = -7
|
||||
if "Last Month" == timespan:
|
||||
months = -1
|
||||
elif "Last Quarter" == timespan:
|
||||
months = -3
|
||||
elif "Last Year" == timespan:
|
||||
years = -1
|
||||
return add_to_date(None, years=years, months=months, days=days,
|
||||
as_string=True, as_datetime=True)
|
||||
|
||||
def get_dates_from_timegrain(from_date, to_date, timegrain):
|
||||
days = months = years = 0
|
||||
if "Daily" == timegrain:
|
||||
days = 1
|
||||
elif "Weekly" == timegrain:
|
||||
days = 7
|
||||
elif "Monthly" == timegrain:
|
||||
months = 1
|
||||
elif "Quarterly" == timegrain:
|
||||
months = 3
|
||||
|
||||
dates = [from_date]
|
||||
while dates[-1] <= to_date:
|
||||
dates.append(add_to_date(dates[-1], years=years, months=months, days=days))
|
||||
return dates
|
@ -2,9 +2,9 @@ from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import date_diff, add_months, today, getdate, add_days, flt
|
||||
from frappe.utils import date_diff, add_months, today, getdate, add_days, flt, get_last_day
|
||||
from erpnext.accounts.utils import get_account_currency
|
||||
from erpnext.accounts.general_ledger import make_gl_entries
|
||||
from frappe.email import sendmail_to_system_managers
|
||||
|
||||
def validate_service_stop_date(doc):
|
||||
''' Validates service_stop_date for Purchase Invoice and Sales Invoice '''
|
||||
@ -33,47 +33,49 @@ def validate_service_stop_date(doc):
|
||||
frappe.throw(_("Cannot change Service Stop Date for item in row {0}".format(item.idx)))
|
||||
|
||||
def convert_deferred_expense_to_expense(start_date=None, end_date=None):
|
||||
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
|
||||
if not start_date:
|
||||
start_date = add_months(today(), -1)
|
||||
if not end_date:
|
||||
end_date = add_days(today(), -1)
|
||||
|
||||
# check for the purchase invoice for which GL entries has to be done
|
||||
invoices = frappe.db.sql_list('''
|
||||
select distinct parent from `tabPurchase Invoice Item` where service_start_date<=%s and service_end_date>=%s
|
||||
select distinct parent from `tabPurchase Invoice Item`
|
||||
where service_start_date<=%s and service_end_date>=%s
|
||||
and enable_deferred_expense = 1 and docstatus = 1 and ifnull(amount, 0) > 0
|
||||
''', (end_date or today(), start_date or add_months(today(), -1)))
|
||||
''', (end_date, start_date))
|
||||
|
||||
# For each invoice, book deferred expense
|
||||
for invoice in invoices:
|
||||
doc = frappe.get_doc("Purchase Invoice", invoice)
|
||||
book_deferred_income_or_expense(doc, start_date, end_date)
|
||||
book_deferred_income_or_expense(doc, end_date)
|
||||
|
||||
def convert_deferred_revenue_to_income(start_date=None, end_date=None):
|
||||
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
|
||||
if not start_date:
|
||||
start_date = add_months(today(), -1)
|
||||
if not end_date:
|
||||
end_date = add_days(today(), -1)
|
||||
|
||||
# check for the sales invoice for which GL entries has to be done
|
||||
invoices = frappe.db.sql_list('''
|
||||
select distinct parent from `tabSales Invoice Item` where service_start_date<=%s and service_end_date>=%s
|
||||
select distinct parent from `tabSales Invoice Item`
|
||||
where service_start_date<=%s and service_end_date>=%s
|
||||
and enable_deferred_revenue = 1 and docstatus = 1 and ifnull(amount, 0) > 0
|
||||
''', (end_date or today(), start_date or add_months(today(), -1)))
|
||||
''', (end_date, start_date))
|
||||
|
||||
# For each invoice, book deferred revenue
|
||||
for invoice in invoices:
|
||||
doc = frappe.get_doc("Sales Invoice", invoice)
|
||||
book_deferred_income_or_expense(doc, start_date, end_date)
|
||||
book_deferred_income_or_expense(doc, end_date)
|
||||
|
||||
def get_booking_dates(doc, item, posting_date=None):
|
||||
if not posting_date:
|
||||
posting_date = add_days(today(), -1)
|
||||
|
||||
last_gl_entry = False
|
||||
|
||||
def get_booking_dates(doc, item, start_date=None, end_date=None):
|
||||
deferred_account = "deferred_revenue_account" if doc.doctype=="Sales Invoice" else "deferred_expense_account"
|
||||
last_gl_entry, skip = False, False
|
||||
|
||||
booking_end_date = getdate(add_days(today(), -1) if not end_date else end_date)
|
||||
if booking_end_date < item.service_start_date or \
|
||||
(item.service_stop_date and booking_end_date.month > item.service_stop_date.month):
|
||||
return None, None, None, True
|
||||
elif booking_end_date >= item.service_end_date:
|
||||
last_gl_entry = True
|
||||
booking_end_date = item.service_end_date
|
||||
elif item.service_stop_date and item.service_stop_date <= booking_end_date:
|
||||
last_gl_entry = True
|
||||
booking_end_date = item.service_stop_date
|
||||
|
||||
booking_start_date = getdate(add_months(today(), -1) if not start_date else start_date)
|
||||
booking_start_date = booking_start_date \
|
||||
if booking_start_date > item.service_start_date else item.service_start_date
|
||||
|
||||
prev_gl_entry = frappe.db.sql('''
|
||||
select name, posting_date from `tabGL Entry` where company=%s and account=%s and
|
||||
@ -81,17 +83,28 @@ def get_booking_dates(doc, item, start_date=None, end_date=None):
|
||||
order by posting_date desc limit 1
|
||||
''', (doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True)
|
||||
|
||||
if not prev_gl_entry and item.service_start_date < booking_start_date:
|
||||
booking_start_date = item.service_start_date
|
||||
elif prev_gl_entry:
|
||||
booking_start_date = getdate(add_days(prev_gl_entry[0].posting_date, 1))
|
||||
skip = True if booking_start_date > booking_end_date else False
|
||||
if prev_gl_entry:
|
||||
start_date = getdate(add_days(prev_gl_entry[0].posting_date, 1))
|
||||
else:
|
||||
start_date = item.service_start_date
|
||||
|
||||
return last_gl_entry, booking_start_date, booking_end_date, skip
|
||||
end_date = get_last_day(start_date)
|
||||
if end_date >= item.service_end_date:
|
||||
end_date = item.service_end_date
|
||||
last_gl_entry = True
|
||||
elif item.service_stop_date and end_date >= item.service_stop_date:
|
||||
end_date = item.service_stop_date
|
||||
last_gl_entry = True
|
||||
|
||||
def calculate_amount_and_base_amount(doc, item, last_gl_entry, total_days, total_booking_days):
|
||||
account_currency = get_account_currency(item.expense_account)
|
||||
if end_date > getdate(posting_date):
|
||||
end_date = posting_date
|
||||
|
||||
if getdate(start_date) <= getdate(end_date):
|
||||
return start_date, end_date, last_gl_entry
|
||||
else:
|
||||
return None, None, None
|
||||
|
||||
def calculate_amount(doc, item, last_gl_entry, total_days, total_booking_days, account_currency):
|
||||
if doc.doctype == "Sales Invoice":
|
||||
total_credit_debit, total_credit_debit_currency = "debit", "debit_in_account_currency"
|
||||
deferred_account = "deferred_revenue_account"
|
||||
@ -123,28 +136,15 @@ def calculate_amount_and_base_amount(doc, item, last_gl_entry, total_days, total
|
||||
|
||||
return amount, base_amount
|
||||
|
||||
def book_deferred_income_or_expense(doc, start_date=None, end_date=None):
|
||||
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
|
||||
# start_date: 1st of the last month or the start date
|
||||
# end_date: end_date or today-1
|
||||
def book_deferred_income_or_expense(doc, posting_date=None):
|
||||
enable_check = "enable_deferred_revenue" \
|
||||
if doc.doctype=="Sales Invoice" else "enable_deferred_expense"
|
||||
|
||||
gl_entries = []
|
||||
for item in doc.get('items'):
|
||||
if not item.get(enable_check): continue
|
||||
|
||||
skip = False
|
||||
last_gl_entry, booking_start_date, booking_end_date, skip = \
|
||||
get_booking_dates(doc, item, start_date, end_date)
|
||||
|
||||
if skip: continue
|
||||
total_days = date_diff(item.service_end_date, item.service_start_date) + 1
|
||||
total_booking_days = date_diff(booking_end_date, booking_start_date) + 1
|
||||
def _book_deferred_revenue_or_expense(item):
|
||||
start_date, end_date, last_gl_entry = get_booking_dates(doc, item, posting_date=posting_date)
|
||||
if not (start_date and end_date): return
|
||||
|
||||
account_currency = get_account_currency(item.expense_account)
|
||||
amount, base_amount = calculate_amount_and_base_amount(doc, item, last_gl_entry, total_days, total_booking_days)
|
||||
|
||||
if doc.doctype == "Sales Invoice":
|
||||
against, project = doc.customer, doc.project
|
||||
credit_account, debit_account = item.income_account, item.deferred_revenue_account
|
||||
@ -152,16 +152,38 @@ def book_deferred_income_or_expense(doc, start_date=None, end_date=None):
|
||||
against, project = doc.supplier, item.project
|
||||
credit_account, debit_account = item.deferred_expense_account, item.expense_account
|
||||
|
||||
total_days = date_diff(item.service_end_date, item.service_start_date) + 1
|
||||
total_booking_days = date_diff(end_date, start_date) + 1
|
||||
|
||||
amount, base_amount = calculate_amount(doc, item, last_gl_entry,
|
||||
total_days, total_booking_days, account_currency)
|
||||
|
||||
make_gl_entries(doc, credit_account, debit_account, against,
|
||||
amount, base_amount, end_date, project, account_currency, item.cost_center, item.name)
|
||||
|
||||
if getdate(end_date) < getdate(posting_date) and not last_gl_entry:
|
||||
_book_deferred_revenue_or_expense(item)
|
||||
|
||||
|
||||
for item in doc.get('items'):
|
||||
if item.get(enable_check):
|
||||
_book_deferred_revenue_or_expense(item)
|
||||
|
||||
def make_gl_entries(doc, credit_account, debit_account, against,
|
||||
amount, base_amount, posting_date, project, account_currency, cost_center, voucher_detail_no):
|
||||
# GL Entry for crediting the amount in the deferred expense
|
||||
from erpnext.accounts.general_ledger import make_gl_entries
|
||||
|
||||
gl_entries = []
|
||||
gl_entries.append(
|
||||
doc.get_gl_dict({
|
||||
"account": credit_account,
|
||||
"against": against,
|
||||
"credit": base_amount,
|
||||
"credit_in_account_currency": amount,
|
||||
"cost_center": item.cost_center,
|
||||
"voucher_detail_no": item.name,
|
||||
'posting_date': booking_end_date,
|
||||
"cost_center": cost_center,
|
||||
"voucher_detail_no": voucher_detail_no,
|
||||
'posting_date': posting_date,
|
||||
'project': project
|
||||
}, account_currency)
|
||||
)
|
||||
@ -172,16 +194,20 @@ def book_deferred_income_or_expense(doc, start_date=None, end_date=None):
|
||||
"against": against,
|
||||
"debit": base_amount,
|
||||
"debit_in_account_currency": amount,
|
||||
"cost_center": item.cost_center,
|
||||
"voucher_detail_no": item.name,
|
||||
'posting_date': booking_end_date,
|
||||
"cost_center": cost_center,
|
||||
"voucher_detail_no": voucher_detail_no,
|
||||
'posting_date': posting_date,
|
||||
'project': project
|
||||
}, account_currency)
|
||||
)
|
||||
|
||||
if gl_entries:
|
||||
try:
|
||||
make_gl_entries(gl_entries, cancel=(doc.docstatus == 2), merge_entries=True)
|
||||
frappe.db.commit()
|
||||
except:
|
||||
frappe.db.rollback()
|
||||
frappe.log_error(message = frappe.get_traceback(), title = _("Error while processing deferred accounting for {0}").format(doc.name))
|
||||
title = _("Error while processing deferred accounting for {0}").format(doc.name)
|
||||
traceback = frappe.get_traceback()
|
||||
frappe.log_error(message=traceback , title=title)
|
||||
sendmail_to_system_managers(title, traceback)
|
@ -98,6 +98,8 @@ class Account(NestedSet):
|
||||
|
||||
ancestors = get_root_company(self.company)
|
||||
if ancestors:
|
||||
if frappe.get_value("Company", self.company, "allow_account_creation_against_child_company"):
|
||||
return
|
||||
frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0]))
|
||||
else:
|
||||
descendants = get_descendants_of('Company', self.company)
|
||||
@ -110,6 +112,8 @@ class Account(NestedSet):
|
||||
["company", "name"], as_dict=True):
|
||||
acc_name_map[d["company"]] = d["name"]
|
||||
|
||||
if not acc_name_map: return
|
||||
|
||||
for company in descendants:
|
||||
doc = frappe.copy_doc(self)
|
||||
doc.flags.ignore_root_company_validation = True
|
||||
|
@ -23,6 +23,10 @@ frappe.treeview_settings["Account"] = {
|
||||
if(r.message) {
|
||||
let root_company = r.message.length ? r.message[0] : "";
|
||||
me.page.fields_dict.root_company.set_value(root_company);
|
||||
|
||||
frappe.db.get_value("Company", {"name": company}, "allow_account_creation_against_child_company", (r) => {
|
||||
frappe.flags.ignore_root_company_validation = r.allow_account_creation_against_child_company;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -133,9 +137,10 @@ frappe.treeview_settings["Account"] = {
|
||||
{
|
||||
label:__("Add Child"),
|
||||
condition: function(node) {
|
||||
return frappe.boot.user.can_create.indexOf("Account") !== -1 &&
|
||||
!frappe.treeview_settings['Account'].treeview.page.fields_dict.root_company.get_value() &&
|
||||
node.expandable && !node.hide_add;
|
||||
return frappe.boot.user.can_create.indexOf("Account") !== -1
|
||||
&& (!frappe.treeview_settings['Account'].treeview.page.fields_dict.root_company.get_value()
|
||||
|| frappe.flags.ignore_root_company_validation)
|
||||
&& node.expandable && !node.hide_add;
|
||||
},
|
||||
click: function() {
|
||||
var me = frappe.treeview_settings['Account'].treeview;
|
||||
|
@ -183,6 +183,10 @@ def get_inventory_account(company, warehouse=None):
|
||||
return account
|
||||
|
||||
def create_account(**kwargs):
|
||||
account = frappe.db.get_value("Account", filters={"account_name": kwargs.get("account_name"), "company": kwargs.get("company")})
|
||||
if account:
|
||||
return account
|
||||
else:
|
||||
account = frappe.get_doc(dict(
|
||||
doctype = "Account",
|
||||
account_name = kwargs.get('account_name'),
|
||||
|
@ -23,6 +23,7 @@
|
||||
"columns": 0,
|
||||
"default": "1",
|
||||
"description": "If enabled, the system will post accounting entries for inventory automatically.",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "auto_accounting_for_stock",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
@ -55,6 +56,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "acc_frozen_upto",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
@ -87,6 +89,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "frozen_accounts_modifier",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -121,6 +124,7 @@
|
||||
"columns": 0,
|
||||
"default": "Billing Address",
|
||||
"description": "Address used to determine Tax Category in transactions.",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "determine_address_tax_category_from",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
@ -154,6 +158,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@ -186,6 +191,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Role that is allowed to submit transactions that exceed credit limits set.",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "credit_controller",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -218,6 +224,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "check_supplier_invoice_uniqueness",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@ -250,6 +257,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "make_payment_via_journal_entry",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@ -283,6 +291,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "1",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "unlink_payment_on_cancellation_of_invoice",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@ -316,6 +325,41 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "1",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "unlink_advance_payment_on_cancelation_of_order",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Unlink Advance Payment on Cancelation of Order",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "1",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "book_asset_depreciation_entry_automatically",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@ -348,6 +392,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "allow_cost_center_in_entry_of_bs_account",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@ -381,6 +426,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "1",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "add_taxes_from_item_tax_template",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@ -413,6 +459,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "print_settings",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -445,6 +492,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "show_inclusive_tax_in_print",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@ -477,6 +525,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_12",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@ -508,6 +557,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "show_payment_schedule_in_print",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@ -540,6 +590,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "currency_exchange_section",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -573,6 +624,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "1",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "allow_stale",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@ -607,6 +659,7 @@
|
||||
"columns": 0,
|
||||
"default": "1",
|
||||
"depends_on": "eval:doc.allow_stale==0",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "stale_days",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
@ -639,6 +692,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "report_settings_sb",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -673,6 +727,7 @@
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"description": "Only select if you have setup Cash Flow Mapper documents",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "use_custom_cash_flow",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@ -700,17 +755,15 @@
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"icon": "icon-cog",
|
||||
"idx": 1,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 1,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-01-07 00:42:34.510150",
|
||||
"modified": "2019-04-06 12:28:43.026250",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounts Settings",
|
||||
@ -776,7 +829,6 @@
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_order": "ASC",
|
||||
"track_changes": 1,
|
||||
|
@ -42,8 +42,8 @@ class BankReconciliation(Document):
|
||||
select
|
||||
"Payment Entry" as payment_document, name as payment_entry,
|
||||
reference_no as cheque_number, reference_date as cheque_date,
|
||||
if(paid_from=%(account)s, paid_amount, "") as credit,
|
||||
if(paid_from=%(account)s, "", received_amount) as debit,
|
||||
if(paid_from=%(account)s, paid_amount, 0) as credit,
|
||||
if(paid_from=%(account)s, 0, received_amount) as debit,
|
||||
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`
|
||||
@ -79,8 +79,12 @@ class BankReconciliation(Document):
|
||||
|
||||
for d in entries:
|
||||
row = self.append('payment_entries', {})
|
||||
amount = d.debit if d.debit else d.credit
|
||||
d.amount = fmt_money(amount, 2, d.account_currency) + " " + (_("Dr") if d.debit else _("Cr"))
|
||||
|
||||
amount = flt(d.get('debit', 0)) - flt(d.get('credit', 0))
|
||||
|
||||
formatted_amount = fmt_money(abs(amount), 2, d.account_currency)
|
||||
d.amount = formatted_amount + " " + (_("Dr") if amount > 0 else _("Cr"))
|
||||
|
||||
d.pop("credit")
|
||||
d.pop("debit")
|
||||
d.pop("account_currency")
|
||||
|
@ -52,11 +52,6 @@ class JournalEntry(AccountsController):
|
||||
self.update_loan()
|
||||
self.update_inter_company_jv()
|
||||
|
||||
def before_print(self):
|
||||
self.gl_entries = frappe.get_list("GL Entry",filters={"voucher_type": "Journal Entry",
|
||||
"voucher_no": self.name} ,
|
||||
fields=["account", "party_type", "party", "debit", "credit", "remarks"]
|
||||
)
|
||||
|
||||
def get_title(self):
|
||||
return self.pay_to_recd_from or self.accounts[0].account
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.utils import flt
|
||||
from frappe import _
|
||||
from frappe.utils import (flt, add_months)
|
||||
from frappe.model.document import Document
|
||||
|
||||
class MonthlyDistribution(Document):
|
||||
@ -25,3 +25,33 @@ class MonthlyDistribution(Document):
|
||||
if flt(total, 2) != 100.0:
|
||||
frappe.throw(_("Percentage Allocation should be equal to 100%") + \
|
||||
" ({0}%)".format(str(flt(total, 2))))
|
||||
|
||||
def get_periodwise_distribution_data(distribution_id, period_list, periodicity):
|
||||
doc = frappe.get_doc('Monthly Distribution', distribution_id)
|
||||
|
||||
months_to_add = {
|
||||
"Yearly": 12,
|
||||
"Half-Yearly": 6,
|
||||
"Quarterly": 3,
|
||||
"Monthly": 1
|
||||
}[periodicity]
|
||||
|
||||
period_dict = {}
|
||||
|
||||
for d in period_list:
|
||||
period_dict[d.key] = get_percentage(doc, d.from_date, months_to_add)
|
||||
|
||||
return period_dict
|
||||
|
||||
def get_percentage(doc, start_date, period):
|
||||
percentage = 0
|
||||
months = [start_date.strftime("%B").title()]
|
||||
|
||||
for r in range(1, period):
|
||||
months.append(add_months(start_date, r).strftime("%B").title())
|
||||
|
||||
for d in doc.percentages:
|
||||
if d.month in months:
|
||||
percentage += d.percentage_allocation
|
||||
|
||||
return percentage
|
@ -70,11 +70,6 @@ class PaymentEntry(AccountsController):
|
||||
self.update_advance_paid()
|
||||
self.update_expense_claim()
|
||||
|
||||
def before_print(self):
|
||||
self.gl_entries = frappe.get_list("GL Entry",filters={"voucher_type": "Payment Entry",
|
||||
"voucher_no": self.name} ,
|
||||
fields=["account", "party_type", "party", "debit", "credit", "remarks"]
|
||||
)
|
||||
|
||||
def on_cancel(self):
|
||||
self.setup_party_account_field()
|
||||
@ -754,7 +749,7 @@ def get_outstanding_on_journal_entry(name):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_reference_details(reference_doctype, reference_name, party_account_currency):
|
||||
total_amount = outstanding_amount = exchange_rate = None
|
||||
total_amount = outstanding_amount = exchange_rate = bill_no = None
|
||||
ref_doc = frappe.get_doc(reference_doctype, reference_name)
|
||||
company_currency = ref_doc.get("company_currency") or erpnext.get_company_currency(ref_doc.company)
|
||||
|
||||
@ -788,6 +783,7 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
|
||||
|
||||
if reference_doctype in ("Sales Invoice", "Purchase Invoice"):
|
||||
outstanding_amount = ref_doc.get("outstanding_amount")
|
||||
bill_no = ref_doc.get("bill_no")
|
||||
elif reference_doctype == "Expense Claim":
|
||||
outstanding_amount = flt(ref_doc.get("total_sanctioned_amount")) \
|
||||
- flt(ref_doc.get("total_amount+reimbursed")) - flt(ref_doc.get("total_advance_amount"))
|
||||
@ -804,7 +800,8 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
|
||||
"due_date": ref_doc.get("due_date"),
|
||||
"total_amount": total_amount,
|
||||
"outstanding_amount": outstanding_amount,
|
||||
"exchange_rate": exchange_rate
|
||||
"exchange_rate": exchange_rate,
|
||||
"bill_no": bill_no
|
||||
})
|
||||
|
||||
|
||||
|
@ -155,7 +155,6 @@ def pos_profile_query(doctype, txt, searchfield, start, page_len, filters):
|
||||
def set_default_profile(pos_profile, company):
|
||||
modified = now()
|
||||
user = frappe.session.user
|
||||
company = frappe.db.escape(company)
|
||||
|
||||
if pos_profile and company:
|
||||
frappe.db.sql(""" update `tabPOS Profile User` pfu, `tabPOS Profile` pf
|
||||
|
@ -119,7 +119,7 @@ class PricingRule(Document):
|
||||
#--------------------------------------------------------------------------------
|
||||
|
||||
@frappe.whitelist()
|
||||
def apply_pricing_rule(args):
|
||||
def apply_pricing_rule(args, doc=None):
|
||||
"""
|
||||
args = {
|
||||
"items": [{"doctype": "", "name": "", "item_code": "", "brand": "", "item_group": ""}, ...],
|
||||
@ -139,6 +139,7 @@ def apply_pricing_rule(args):
|
||||
"ignore_pricing_rule": "something"
|
||||
}
|
||||
"""
|
||||
|
||||
if isinstance(args, string_types):
|
||||
args = json.loads(args)
|
||||
|
||||
@ -161,10 +162,11 @@ def apply_pricing_rule(args):
|
||||
for item in item_list:
|
||||
args_copy = copy.deepcopy(args)
|
||||
args_copy.update(item)
|
||||
data = get_pricing_rule_for_item(args_copy, item.get('price_list_rate'))
|
||||
data = get_pricing_rule_for_item(args_copy, item.get('price_list_rate'), doc=doc)
|
||||
out.append(data)
|
||||
if set_serial_nos_based_on_fifo and not args.get('is_return'):
|
||||
out.append(get_serial_no_for_item(args_copy))
|
||||
if not item.get("serial_no") and set_serial_nos_based_on_fifo and not args.get('is_return'):
|
||||
out[0].update(get_serial_no_for_item(args_copy))
|
||||
|
||||
return out
|
||||
|
||||
def get_serial_no_for_item(args):
|
||||
@ -182,6 +184,12 @@ def get_serial_no_for_item(args):
|
||||
def get_pricing_rule_for_item(args, price_list_rate=0, doc=None):
|
||||
from erpnext.accounts.doctype.pricing_rule.utils import get_pricing_rules
|
||||
|
||||
if isinstance(doc, string_types):
|
||||
doc = json.loads(doc)
|
||||
|
||||
if doc:
|
||||
doc = frappe.get_doc(doc)
|
||||
|
||||
if (args.get('is_free_item') or
|
||||
args.get("parenttype") == "Material Request"): return {}
|
||||
|
||||
@ -227,11 +235,11 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None):
|
||||
if pricing_rules:
|
||||
rules = []
|
||||
|
||||
item_details.discount_percentage = 0
|
||||
item_details.discount_amount = 0
|
||||
for pricing_rule in pricing_rules:
|
||||
if not pricing_rule or pricing_rule.get('suggestion'): continue
|
||||
|
||||
item_details.validate_applied_rule = pricing_rule.get("validate_applied_rule", 0)
|
||||
|
||||
rules.append(get_pricing_rule_details(args, pricing_rule))
|
||||
if pricing_rule.mixed_conditions or pricing_rule.apply_rule_on_other:
|
||||
continue
|
||||
@ -243,8 +251,8 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None):
|
||||
item_details.has_pricing_rule = 1
|
||||
|
||||
# if discount is applied on the rate and not on price list rate
|
||||
if price_list_rate:
|
||||
set_discount_amount(price_list_rate, item_details)
|
||||
# if price_list_rate:
|
||||
# set_discount_amount(price_list_rate, item_details)
|
||||
|
||||
item_details.pricing_rules = ','.join([d.pricing_rule for d in rules])
|
||||
|
||||
@ -264,7 +272,7 @@ def get_pricing_rule_details(args, pricing_rule):
|
||||
'pricing_rule': pricing_rule.name,
|
||||
'rate_or_discount': pricing_rule.rate_or_discount,
|
||||
'margin_type': pricing_rule.margin_type,
|
||||
'item_code': pricing_rule.item_code,
|
||||
'item_code': pricing_rule.item_code or args.get("item_code"),
|
||||
'child_docname': args.get('child_docname')
|
||||
})
|
||||
|
||||
@ -296,6 +304,9 @@ def apply_price_discount_pricing_rule(pricing_rule, item_details, args):
|
||||
discount_field = "{0}_on_rate".format(field)
|
||||
item_details[discount_field].append(pricing_rule.get(field, 0))
|
||||
else:
|
||||
if field not in item_details:
|
||||
item_details.setdefault(field, 0)
|
||||
|
||||
item_details[field] += (pricing_rule.get(field, 0)
|
||||
if pricing_rule else args.get(field, 0))
|
||||
|
||||
@ -308,6 +319,7 @@ def set_discount_amount(rate, item_details):
|
||||
item_details.rate = rate
|
||||
|
||||
def remove_pricing_rule_for_item(pricing_rules, item_details, item_code=None):
|
||||
from erpnext.accounts.doctype.pricing_rule.utils import get_apply_on_and_items
|
||||
for d in pricing_rules.split(','):
|
||||
if not d: continue
|
||||
pricing_rule = frappe.get_doc('Pricing Rule', d)
|
||||
@ -327,6 +339,11 @@ def remove_pricing_rule_for_item(pricing_rules, item_details, item_code=None):
|
||||
item_details.remove_free_item = (item_code if pricing_rule.get('same_item')
|
||||
else pricing_rule.get('free_item'))
|
||||
|
||||
if pricing_rule.get("mixed_conditions") or pricing_rule.get("apply_rule_on_other"):
|
||||
apply_on, items = get_apply_on_and_items(pricing_rule, item_details)
|
||||
item_details.apply_on = apply_on
|
||||
item_details.applied_on_items = ','.join(items)
|
||||
|
||||
item_details.pricing_rules = ''
|
||||
|
||||
return item_details
|
||||
@ -368,35 +385,6 @@ def make_pricing_rule(doctype, docname):
|
||||
|
||||
return doc
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_free_items(pricing_rules, item_row):
|
||||
if isinstance(item_row, string_types):
|
||||
item_row = json.loads(item_row)
|
||||
|
||||
free_items = []
|
||||
pricing_rules = list(set(pricing_rules.split(',')))
|
||||
|
||||
for d in pricing_rules:
|
||||
pr_doc = frappe.get_doc('Pricing Rule', d)
|
||||
if pr_doc.price_or_product_discount == 'Product':
|
||||
item = (item_row.get('item_code') if pr_doc.same_item
|
||||
else pr_doc.free_item)
|
||||
if not item: return free_items
|
||||
|
||||
doc = frappe.get_doc('Item', item)
|
||||
|
||||
free_items.append({
|
||||
'item_code': item,
|
||||
'item_name': doc.item_name,
|
||||
'description': doc.description,
|
||||
'qty': pr_doc.free_qty,
|
||||
'uom': pr_doc.free_item_uom,
|
||||
'rate': pr_doc.free_item_rate or 0,
|
||||
'is_free_item': 1
|
||||
})
|
||||
|
||||
return free_items
|
||||
|
||||
def get_item_uoms(doctype, txt, searchfield, start, page_len, filters):
|
||||
items = [filters.get('value')]
|
||||
if filters.get('apply_on') != 'Item Code':
|
||||
|
@ -4,16 +4,21 @@
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import json
|
||||
import copy
|
||||
import frappe, copy, json
|
||||
from frappe import throw, _
|
||||
from six import string_types
|
||||
from frappe.utils import flt, cint, get_datetime
|
||||
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
|
||||
from erpnext.stock.get_item_details import get_conversion_factor
|
||||
|
||||
class MultiplePricingRuleConflict(frappe.ValidationError): pass
|
||||
|
||||
apply_on_table = {
|
||||
'Item Code': 'items',
|
||||
'Item Group': 'item_groups',
|
||||
'Brand': 'brands'
|
||||
}
|
||||
|
||||
def get_pricing_rules(args, doc=None):
|
||||
pricing_rules = []
|
||||
values = {}
|
||||
@ -33,7 +38,9 @@ def get_pricing_rules(args, doc=None):
|
||||
if pricing_rule:
|
||||
rules.append(pricing_rule)
|
||||
else:
|
||||
rules.append(filter_pricing_rules(args, pricing_rules, doc))
|
||||
pricing_rule = filter_pricing_rules(args, pricing_rules, doc)
|
||||
if pricing_rule:
|
||||
rules.append(pricing_rule)
|
||||
|
||||
return rules
|
||||
|
||||
@ -169,7 +176,7 @@ def filter_pricing_rules(args, pricing_rules, doc=None):
|
||||
pr_doc = frappe.get_doc('Pricing Rule', pricing_rules[0].name)
|
||||
|
||||
if pricing_rules[0].mixed_conditions and doc:
|
||||
stock_qty, amount = get_qty_and_rate_for_mixed_conditions(doc, pr_doc)
|
||||
stock_qty, amount = get_qty_and_rate_for_mixed_conditions(doc, pr_doc, args)
|
||||
|
||||
elif pricing_rules[0].is_cumulative:
|
||||
items = [args.get(frappe.scrub(pr_doc.get('apply_on')))]
|
||||
@ -308,7 +315,7 @@ def apply_internal_priority(pricing_rules, field_set, args):
|
||||
|
||||
return filtered_rules or pricing_rules
|
||||
|
||||
def get_qty_and_rate_for_mixed_conditions(doc, pr_doc):
|
||||
def get_qty_and_rate_for_mixed_conditions(doc, pr_doc, args):
|
||||
sum_qty, sum_amt = [0, 0]
|
||||
items = get_pricing_rule_items(pr_doc) or []
|
||||
apply_on = frappe.scrub(pr_doc.get('apply_on'))
|
||||
@ -318,8 +325,12 @@ def get_qty_and_rate_for_mixed_conditions(doc, pr_doc):
|
||||
if row.get(apply_on) not in items: continue
|
||||
|
||||
if pr_doc.mixed_conditions:
|
||||
sum_qty += row.stock_qty
|
||||
sum_amt += row.amount
|
||||
amt = args.get('qty') * args.get("price_list_rate")
|
||||
if args.get("item_code") != row.get("item_code"):
|
||||
amt = row.get('qty') * row.get("price_list_rate")
|
||||
|
||||
sum_qty += row.get("stock_qty") or args.get("stock_qty")
|
||||
sum_amt += amt
|
||||
|
||||
if pr_doc.is_cumulative:
|
||||
data = get_qty_amount_data_for_cumulative(pr_doc, doc, items)
|
||||
@ -334,8 +345,8 @@ def get_qty_and_rate_for_other_item(doc, pr_doc, pricing_rules):
|
||||
for d in get_pricing_rule_items(pr_doc):
|
||||
for row in doc.items:
|
||||
if d == row.get(frappe.scrub(pr_doc.apply_on)):
|
||||
pricing_rules = filter_pricing_rules_for_qty_amount(row.stock_qty,
|
||||
row.amount, pricing_rules, row)
|
||||
pricing_rules = filter_pricing_rules_for_qty_amount(row.get("stock_qty"),
|
||||
row.get("amount"), pricing_rules, row)
|
||||
|
||||
if pricing_rules and pricing_rules[0]:
|
||||
return pricing_rules
|
||||
@ -389,17 +400,15 @@ def get_qty_amount_data_for_cumulative(pr_doc, doc, items=[]):
|
||||
def validate_pricing_rules(doc):
|
||||
validate_pricing_rule_on_transactions(doc)
|
||||
|
||||
if not doc.pricing_rules: return
|
||||
|
||||
for d in doc.items:
|
||||
validate_pricing_rule_on_items(doc, d)
|
||||
|
||||
doc.calculate_taxes_and_totals()
|
||||
|
||||
def validate_pricing_rule_on_items(doc, item_row):
|
||||
def validate_pricing_rule_on_items(doc, item_row, do_not_validate = False):
|
||||
value = 0
|
||||
for pr_row in get_applied_pricing_rules(doc, item_row):
|
||||
pr_doc = frappe.get_doc('Pricing Rule', pr_row.pricing_rule)
|
||||
for pricing_rule in get_applied_pricing_rules(doc, item_row):
|
||||
pr_doc = frappe.get_doc('Pricing Rule', pricing_rule)
|
||||
|
||||
if pr_doc.get('apply_on') == 'Transaction': continue
|
||||
|
||||
@ -410,7 +419,7 @@ def validate_pricing_rule_on_items(doc, item_row):
|
||||
if not pr_doc.get(field): continue
|
||||
|
||||
value += pr_doc.get(field)
|
||||
apply_pricing_rule(doc, pr_doc, pr_row, item_row, value)
|
||||
apply_pricing_rule(doc, pr_doc, item_row, value, do_not_validate)
|
||||
|
||||
def validate_pricing_rule_on_transactions(doc):
|
||||
conditions = "apply_on = 'Transaction'"
|
||||
@ -445,8 +454,8 @@ def validate_pricing_rule_on_transactions(doc):
|
||||
apply_pricing_rule_for_free_items(doc, d)
|
||||
|
||||
def get_applied_pricing_rules(doc, item_row):
|
||||
return [d for d in doc.pricing_rules
|
||||
if d.child_docname == item_row.name]
|
||||
return (item_row.get("pricing_rules").split(',')
|
||||
if item_row.get("pricing_rules") else [])
|
||||
|
||||
def apply_pricing_rule_for_free_items(doc, pricing_rule):
|
||||
if pricing_rule.get('free_item'):
|
||||
@ -465,7 +474,37 @@ def apply_pricing_rule_for_free_items(doc, pricing_rule):
|
||||
|
||||
doc.set_missing_values()
|
||||
|
||||
def apply_pricing_rule(doc, pr_doc, pr_row, item_row, value):
|
||||
def apply_pricing_rule(doc, pr_doc, item_row, value, do_not_validate=False):
|
||||
apply_on, items = get_apply_on_and_items(pr_doc, item_row)
|
||||
|
||||
rule_applied = {}
|
||||
|
||||
for item in doc.get("items"):
|
||||
if not item.pricing_rules:
|
||||
item.pricing_rules = item_row.pricing_rules
|
||||
|
||||
if item.get(apply_on) in items:
|
||||
for field in ['discount_percentage', 'discount_amount', 'rate']:
|
||||
if not pr_doc.get(field): continue
|
||||
|
||||
key = (item.name, item.pricing_rules)
|
||||
if not pr_doc.validate_applied_rule:
|
||||
rule_applied[key] = 1
|
||||
item.set(field, value)
|
||||
elif item.get(field) < value:
|
||||
if not do_not_validate and item.idx == item_row.idx:
|
||||
rule_applied[key] = 0
|
||||
frappe.msgprint(_("Row {0}: user has not applied rule <b>{1}</b> on the item <b>{2}</b>")
|
||||
.format(item.idx, pr_doc.title, item.item_code))
|
||||
|
||||
if rule_applied and doc.get("pricing_rules"):
|
||||
for d in doc.get("pricing_rules"):
|
||||
key = (d.child_docname, d.pricing_rule)
|
||||
if key in rule_applied:
|
||||
d.rule_applied = 1
|
||||
|
||||
def get_apply_on_and_items(pr_doc, item_row):
|
||||
# for mixed or other items conditions
|
||||
apply_on = frappe.scrub(pr_doc.get('apply_on'))
|
||||
items = (get_pricing_rule_items(pr_doc)
|
||||
if pr_doc.mixed_conditions else [item_row.get(apply_on)])
|
||||
@ -474,20 +513,22 @@ def apply_pricing_rule(doc, pr_doc, pr_row, item_row, value):
|
||||
apply_on = frappe.scrub(pr_doc.apply_rule_on_other)
|
||||
items = [pr_doc.get(apply_on)]
|
||||
|
||||
rule_applied = 1
|
||||
if item_row.get(apply_on) in items:
|
||||
for field in ['discount_percentage', 'discount_amount', 'rate']:
|
||||
if not pr_doc.get(field): continue
|
||||
|
||||
if not pr_doc.validate_applied_rule:
|
||||
item_row.set(field, value)
|
||||
elif item_row.get(field) < value:
|
||||
rule_applied = 0
|
||||
frappe.msgprint(_("Row {0}: user has not applied rule <b>{1}</b> on the item <b>{2}</b>")
|
||||
.format(item_row.idx, pr_doc.title, item_row.item_code))
|
||||
|
||||
pr_row.rule_applied = rule_applied
|
||||
return apply_on, items
|
||||
|
||||
def get_pricing_rule_items(pr_doc):
|
||||
apply_on = frappe.scrub(pr_doc.get('apply_on'))
|
||||
return [item.get(apply_on) for item in pr_doc.items] or []
|
||||
|
||||
pricing_rule_apply_on = apply_on_table.get(pr_doc.get('apply_on'))
|
||||
|
||||
return [item.get(apply_on) for item in pr_doc.get(pricing_rule_apply_on)] or []
|
||||
|
||||
@frappe.whitelist()
|
||||
def validate_pricing_rule_for_different_cond(doc):
|
||||
if isinstance(doc, string_types):
|
||||
doc = json.loads(doc)
|
||||
|
||||
doc = frappe.get_doc(doc)
|
||||
for d in doc.get("items"):
|
||||
validate_pricing_rule_on_items(doc, d, True)
|
||||
|
||||
return doc
|
@ -468,7 +468,7 @@ cur_frm.fields_dict["items"].grid.get_field("cost_center").get_query = function(
|
||||
|
||||
cur_frm.cscript.cost_center = function(doc, cdt, cdn){
|
||||
var d = locals[cdt][cdn];
|
||||
if(d.idx == 1 && d.cost_center){
|
||||
if(d.cost_center){
|
||||
var cl = doc.items || [];
|
||||
for(var i = 0; i < cl.length; i++){
|
||||
if(!cl[i].cost_center) cl[i].cost_center = d.cost_center;
|
||||
|
@ -55,11 +55,6 @@ class PurchaseInvoice(BuyingController):
|
||||
if not self.on_hold:
|
||||
self.release_date = ''
|
||||
|
||||
def before_print(self):
|
||||
self.gl_entries = frappe.get_list("GL Entry",filters={"voucher_type": "Purchase Invoice",
|
||||
"voucher_no": self.name} ,
|
||||
fields=["account", "party_type", "party", "debit", "credit"]
|
||||
)
|
||||
|
||||
def invoice_is_blocked(self):
|
||||
return self.on_hold and (not self.release_date or self.release_date > getdate(nowdate()))
|
||||
@ -770,10 +765,6 @@ class PurchaseInvoice(BuyingController):
|
||||
self.update_status_updater_args()
|
||||
|
||||
if not self.is_return:
|
||||
from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
|
||||
if frappe.db.get_single_value('Accounts Settings', 'unlink_payment_on_cancellation_of_invoice'):
|
||||
unlink_ref_doc_from_payment_entries(self)
|
||||
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
|
||||
self.update_billing_status_in_pr()
|
||||
|
@ -89,6 +89,12 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
}, __('Create'));
|
||||
}
|
||||
|
||||
if (doc.docstatus === 1) {
|
||||
cur_frm.add_custom_button(__('Maintenance Schedule'), function () {
|
||||
cur_frm.cscript.make_maintenance_schedule();
|
||||
}, __('Create'));
|
||||
}
|
||||
|
||||
if(!doc.auto_repeat) {
|
||||
cur_frm.add_custom_button(__('Subscription'), function() {
|
||||
erpnext.utils.make_subscription(doc.doctype, doc.name)
|
||||
@ -118,6 +124,13 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
}
|
||||
},
|
||||
|
||||
make_maintenance_schedule: function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_maintenance_schedule",
|
||||
frm: cur_frm
|
||||
})
|
||||
},
|
||||
|
||||
on_submit: function(doc, dt, dn) {
|
||||
var me = this;
|
||||
|
||||
|
@ -205,18 +205,11 @@ class SalesInvoice(SellingController):
|
||||
def before_cancel(self):
|
||||
self.update_time_sheet(None)
|
||||
|
||||
def before_print(self):
|
||||
self.gl_entries = frappe.get_list("GL Entry",filters={"voucher_type": "Sales Invoice",
|
||||
"voucher_no": self.name} ,
|
||||
fields=["account", "party_type", "party", "debit", "credit"]
|
||||
)
|
||||
|
||||
def on_cancel(self):
|
||||
self.check_sales_order_on_hold_or_close("sales_order")
|
||||
super(SalesInvoice, self).on_cancel()
|
||||
|
||||
from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
|
||||
if frappe.db.get_single_value('Accounts Settings', 'unlink_payment_on_cancellation_of_invoice'):
|
||||
unlink_ref_doc_from_payment_entries(self)
|
||||
self.check_sales_order_on_hold_or_close("sales_order")
|
||||
|
||||
if self.is_return and not self.update_billed_amount_in_sales_order:
|
||||
# NOTE status updating bypassed for is_return
|
||||
@ -1230,6 +1223,22 @@ def get_bank_cash_account(mode_of_payment, company):
|
||||
"account": account
|
||||
}
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_maintenance_schedule(source_name, target_doc=None):
|
||||
doclist = get_mapped_doc("Sales Invoice", source_name, {
|
||||
"Sales Invoice": {
|
||||
"doctype": "Maintenance Schedule",
|
||||
"validation": {
|
||||
"docstatus": ["=", 1]
|
||||
}
|
||||
},
|
||||
"Sales Invoice Item": {
|
||||
"doctype": "Maintenance Schedule Item",
|
||||
},
|
||||
}, target_doc)
|
||||
|
||||
return doclist
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_delivery_note(source_name, target_doc=None):
|
||||
def set_missing_values(source, target):
|
||||
|
@ -14,8 +14,9 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_per
|
||||
from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency
|
||||
from erpnext.stock.doctype.serial_no.serial_no import SerialNoWarehouseError
|
||||
from frappe.model.naming import make_autoname
|
||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account
|
||||
from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data
|
||||
from erpnext.stock.doctype.item.test_item import create_item
|
||||
from six import iteritems
|
||||
class TestSalesInvoice(unittest.TestCase):
|
||||
def make(self):
|
||||
@ -1572,6 +1573,56 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
|
||||
accounts_settings.save()
|
||||
|
||||
def test_deferred_revenue(self):
|
||||
deferred_account = create_account(account_name="Deferred Revenue",
|
||||
parent_account="Current Liabilities - _TC", company="_Test Company")
|
||||
|
||||
item = create_item("_Test Item for Deferred Accounting")
|
||||
item.enable_deferred_revenue = 1
|
||||
item.deferred_revenue_account = deferred_account
|
||||
item.no_of_months = 12
|
||||
item.save()
|
||||
|
||||
si = create_sales_invoice(item=item.name, posting_date="2019-01-10", do_not_submit=True)
|
||||
si.items[0].enable_deferred_revenue = 1
|
||||
si.items[0].service_start_date = "2019-01-10"
|
||||
si.items[0].service_end_date = "2019-03-15"
|
||||
si.items[0].deferred_revenue_account = deferred_account
|
||||
si.save()
|
||||
si.submit()
|
||||
|
||||
from erpnext.accounts.deferred_revenue import convert_deferred_revenue_to_income
|
||||
convert_deferred_revenue_to_income(start_date="2019-01-01", end_date="2019-01-31")
|
||||
|
||||
expected_gle = [
|
||||
[deferred_account, 33.85, 0.0, "2019-01-31"],
|
||||
["Sales - _TC", 0.0, 33.85, "2019-01-31"]
|
||||
]
|
||||
|
||||
self.check_gl_entries(si.name, expected_gle, "2019-01-10")
|
||||
|
||||
convert_deferred_revenue_to_income(start_date="2019-01-01", end_date="2019-03-31")
|
||||
|
||||
expected_gle = [
|
||||
[deferred_account, 43.08, 0.0, "2019-02-28"],
|
||||
["Sales - _TC", 0.0, 43.08, "2019-02-28"],
|
||||
[deferred_account, 23.07, 0.0, "2019-03-15"],
|
||||
["Sales - _TC", 0.0, 23.07, "2019-03-15"]
|
||||
]
|
||||
|
||||
self.check_gl_entries(si.name, expected_gle, "2019-01-31")
|
||||
|
||||
def check_gl_entries(self, voucher_no, expected_gle, posting_date):
|
||||
gl_entries = frappe.db.sql("""select account, debit, credit, posting_date
|
||||
from `tabGL Entry`
|
||||
where voucher_type='Sales Invoice' and voucher_no=%s and posting_date > %s
|
||||
order by posting_date asc, account asc""", (voucher_no, posting_date), as_dict=1)
|
||||
|
||||
for i, gle in enumerate(gl_entries):
|
||||
self.assertEqual(expected_gle[i][0], gle.account)
|
||||
self.assertEqual(expected_gle[i][1], gle.debit)
|
||||
self.assertEqual(expected_gle[i][2], gle.credit)
|
||||
self.assertEqual(getdate(expected_gle[i][3]), gle.posting_date)
|
||||
|
||||
def create_sales_invoice(**args):
|
||||
si = frappe.new_doc("Sales Invoice")
|
||||
|
@ -333,6 +333,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
var me = this;
|
||||
this.frm = {}
|
||||
this.load_data(true);
|
||||
this.frm.doc.offline_pos_name = '';
|
||||
this.setup();
|
||||
this.set_default_customer()
|
||||
},
|
||||
@ -345,7 +346,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
|
||||
if (load_doc) {
|
||||
this.frm.doc = JSON.parse(localStorage.getItem('doc'));
|
||||
this.frm.doc.offline_pos_name = null;
|
||||
}
|
||||
|
||||
$.each(this.meta, function (i, data) {
|
||||
@ -641,7 +641,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
me.list_customers_btn.toggleClass("view_customer");
|
||||
me.pos_bill.show();
|
||||
me.list_customers_btn.show();
|
||||
me.frm.doc.offline_pos_name = $(this).parents().attr('invoice-name')
|
||||
me.frm.doc.offline_pos_name = $(this).parents().attr('invoice-name');
|
||||
me.edit_record();
|
||||
})
|
||||
|
||||
@ -984,7 +984,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
}
|
||||
|
||||
if(!this.customer_doc.fields_dict.customer_pos_id.value) {
|
||||
this.customer_doc.set_value("customer_pos_id", $.now())
|
||||
this.customer_doc.set_value("customer_pos_id", frappe.datetime.now_datetime())
|
||||
}
|
||||
},
|
||||
|
||||
@ -1686,10 +1686,18 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
|
||||
create_invoice: function () {
|
||||
var me = this;
|
||||
var existing_pos_list = [];
|
||||
var invoice_data = {};
|
||||
this.si_docs = this.get_doc_from_localstorage();
|
||||
|
||||
if (this.frm.doc.offline_pos_name) {
|
||||
if(this.si_docs) {
|
||||
this.si_docs.forEach((row) => {
|
||||
existing_pos_list.push(Object.keys(row));
|
||||
});
|
||||
}
|
||||
|
||||
if (this.frm.doc.offline_pos_name
|
||||
&& in_list(existing_pos_list, this.frm.doc.offline_pos_name)) {
|
||||
this.update_invoice()
|
||||
//to retrieve and set the default payment
|
||||
invoice_data[this.frm.doc.offline_pos_name] = this.frm.doc;
|
||||
@ -1698,8 +1706,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
|
||||
this.frm.doc.paid_amount = this.frm.doc.net_total
|
||||
this.frm.doc.outstanding_amount = 0
|
||||
} else {
|
||||
this.frm.doc.offline_pos_name = $.now();
|
||||
} else if(!this.frm.doc.offline_pos_name) {
|
||||
this.frm.doc.offline_pos_name = frappe.datetime.now_datetime();
|
||||
this.frm.doc.posting_date = frappe.datetime.get_today();
|
||||
this.frm.doc.posting_time = frappe.datetime.now_time();
|
||||
this.frm.doc.pos_total_qty = this.frm.doc.qty_total;
|
||||
|
@ -592,13 +592,17 @@ def get_party_shipping_address(doctype, name):
|
||||
else:
|
||||
return ''
|
||||
|
||||
def get_partywise_advanced_payment_amount(party_type="Customer"):
|
||||
def get_partywise_advanced_payment_amount(party_type, posting_date = None):
|
||||
cond = "1=1"
|
||||
if posting_date:
|
||||
cond = "posting_date <= '{0}'".format(posting_date)
|
||||
|
||||
data = frappe.db.sql(""" SELECT party, sum({0}) as amount
|
||||
FROM `tabGL Entry`
|
||||
WHERE
|
||||
party_type = %s and against_voucher is null
|
||||
GROUP BY party"""
|
||||
.format(("credit") if party_type == "Customer" else "debit") , party_type)
|
||||
and {1} GROUP BY party"""
|
||||
.format(("credit") if party_type == "Customer" else "debit", cond) , party_type)
|
||||
|
||||
if data:
|
||||
return frappe._dict(data)
|
@ -136,7 +136,8 @@ class AccountsReceivableSummary(ReceivablePayableReport):
|
||||
|
||||
partywise_total = self.get_partywise_total(party_naming_by, args)
|
||||
|
||||
partywise_advance_amount = get_partywise_advanced_payment_amount(args.get("party_type")) or {}
|
||||
partywise_advance_amount = get_partywise_advanced_payment_amount(args.get("party_type"),
|
||||
self.filters.get("report_date")) or {}
|
||||
for party, party_dict in iteritems(partywise_total):
|
||||
row = [party]
|
||||
|
||||
@ -144,6 +145,9 @@ class AccountsReceivableSummary(ReceivablePayableReport):
|
||||
row += [self.get_party_name(args.get("party_type"), party)]
|
||||
|
||||
row += [partywise_advance_amount.get(party, 0)]
|
||||
|
||||
paid_amt = 0
|
||||
if party_dict.paid_amt > 0:
|
||||
paid_amt = flt(party_dict.paid_amt - partywise_advance_amount.get(party, 0))
|
||||
|
||||
row += [
|
||||
|
@ -14,7 +14,7 @@ def execute(filters=None):
|
||||
|
||||
def get_column():
|
||||
return [
|
||||
_("Delivery Note") + ":Link/Delivery Note:120", _("Date") + ":Date:100",
|
||||
_("Delivery Note") + ":Link/Delivery Note:120", _("Status") + "::120", _("Date") + ":Date:100",
|
||||
_("Suplier") + ":Link/Customer:120", _("Customer Name") + "::120",
|
||||
_("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120",
|
||||
_("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Pending Amount") + ":Currency:100",
|
||||
|
@ -17,7 +17,7 @@ def get_ordered_to_be_billed_data(args):
|
||||
|
||||
return frappe.db.sql("""
|
||||
Select
|
||||
`{parent_tab}`.name, `{parent_tab}`.{date_field}, `{parent_tab}`.{party}, `{parent_tab}`.{party}_name,
|
||||
`{parent_tab}`.name, `{parent_tab}`.status, `{parent_tab}`.{date_field}, `{parent_tab}`.{party}, `{parent_tab}`.{party}_name,
|
||||
{project_field}, `{child_tab}`.item_code, `{child_tab}`.base_amount,
|
||||
(`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1)),
|
||||
(`{child_tab}`.base_amount - (`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1))),
|
||||
|
@ -14,7 +14,7 @@ def execute(filters=None):
|
||||
|
||||
def get_column():
|
||||
return [
|
||||
_("Sales Order") + ":Link/Sales Order:120", _("Date") + ":Date:100",
|
||||
_("Sales Order") + ":Link/Sales Order:120", _("Status") + "::120", _("Date") + ":Date:100",
|
||||
_("Suplier") + ":Link/Customer:120", _("Customer Name") + "::120",
|
||||
_("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120",
|
||||
_("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Pending Amount") + ":Currency:100",
|
||||
|
@ -133,6 +133,13 @@ def get_columns(filters):
|
||||
"options": filters.get("based_on"),
|
||||
"width": 300
|
||||
},
|
||||
{
|
||||
"fieldname": "currency",
|
||||
"label": _("Currency"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Currency",
|
||||
"hidden": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "income",
|
||||
"label": _("Income"),
|
||||
@ -153,13 +160,6 @@ def get_columns(filters):
|
||||
"fieldtype": "Currency",
|
||||
"options": "currency",
|
||||
"width": 120
|
||||
},
|
||||
{
|
||||
"fieldname": "currency",
|
||||
"label": _("Currency"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Currency",
|
||||
"hidden": 1
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -14,7 +14,7 @@ def execute(filters=None):
|
||||
|
||||
def get_column():
|
||||
return [
|
||||
_("Purchase Order") + ":Link/Purchase Order:120", _("Date") + ":Date:100",
|
||||
_("Purchase Order") + ":Link/Purchase Order:120", _("Status") + "::120", _("Date") + ":Date:100",
|
||||
_("Suplier") + ":Link/Supplier:120", _("Suplier Name") + "::120",
|
||||
_("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120",
|
||||
_("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Amount to Bill") + ":Currency:100",
|
||||
|
@ -14,7 +14,7 @@ def execute(filters=None):
|
||||
|
||||
def get_column():
|
||||
return [
|
||||
_("Purchase Receipt") + ":Link/Purchase Receipt:120", _("Date") + ":Date:100",
|
||||
_("Purchase Receipt") + ":Link/Purchase Receipt:120", _("Status") + "::120", _("Date") + ":Date:100",
|
||||
_("Supplier") + ":Link/Supplier:120", _("Supplier Name") + "::120",
|
||||
_("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120",
|
||||
_("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Amount to Bill") + ":Currency:100",
|
||||
|
@ -25,9 +25,6 @@ frappe.ui.form.on("Purchase Order", {
|
||||
frm.set_indicator_formatter('item_code',
|
||||
function(doc) { return (doc.qty<=doc.received_qty) ? "green" : "orange" })
|
||||
|
||||
frm.set_indicator_formatter('pricing_rule',
|
||||
function(doc) { return (doc.rule_applied) ? "green" : "red" })
|
||||
|
||||
frm.set_query("blanket_order", "items", function() {
|
||||
return {
|
||||
filters: {
|
||||
|
@ -444,7 +444,7 @@ def make_rm_stock_entry(purchase_order, rm_items):
|
||||
item_wh = get_item_details(items)
|
||||
|
||||
stock_entry = frappe.new_doc("Stock Entry")
|
||||
stock_entry.purpose = "Subcontract"
|
||||
stock_entry.purpose = "Send to Subcontractor"
|
||||
stock_entry.purchase_order = purchase_order.name
|
||||
stock_entry.supplier = purchase_order.supplier
|
||||
stock_entry.supplier_name = purchase_order.supplier_name
|
||||
@ -452,6 +452,7 @@ def make_rm_stock_entry(purchase_order, rm_items):
|
||||
stock_entry.address_display = purchase_order.address_display
|
||||
stock_entry.company = purchase_order.company
|
||||
stock_entry.to_warehouse = purchase_order.supplier_warehouse
|
||||
stock_entry.set_stock_entry_type()
|
||||
|
||||
for item_code in fg_items:
|
||||
for rm_item_data in rm_items_list:
|
||||
|
@ -465,6 +465,33 @@ class TestPurchaseOrder(unittest.TestCase):
|
||||
self.assertEquals(se_items, supplied_items)
|
||||
update_backflush_based_on("BOM")
|
||||
|
||||
def test_advance_payment_entry_unlink_against_purchase_order(self):
|
||||
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
|
||||
frappe.db.set_value("Accounts Settings", "Accounts Settings",
|
||||
"unlink_advance_payment_on_cancelation_of_order", 1)
|
||||
|
||||
po_doc = create_purchase_order()
|
||||
|
||||
pe = get_payment_entry("Purchase Order", po_doc.name, bank_account="_Test Bank - _TC")
|
||||
pe.reference_no = "1"
|
||||
pe.reference_date = nowdate()
|
||||
pe.paid_from_account_currency = po_doc.currency
|
||||
pe.paid_to_account_currency = po_doc.currency
|
||||
pe.source_exchange_rate = 1
|
||||
pe.target_exchange_rate = 1
|
||||
pe.paid_amount = po_doc.grand_total
|
||||
pe.save(ignore_permissions=True)
|
||||
pe.submit()
|
||||
|
||||
po_doc = frappe.get_doc('Purchase Order', po_doc.name)
|
||||
po_doc.cancel()
|
||||
|
||||
pe_doc = frappe.get_doc('Payment Entry', pe.name)
|
||||
pe_doc.cancel()
|
||||
|
||||
frappe.db.set_value("Accounts Settings", "Accounts Settings",
|
||||
"unlink_advance_payment_on_cancelation_of_order", 0)
|
||||
|
||||
def make_subcontracted_item(item_code):
|
||||
from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
|
||||
|
||||
|
@ -81,9 +81,9 @@ def get_data():
|
||||
"description": "Sales pipeline, leads, opportunities and customers."
|
||||
},
|
||||
{
|
||||
"module_name": "Help Desk",
|
||||
"module_name": "Support",
|
||||
"category": "Modules",
|
||||
"label": _("Help Desk"),
|
||||
"label": _("Support"),
|
||||
"color": "#1abc9c",
|
||||
"icon": "fa fa-check-square-o",
|
||||
"type": "module",
|
||||
|
@ -1,82 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
from frappe import _
|
||||
|
||||
def get_data():
|
||||
return [
|
||||
{
|
||||
"label": _("Issues"),
|
||||
"items": [
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Issue",
|
||||
"description": _("Support queries from customers."),
|
||||
"onboard": 1,
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Communication",
|
||||
"description": _("Communication log."),
|
||||
"onboard": 1,
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": _("Warranty"),
|
||||
"items": [
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Warranty Claim",
|
||||
"description": _("Warranty Claim against Serial No."),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Serial No",
|
||||
"description": _("Single unit of an Item."),
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": _("Service Level Agreement"),
|
||||
"items": [
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Employee Group",
|
||||
"description": _("Support Team."),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Service Level",
|
||||
"description": _("Service Level."),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Service Level Agreement",
|
||||
"description": _("Service Level Agreement."),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": _("Reports"),
|
||||
"icon": "fa fa-list",
|
||||
"items": [
|
||||
{
|
||||
"type": "page",
|
||||
"name": "support-analytics",
|
||||
"label": _("Support Analytics"),
|
||||
"icon": "fa fa-bar-chart"
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
"name": "Minutes to First Response for Issues",
|
||||
"doctype": "Issue",
|
||||
"is_query_report": True
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
"name": "Support Hours",
|
||||
"doctype": "Issue",
|
||||
"is_query_report": True
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
@ -287,6 +287,11 @@ def get_data():
|
||||
"name": "Employee Advance",
|
||||
"dependencies": ["Employee"]
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Expense Claim",
|
||||
"dependencies": ["Employee"]
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Loan Type",
|
||||
@ -296,6 +301,10 @@ def get_data():
|
||||
"name": "Loan Application",
|
||||
"dependencies": ["Employee"]
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Loan"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -27,6 +27,13 @@ def get_data():
|
||||
"onboard": 1,
|
||||
"dependencies": ["Item", "Customer"],
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Sales Invoice",
|
||||
"description": _("Invoices for Costumers."),
|
||||
"onboard": 1,
|
||||
"dependencies": ["Item", "Customer"],
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Sales Partner",
|
||||
|
@ -10,11 +10,13 @@ def get_data():
|
||||
"type": "doctype",
|
||||
"name": "Issue",
|
||||
"description": _("Support queries from customers."),
|
||||
"onboard": 1,
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Communication",
|
||||
"description": _("Communication log."),
|
||||
"onboard": 1,
|
||||
},
|
||||
]
|
||||
},
|
||||
@ -33,6 +35,26 @@ def get_data():
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": _("Service Level Agreement"),
|
||||
"items": [
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Employee Group",
|
||||
"description": _("Support Team."),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Service Level",
|
||||
"description": _("Service Level."),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Service Level Agreement",
|
||||
"description": _("Service Level Agreement."),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": _("Reports"),
|
||||
"icon": "fa fa-list",
|
||||
@ -57,24 +79,4 @@ def get_data():
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": _("Service Level Agreement"),
|
||||
"items": [
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Employee Group",
|
||||
"description": _("Support Team."),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Service Level",
|
||||
"description": _("Service Level."),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Service Level Agreement",
|
||||
"description": _("Service Level Agreement."),
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
@ -119,6 +119,12 @@ class AccountsController(TransactionBase):
|
||||
self.validate_non_invoice_documents_schedule()
|
||||
|
||||
def before_print(self):
|
||||
if self.doctype in ['Journal Entry', 'Payment Entry', 'Sales Invoice', 'Purchase Invoice']:
|
||||
self.gl_entries = frappe.get_list("GL Entry", filters={
|
||||
"voucher_type": self.doctype,
|
||||
"voucher_no": self.name
|
||||
}, fields=["account", "party_type", "party", "debit", "credit", "remarks"])
|
||||
|
||||
if self.doctype in ['Purchase Order', 'Sales Order', 'Sales Invoice', 'Purchase Invoice',
|
||||
'Supplier Quotation', 'Purchase Receipt', 'Delivery Note', 'Quotation']:
|
||||
if self.get("group_same_items"):
|
||||
@ -276,7 +282,7 @@ class AccountsController(TransactionBase):
|
||||
if self.doctype in ["Purchase Invoice", "Sales Invoice"] and item.meta.get_field('is_fixed_asset'):
|
||||
item.set('is_fixed_asset', ret.get('is_fixed_asset', 0))
|
||||
|
||||
if ret.get("pricing_rules"):
|
||||
if ret.get("pricing_rules") and not ret.get("validate_applied_rule", 0):
|
||||
# if user changed the discount percentage then set user's discount percentage ?
|
||||
item.set("pricing_rules", ret.get("pricing_rules"))
|
||||
item.set("discount_percentage", ret.get("discount_percentage"))
|
||||
@ -546,6 +552,19 @@ class AccountsController(TransactionBase):
|
||||
from erpnext.accounts.utils import reconcile_against_document
|
||||
reconcile_against_document(lst)
|
||||
|
||||
def on_cancel(self):
|
||||
from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
|
||||
|
||||
if self.doctype in ["Sales Invoice", "Purchase Invoice"]:
|
||||
if self.is_return: return
|
||||
|
||||
if frappe.db.get_single_value('Accounts Settings', 'unlink_payment_on_cancellation_of_invoice'):
|
||||
unlink_ref_doc_from_payment_entries(self)
|
||||
|
||||
elif self.doctype in ["Sales Order", "Purchase Order"]:
|
||||
if frappe.db.get_single_value('Accounts Settings', 'unlink_advance_payment_on_cancelation_of_order'):
|
||||
unlink_ref_doc_from_payment_entries(self)
|
||||
|
||||
def validate_multiple_billing(self, ref_dt, item_ref_dn, based_on, parentfield):
|
||||
from erpnext.controllers.status_updater import get_tolerance_for
|
||||
item_tolerance = {}
|
||||
|
@ -538,6 +538,8 @@ class BuyingController(StockController):
|
||||
update_last_purchase_rate(self, is_submit = 1)
|
||||
|
||||
def on_cancel(self):
|
||||
super(BuyingController, self).on_cancel()
|
||||
|
||||
if self.get('is_return'):
|
||||
return
|
||||
|
||||
@ -736,7 +738,7 @@ def get_subcontracted_raw_materials_from_se(purchase_orders):
|
||||
sed.stock_uom, sed.subcontracted_item as main_item_code, sed.serial_no, sed.batch_no
|
||||
from `tabStock Entry` se,`tabStock Entry Detail` sed
|
||||
where
|
||||
se.name = sed.parent and se.docstatus=1 and se.purpose='Subcontract'
|
||||
se.name = sed.parent and se.docstatus=1 and se.purpose='Send to Subcontractor'
|
||||
and se.purchase_order in (%s) and ifnull(sed.t_warehouse, '') != ''
|
||||
group by sed.item_code, sed.t_warehouse
|
||||
""" % (','.join(['%s'] * len(purchase_orders))), tuple(purchase_orders), as_dict=1)
|
||||
|
@ -152,7 +152,6 @@ standard_portal_menu_items = [
|
||||
{"title": _("Issues"), "route": "/issues", "reference_doctype": "Issue", "role":"Customer"},
|
||||
{"title": _("Addresses"), "route": "/addresses", "reference_doctype": "Address"},
|
||||
{"title": _("Timesheets"), "route": "/timesheets", "reference_doctype": "Timesheet", "role":"Customer"},
|
||||
{"title": _("Timesheets"), "route": "/timesheets", "reference_doctype": "Timesheet", "role":"Customer"},
|
||||
{"title": _("Lab Test"), "route": "/lab-test", "reference_doctype": "Lab Test", "role":"Patient"},
|
||||
{"title": _("Prescription"), "route": "/prescription", "reference_doctype": "Patient Encounter", "role":"Patient"},
|
||||
{"title": _("Patient Appointment"), "route": "/patient-appointments", "reference_doctype": "Patient Appointment", "role":"Patient"},
|
||||
@ -241,8 +240,7 @@ scheduler_events = {
|
||||
"erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_mws_settings.schedule_get_order_details",
|
||||
"erpnext.accounts.doctype.gl_entry.gl_entry.rename_gle_sle_docs",
|
||||
"erpnext.projects.doctype.project.project.hourly_reminder",
|
||||
"erpnext.projects.doctype.project.project.collect_project_status",
|
||||
"erpnext.support.doctype.issue.issue.update_support_timer",
|
||||
"erpnext.projects.doctype.project.project.collect_project_status"
|
||||
],
|
||||
"daily": [
|
||||
"erpnext.stock.reorder_item.reorder_item",
|
||||
|
@ -400,6 +400,19 @@ def get_leave_balance_on(employee, leave_type, date, allocation_records=None, do
|
||||
|
||||
return flt(allocation.total_leaves_allocated) - (flt(leaves_taken) + flt(leaves_encashed))
|
||||
|
||||
def get_total_allocated_leaves(employee, leave_type, date):
|
||||
filters= {
|
||||
'from_date': ['<=', date],
|
||||
'to_date': ['>=', date],
|
||||
'docstatus': 1,
|
||||
'leave_type': leave_type,
|
||||
'employee': employee
|
||||
}
|
||||
|
||||
leave_allocation_records = frappe.db.get_all('Leave Allocation', filters=filters, fields=['total_leaves_allocated'])
|
||||
|
||||
return flt(leave_allocation_records[0]['total_leaves_allocated']) if leave_allocation_records else flt(0)
|
||||
|
||||
def get_leaves_for_period(employee, leave_type, from_date, to_date, status, docname=None):
|
||||
leave_applications = frappe.db.sql("""
|
||||
select name, employee, leave_type, from_date, to_date, total_leave_days
|
||||
|
@ -452,7 +452,10 @@ class SalarySlip(TransactionBase):
|
||||
|
||||
self.set_loan_repayment()
|
||||
|
||||
self.net_pay = flt(self.gross_pay) - (flt(self.total_deduction) + flt(self.total_loan_repayment))
|
||||
self.net_pay = 0
|
||||
if self.total_working_days:
|
||||
self.net_pay = (flt(self.gross_pay) - (flt(self.total_deduction) + flt(self.total_loan_repayment))) * flt(self.payment_days / self.total_working_days)
|
||||
|
||||
self.rounded_total = rounded(self.net_pay,
|
||||
self.precision("net_pay") if disable_rounded_total else 0)
|
||||
|
||||
|
@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from erpnext.hr.doctype.leave_application.leave_application \
|
||||
import get_leave_allocation_records, get_leave_balance_on, get_approved_leaves_for_period
|
||||
import get_leave_allocation_records, get_leave_balance_on, get_approved_leaves_for_period, get_total_allocated_leaves
|
||||
|
||||
|
||||
def execute(filters=None):
|
||||
@ -51,8 +51,7 @@ def get_data(filters, leave_types):
|
||||
filters.from_date, filters.to_date)
|
||||
|
||||
# opening balance
|
||||
opening = get_leave_balance_on(employee.name, leave_type, filters.from_date,
|
||||
allocation_records_based_on_from_date.get(employee.name, frappe._dict()))
|
||||
opening = get_total_allocated_leaves(employee.name, leave_type, filters.to_date)
|
||||
|
||||
# closing balance
|
||||
closing = get_leave_balance_on(employee.name, leave_type, filters.to_date,
|
||||
|
@ -14,11 +14,11 @@ def execute(filters=None):
|
||||
columns, earning_types, ded_types = get_columns(salary_slips)
|
||||
ss_earning_map = get_ss_earning_map(salary_slips)
|
||||
ss_ded_map = get_ss_ded_map(salary_slips)
|
||||
|
||||
doj_map = get_employee_doj_map()
|
||||
|
||||
data = []
|
||||
for ss in salary_slips:
|
||||
row = [ss.name, ss.employee, ss.employee_name, ss.branch, ss.department, ss.designation,
|
||||
row = [ss.name, ss.employee, ss.employee_name, doj_map.get(ss.employee), ss.branch, ss.department, ss.designation,
|
||||
ss.company, ss.start_date, ss.end_date, ss.leave_without_pay, ss.payment_days]
|
||||
|
||||
if not ss.branch == None:columns[3] = columns[3].replace('-1','120')
|
||||
@ -44,17 +44,17 @@ def execute(filters=None):
|
||||
def get_columns(salary_slips):
|
||||
"""
|
||||
columns = [
|
||||
_("Salary Slip ID") + ":Link/Salary Slip:150",_("Employee") + ":Link/Employee:120", _("Employee Name") + "::140", _("Branch") + ":Link/Branch:120",
|
||||
_("Department") + ":Link/Department:120", _("Designation") + ":Link/Designation:120",
|
||||
_("Company") + ":Link/Company:120", _("Start Date") + "::80", _("End Date") + "::80", _("Leave Without Pay") + ":Float:130",
|
||||
_("Payment Days") + ":Float:120"
|
||||
_("Salary Slip ID") + ":Link/Salary Slip:150",_("Employee") + ":Link/Employee:120", _("Employee Name") + "::140",
|
||||
_("Date of Joining") + "::80", _("Branch") + ":Link/Branch:120", _("Department") + ":Link/Department:120",
|
||||
_("Designation") + ":Link/Designation:120", _("Company") + ":Link/Company:120", _("Start Date") + "::80",
|
||||
_("End Date") + "::80", _("Leave Without Pay") + ":Float:130", _("Payment Days") + ":Float:120"
|
||||
]
|
||||
"""
|
||||
columns = [
|
||||
_("Salary Slip ID") + ":Link/Salary Slip:150",_("Employee") + ":Link/Employee:120", _("Employee Name") + "::140", _("Branch") + ":Link/Branch:-1",
|
||||
_("Department") + ":Link/Department:-1", _("Designation") + ":Link/Designation:-1",
|
||||
_("Company") + ":Link/Company:120", _("Start Date") + "::80", _("End Date") + "::80", _("Leave Without Pay") + ":Float:-1",
|
||||
_("Payment Days") + ":Float:120"
|
||||
_("Salary Slip ID") + ":Link/Salary Slip:150",_("Employee") + ":Link/Employee:120", _("Employee Name") + "::140",
|
||||
_("Date of Joining") + "::80", _("Branch") + ":Link/Branch:-1", _("Department") + ":Link/Department:-1",
|
||||
_("Designation") + ":Link/Designation:-1", _("Company") + ":Link/Company:120", _("Start Date") + "::80",
|
||||
_("End Date") + "::80", _("Leave Without Pay") + ":Float:-1", _("Payment Days") + ":Float:120"
|
||||
]
|
||||
|
||||
salary_components = {_("Earning"): [], _("Deduction"): []}
|
||||
@ -93,6 +93,16 @@ def get_conditions(filters):
|
||||
|
||||
return conditions, filters
|
||||
|
||||
def get_employee_doj_map():
|
||||
return frappe._dict(frappe.db.sql("""
|
||||
SELECT
|
||||
employee,
|
||||
date_of_joining
|
||||
FROM `tabEmployee`
|
||||
WHERE
|
||||
`status`='Active'
|
||||
"""))
|
||||
|
||||
def get_ss_earning_map(salary_slips):
|
||||
ss_earnings = frappe.db.sql("""select parent, salary_component, amount
|
||||
from `tabSalary Detail` where parent in (%s)""" %
|
||||
|
@ -568,6 +568,7 @@ def make_stock_entry(production_order_id, purpose, qty=None):
|
||||
stock_entry.bom_no = production_order.bom_no
|
||||
stock_entry.use_multi_level_bom = production_order.use_multi_level_bom
|
||||
stock_entry.fg_completed_qty = qty or (flt(production_order.qty) - flt(production_order.produced_qty))
|
||||
stock_entry.set_stock_entry_type()
|
||||
|
||||
if purpose=="Material Transfer for Manufacture":
|
||||
stock_entry.to_warehouse = wip_warehouse
|
||||
|
@ -631,6 +631,7 @@ def make_stock_entry(work_order_id, purpose, qty=None):
|
||||
additional_costs = get_additional_costs(work_order, fg_qty=stock_entry.fg_completed_qty)
|
||||
stock_entry.set("additional_costs", additional_costs)
|
||||
|
||||
stock_entry.set_stock_entry_type()
|
||||
stock_entry.get_items()
|
||||
return stock_entry.as_dict()
|
||||
|
||||
|
@ -586,8 +586,12 @@ execute:frappe.delete_doc('DocType', 'Notification Control')
|
||||
erpnext.patches.v12_0.set_gst_category
|
||||
erpnext.patches.v11_0.remove_barcodes_field_from_copy_fields_to_variants
|
||||
erpnext.patches.v12_0.set_task_status
|
||||
erpnext.patches.v11_0.make_italian_localization_fields # 01-03-2019
|
||||
erpnext.patches.v11_0.make_italian_localization_fields # 26-03-2019
|
||||
erpnext.patches.v12_0.add_item_name_in_work_orders
|
||||
erpnext.patches.v12_0.update_pricing_rule_fields
|
||||
erpnext.patches.v11_1.make_job_card_time_logs
|
||||
erpnext.patches.v12_0.rename_pricing_rule_child_doctypes
|
||||
erpnext.patches.v12_0.move_target_distribution_from_parent_to_child
|
||||
erpnext.patches.v12_0.stock_entry_enhancements
|
||||
erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019
|
||||
erpnext.patches.v12_0.move_item_tax_to_item_tax_template
|
||||
|
@ -6,7 +6,6 @@ from erpnext.regional.italy.setup import make_custom_fields, setup_report
|
||||
from erpnext.regional.italy import state_codes
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
company = frappe.get_all('Company', filters = {'country': 'Italy'})
|
||||
if not company:
|
||||
@ -27,4 +26,12 @@ def execute():
|
||||
frappe.db.sql("""
|
||||
UPDATE tabAddress set {condition} country_code = UPPER(ifnull((select code
|
||||
from `tabCountry` where name = `tabAddress`.country), ''))
|
||||
where country_code is null and state_code is null
|
||||
""".format(condition=condition))
|
||||
|
||||
frappe.db.sql("""
|
||||
UPDATE `tabSales Invoice Item` si, `tabSales Order` so
|
||||
set si.customer_po_no = so.po_no, si.customer_po_date = so.po_date
|
||||
WHERE
|
||||
si.sales_order = so.name and so.po_no is not null
|
||||
""")
|
||||
|
@ -14,6 +14,6 @@ def execute():
|
||||
set
|
||||
sed.subcontracted_item = pois.main_item_code
|
||||
where
|
||||
se.purpose = 'Subcontract' and sed.parent = se.name
|
||||
se.purpose = 'Send to Subcontractor' and sed.parent = se.name
|
||||
and pois.rm_item_code = sed.item_code and se.docstatus = 1
|
||||
and pois.parenttype = 'Purchase Order'""")
|
@ -3,6 +3,8 @@ import json
|
||||
from six import iteritems
|
||||
|
||||
def execute():
|
||||
if "tax_type" not in frappe.db.get_table_columns("Item Tax"):
|
||||
return
|
||||
old_item_taxes = {}
|
||||
item_tax_templates = {}
|
||||
rename_template_to_untitled = []
|
||||
|
@ -0,0 +1,22 @@
|
||||
# Copyright (c) 2017, Frappe and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc("setup", "doctype", "target_detail")
|
||||
|
||||
for d in ['Sales Person', 'Sales Partner', 'Territory']:
|
||||
frappe.db.sql("""
|
||||
UPDATE `tab{child_doc}`, `tab{parent_doc}`
|
||||
SET
|
||||
`tab{child_doc}`.distribution_id = `tab{parent_doc}`.distribution_id
|
||||
WHERE
|
||||
`tab{child_doc}`.parent = `tab{parent_doc}`.name
|
||||
and `tab{parent_doc}`.distribution_id is not null and `tab{parent_doc}`.distribution_id != ''
|
||||
""".format(parent_doc = d, child_doc = "Target Detail"))
|
||||
|
||||
frappe.delete_doc("Report", "Sales Partner-wise Transaction Summary")
|
||||
frappe.delete_doc("Report", "Sales Person Target Variance Item Group-Wise")
|
||||
frappe.delete_doc("Report", "Territory Target Variance Item Group-Wise")
|
52
erpnext/patches/v12_0/stock_entry_enhancements.py
Normal file
52
erpnext/patches/v12_0/stock_entry_enhancements.py
Normal file
@ -0,0 +1,52 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
||||
|
||||
def execute():
|
||||
create_stock_entry_types()
|
||||
|
||||
company = frappe.db.get_value("Company", {'country': 'India'}, 'name')
|
||||
if company:
|
||||
add_gst_hsn_code_field()
|
||||
|
||||
def create_stock_entry_types():
|
||||
frappe.reload_doc('stock', 'doctype', 'stock_entry_type')
|
||||
frappe.reload_doc('stock', 'doctype', 'stock_entry')
|
||||
|
||||
for purpose in ["Material Issue", "Material Receipt", "Material Transfer",
|
||||
"Material Transfer for Manufacture", "Material Consumption for Manufacture", "Manufacture",
|
||||
"Repack", "Send to Subcontractor", "Send to Warehouse", "Receive at Warehouse"]:
|
||||
|
||||
ste_type = frappe.get_doc({
|
||||
'doctype': 'Stock Entry Type',
|
||||
'name': purpose,
|
||||
'purpose': purpose
|
||||
})
|
||||
|
||||
try:
|
||||
ste_type.insert()
|
||||
except frappe.DuplicateEntryError:
|
||||
pass
|
||||
|
||||
frappe.db.sql(" UPDATE `tabStock Entry` set purpose = 'Send to Subcontractor' where purpose = 'Subcontract'")
|
||||
frappe.db.sql(" UPDATE `tabStock Entry` set stock_entry_type = purpose ")
|
||||
|
||||
def add_gst_hsn_code_field():
|
||||
custom_fields = {
|
||||
'Stock Entry Detail': [dict(fieldname='gst_hsn_code', label='HSN/SAC',
|
||||
fieldtype='Data', fetch_from='item_code.gst_hsn_code',
|
||||
insert_after='description', allow_on_submit=1, print_hide=0)]
|
||||
}
|
||||
|
||||
create_custom_fields(custom_fields, ignore_validate = frappe.flags.in_patch, update=True)
|
||||
|
||||
frappe.db.sql(""" update `tabStock Entry Detail`, `tabItem`
|
||||
SET
|
||||
`tabStock Entry Detail`.gst_hsn_code = `tabItem`.gst_hsn_code
|
||||
Where
|
||||
`tabItem`.name = `tabStock Entry Detail`.item_code and `tabItem`.gst_hsn_code is not null
|
||||
""")
|
@ -165,6 +165,13 @@ class Task(NestedSet):
|
||||
|
||||
self.update_nsm_model()
|
||||
|
||||
def update_status(self):
|
||||
if self.status not in ('Cancelled', 'Completed') and self.exp_end_date:
|
||||
from datetime import datetime
|
||||
if self.exp_end_date < datetime.now().date():
|
||||
self.db_set('status', 'Overdue')
|
||||
self.update_project()
|
||||
|
||||
@frappe.whitelist()
|
||||
def check_if_child_exists(name):
|
||||
child_tasks = frappe.get_all("Task", filters={"parent_task": name})
|
||||
@ -196,10 +203,9 @@ def set_multiple_status(names, status):
|
||||
task.save()
|
||||
|
||||
def set_tasks_as_overdue():
|
||||
frappe.db.sql("""update tabTask set `status`='Overdue'
|
||||
where exp_end_date is not null
|
||||
and exp_end_date < CURDATE()
|
||||
and `status` not in ('Completed', 'Cancelled')""")
|
||||
tasks = frappe.get_all("Task", filters={'status':['not in',['Cancelled', 'Completed']]})
|
||||
for task in tasks:
|
||||
frappe.get_doc("Task", task.name).update_status()
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_children(doctype, parent, task=None, project=None, is_root=False):
|
||||
|
@ -10,8 +10,8 @@ frappe.ui.form.on("Timesheet", {
|
||||
filters:{
|
||||
'status': 'Active'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
frm.fields_dict['time_logs'].grid.get_field('task').get_query = function(frm, cdt, cdn) {
|
||||
var child = locals[cdt][cdn];
|
||||
@ -20,22 +20,26 @@ frappe.ui.form.on("Timesheet", {
|
||||
'project': child.project,
|
||||
'status': ["!=", "Cancelled"]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
frm.fields_dict['time_logs'].grid.get_field('project').get_query = function() {
|
||||
return{
|
||||
filters: {
|
||||
'company': frm.doc.company
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
},
|
||||
|
||||
onload: function(frm){
|
||||
if (frm.doc.__islocal && frm.doc.time_logs) {
|
||||
calculate_time_and_amount(frm);
|
||||
}
|
||||
|
||||
if (frm.is_new()) {
|
||||
set_employee_and_company(frm);
|
||||
}
|
||||
},
|
||||
|
||||
refresh: function(frm) {
|
||||
@ -58,7 +62,7 @@ frappe.ui.form.on("Timesheet", {
|
||||
if ((row.from_time <= frappe.datetime.now_datetime()) && !row.completed) {
|
||||
button = 'Resume Timer';
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
frm.add_custom_button(__(button), function() {
|
||||
var flag = true;
|
||||
@ -77,7 +81,7 @@ frappe.ui.form.on("Timesheet", {
|
||||
erpnext.timesheet.timer(frm, row, timestamp);
|
||||
flag = false;
|
||||
}
|
||||
})
|
||||
});
|
||||
// If no activities found to start a timer, create new
|
||||
if (flag) {
|
||||
erpnext.timesheet.timer(frm);
|
||||
@ -125,8 +129,8 @@ frappe.ui.form.on("Timesheet", {
|
||||
frappe.set_route("Form", r.message.doctype, r.message.name);
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
dialog.show();
|
||||
},
|
||||
|
||||
@ -136,7 +140,7 @@ frappe.ui.form.on("Timesheet", {
|
||||
frm: frm
|
||||
});
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
frappe.ui.form.on("Timesheet Detail", {
|
||||
time_logs_remove: function(frm) {
|
||||
@ -171,22 +175,22 @@ frappe.ui.form.on("Timesheet Detail", {
|
||||
.find('[data-fieldname="timer"]')
|
||||
.append(frappe.render_template("timesheet"));
|
||||
frm.trigger("control_timer");
|
||||
})
|
||||
});
|
||||
},
|
||||
hours: function(frm, cdt, cdn) {
|
||||
calculate_end_time(frm, cdt, cdn)
|
||||
calculate_end_time(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
billing_hours: function(frm, cdt, cdn) {
|
||||
calculate_billing_costing_amount(frm, cdt, cdn)
|
||||
calculate_billing_costing_amount(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
billing_rate: function(frm, cdt, cdn) {
|
||||
calculate_billing_costing_amount(frm, cdt, cdn)
|
||||
calculate_billing_costing_amount(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
costing_rate: function(frm, cdt, cdn) {
|
||||
calculate_billing_costing_amount(frm, cdt, cdn)
|
||||
calculate_billing_costing_amount(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
billable: function(frm, cdt, cdn) {
|
||||
@ -212,7 +216,7 @@ frappe.ui.form.on("Timesheet Detail", {
|
||||
calculate_billing_costing_amount(frm, cdt, cdn);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@ -244,19 +248,19 @@ var calculate_end_time = function(frm, cdt, cdn) {
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var update_billing_hours = function(frm, cdt, cdn){
|
||||
var child = locals[cdt][cdn];
|
||||
if(!child.billable) frappe.model.set_value(cdt, cdn, 'billing_hours', 0.0);
|
||||
}
|
||||
};
|
||||
|
||||
var update_time_rates = function(frm, cdt, cdn){
|
||||
var child = locals[cdt][cdn];
|
||||
if(!child.billable){
|
||||
frappe.model.set_value(cdt, cdn, 'billing_rate', 0.0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var calculate_billing_costing_amount = function(frm, cdt, cdn){
|
||||
var child = locals[cdt][cdn];
|
||||
@ -270,7 +274,7 @@ var calculate_billing_costing_amount = function(frm, cdt, cdn){
|
||||
frappe.model.set_value(cdt, cdn, 'billing_amount', billing_amount);
|
||||
frappe.model.set_value(cdt, cdn, 'costing_amount', costing_amount);
|
||||
calculate_time_and_amount(frm);
|
||||
}
|
||||
};
|
||||
|
||||
var calculate_time_and_amount = function(frm) {
|
||||
var tl = frm.doc.time_logs || [];
|
||||
@ -294,4 +298,17 @@ var calculate_time_and_amount = function(frm) {
|
||||
frm.set_value("total_hours", total_working_hr);
|
||||
frm.set_value("total_billable_amount", total_billable_amount);
|
||||
frm.set_value("total_costing_amount", total_costing_amount);
|
||||
};
|
||||
|
||||
// set employee (and company) to the one that's currently logged in
|
||||
const set_employee_and_company = function(frm) {
|
||||
const options = { user_id: frappe.session.user };
|
||||
const fields = ['name', 'company'];
|
||||
frappe.db.get_value('Employee', options, fields).then(({ message }) => {
|
||||
if (message) {
|
||||
// there is an employee with the currently logged in user_id
|
||||
frm.set_value("employee", message.name);
|
||||
frm.set_value("company", message.company);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
1
erpnext/public/.gitignore
vendored
Normal file
1
erpnext/public/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
node_modules
|
@ -158,6 +158,12 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
if(frappe.meta.get_docfield(this.frm.doc.doctype, "pricing_rules")) {
|
||||
this.frm.set_indicator_formatter('pricing_rule', function(doc) {
|
||||
return (doc.rule_applied) ? "green" : "red";
|
||||
});
|
||||
}
|
||||
},
|
||||
onload: function() {
|
||||
var me = this;
|
||||
@ -422,6 +428,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
method: "erpnext.stock.get_item_details.get_item_details",
|
||||
child: item,
|
||||
args: {
|
||||
doc: me.frm.doc,
|
||||
args: {
|
||||
item_code: item.item_code,
|
||||
barcode: item.barcode,
|
||||
@ -456,7 +463,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
cost_center: item.cost_center,
|
||||
tax_category: me.frm.doc.tax_category,
|
||||
item_tax_template: item.item_tax_template,
|
||||
child_docname: item.name
|
||||
child_docname: item.name,
|
||||
}
|
||||
},
|
||||
|
||||
@ -482,7 +489,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
}
|
||||
},
|
||||
() => me.conversion_factor(doc, cdt, cdn, true),
|
||||
() => me.update_free_items(item)
|
||||
() => me.validate_pricing_rule(item)
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -1116,7 +1123,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
callback: function(r) {
|
||||
if (!r.exc && r.message) {
|
||||
r.message.forEach(row_item => {
|
||||
me.update_free_items(row_item);
|
||||
me.validate_pricing_rule(row_item);
|
||||
});
|
||||
me._set_values_for_item_list(r.message);
|
||||
me.calculate_taxes_and_totals();
|
||||
@ -1139,14 +1146,12 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
|
||||
return this.frm.call({
|
||||
method: "erpnext.accounts.doctype.pricing_rule.pricing_rule.apply_pricing_rule",
|
||||
args: { args: args },
|
||||
args: { args: args, doc: me.frm.doc },
|
||||
callback: function(r) {
|
||||
if (!r.exc && r.message) {
|
||||
me._set_values_for_item_list(r.message);
|
||||
if(item) me.set_gross_profit(item);
|
||||
if(calculate_taxes_and_totals) me.calculate_taxes_and_totals();
|
||||
if(me.frm.doc.apply_discount_on) me.frm.trigger("apply_discount_on")
|
||||
me.update_free_items(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1200,7 +1205,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
"warehouse": d.warehouse,
|
||||
"serial_no": d.serial_no,
|
||||
"price_list_rate": d.price_list_rate,
|
||||
"discount_percentage": d.discount_percentage || 0.0,
|
||||
"conversion_factor": d.conversion_factor || 1.0
|
||||
});
|
||||
|
||||
@ -1241,6 +1245,8 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
// if pricing rule set as blank from an existing value, apply price_list
|
||||
if(!me.frm.doc.ignore_pricing_rule && existing_pricing_rule && !d.pricing_rules) {
|
||||
me.apply_price_list(frappe.get_doc(d.doctype, d.name));
|
||||
} else {
|
||||
me.validate_pricing_rule(frappe.get_doc(d.doctype, d.name));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1288,41 +1294,29 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
});
|
||||
},
|
||||
|
||||
update_free_items: function(item) {
|
||||
var me = this;
|
||||
validate_pricing_rule: function(item) {
|
||||
let me = this;
|
||||
const fields = ["discount_percentage", "discount_amount", "pricing_rules"];
|
||||
|
||||
if (item.pricing_rules) {
|
||||
frappe.call({
|
||||
method: "erpnext.accounts.doctype.pricing_rule.pricing_rule.get_free_items",
|
||||
method: "erpnext.accounts.doctype.pricing_rule.utils.validate_pricing_rule_for_different_cond",
|
||||
args: {
|
||||
pricing_rules: item.pricing_rules,
|
||||
item_row: item
|
||||
doc: me.frm.doc
|
||||
},
|
||||
callback: function(r) {
|
||||
let items = [];
|
||||
let child = '';
|
||||
|
||||
me.frm.doc.items.map(d => {
|
||||
items[d.item_code] = d;
|
||||
if (r.message) {
|
||||
r.message.items.forEach(d => {
|
||||
me.frm.doc.items.forEach(row => {
|
||||
if(d.name == row.name) {
|
||||
fields.forEach(f => {
|
||||
row[f] = d[f];
|
||||
});
|
||||
|
||||
if(r.message && r.message.length) {
|
||||
r.message.forEach(d => {
|
||||
// If free item is already exists
|
||||
|
||||
if(d.item_code in items &&
|
||||
d.is_free_item && items[d.item_code].is_free_item) {
|
||||
child = items[d.item_code];
|
||||
} else {
|
||||
child = frappe.model.add_child(me.frm.doc, item.doctype, "items");
|
||||
}
|
||||
|
||||
$.each(d, function(k, v) {
|
||||
child[k] = v;
|
||||
});
|
||||
});
|
||||
|
||||
me.frm.script_manager.trigger("price_list_rate", child.doctype, child.name);
|
||||
});
|
||||
me.trigger_price_list_rate();
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1337,7 +1331,27 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
|
||||
me.frm.doc.items = items;
|
||||
refresh_field('items');
|
||||
} else if(item.applied_on_items && item.apply_on) {
|
||||
const applied_on_items = item.applied_on_items.split(',');
|
||||
me.frm.doc.items.forEach(row => {
|
||||
if(applied_on_items.includes(row[item.apply_on])) {
|
||||
fields.forEach(f => {
|
||||
row[f] = 0;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
me.trigger_price_list_rate();
|
||||
}
|
||||
},
|
||||
|
||||
trigger_price_list_rate: function() {
|
||||
var me = this;
|
||||
|
||||
this.frm.doc.items.forEach(child_row => {
|
||||
me.frm.script_manager.trigger("price_list_rate",
|
||||
child_row.doctype, child_row.name);
|
||||
})
|
||||
},
|
||||
|
||||
validate_company_and_party: function() {
|
||||
@ -1379,7 +1393,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
},
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
me.frm.set_value("taxes", r.message);
|
||||
for (let tax of r.message) {
|
||||
me.frm.add_child("taxes", tax);
|
||||
}
|
||||
me.calculate_taxes_and_totals();
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@
|
||||
<base-image :src="image" :alt="title" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-8" style='padding-left: 30px;'>
|
||||
<h2>{{ title }}</h2>
|
||||
<div class="text-muted">
|
||||
<slot name="detail-header-item"></slot>
|
||||
|
@ -1 +0,0 @@
|
||||
/Users/netchampfaris/frappe-bench/apps/erpnext/node_modules
|
@ -5,6 +5,7 @@ from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
from frappe.utils import getdate
|
||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
@ -12,10 +13,27 @@ import json
|
||||
|
||||
class TestGSTR3BReport(unittest.TestCase):
|
||||
def test_gstr_3b_report(self):
|
||||
|
||||
month_number_mapping = {
|
||||
1: "January",
|
||||
2: "February",
|
||||
3: "March",
|
||||
4: "April",
|
||||
5: "May",
|
||||
6: "June",
|
||||
7: "July",
|
||||
8: "August",
|
||||
9: "September",
|
||||
10: "October",
|
||||
11: "November",
|
||||
12: "December"
|
||||
}
|
||||
|
||||
frappe.set_user("Administrator")
|
||||
|
||||
frappe.db.sql("delete from `tabSales Invoice` where company='_Test Company GST'")
|
||||
frappe.db.sql("delete from `tabPurchase Invoice` where company='_Test Company GST'")
|
||||
frappe.db.sql("delete from `tabGSTR 3B Report` where company='_Test Company GST'")
|
||||
|
||||
make_company()
|
||||
make_item("Milk", properties = {"is_nil_exempt": 1, "standard_rate": 0.000000})
|
||||
@ -33,8 +51,8 @@ class TestGSTR3BReport(unittest.TestCase):
|
||||
"doctype": "GSTR 3B Report",
|
||||
"company": "_Test Company GST",
|
||||
"company_address": "_Test Address-Billing",
|
||||
"year": "2019",
|
||||
"month": "March"
|
||||
"year": getdate().year,
|
||||
"month": month_number_mapping.get(getdate().month)
|
||||
}).insert()
|
||||
|
||||
output = json.loads(report.json_output)
|
||||
@ -55,7 +73,6 @@ def make_sales_invoice():
|
||||
income_account = 'Sales - _GST',
|
||||
expense_account = 'Cost of Goods Sold - _GST',
|
||||
cost_center = 'Main - _GST',
|
||||
posting_date = '2019-03-10',
|
||||
do_not_save=1
|
||||
)
|
||||
|
||||
@ -77,7 +94,6 @@ def make_sales_invoice():
|
||||
income_account = 'Sales - _GST',
|
||||
expense_account = 'Cost of Goods Sold - _GST',
|
||||
cost_center = 'Main - _GST',
|
||||
posting_date = '2019-03-10',
|
||||
do_not_save=1
|
||||
)
|
||||
|
||||
@ -99,7 +115,6 @@ def make_sales_invoice():
|
||||
income_account = 'Sales - _GST',
|
||||
expense_account = 'Cost of Goods Sold - _GST',
|
||||
cost_center = 'Main - _GST',
|
||||
posting_date = '2019-03-10',
|
||||
do_not_save=1
|
||||
)
|
||||
|
||||
@ -122,7 +137,6 @@ def make_sales_invoice():
|
||||
income_account = 'Sales - _GST',
|
||||
expense_account = 'Cost of Goods Sold - _GST',
|
||||
cost_center = 'Main - _GST',
|
||||
posting_date = '2019-03-10',
|
||||
do_not_save=1
|
||||
)
|
||||
si3.submit()
|
||||
@ -135,7 +149,6 @@ def create_purchase_invoices():
|
||||
currency = 'INR',
|
||||
warehouse = 'Finished Goods - _GST',
|
||||
cost_center = 'Main - _GST',
|
||||
posting_date = '2019-03-10',
|
||||
do_not_save=1,
|
||||
)
|
||||
|
||||
@ -157,7 +170,6 @@ def create_purchase_invoices():
|
||||
currency = 'INR',
|
||||
warehouse = 'Finished Goods - _GST',
|
||||
cost_center = 'Main - _GST',
|
||||
posting_date = '2019-03-10',
|
||||
item = "Milk",
|
||||
do_not_save=1
|
||||
)
|
||||
|
@ -265,6 +265,7 @@ def make_custom_fields(update=True):
|
||||
'Purchase Order Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
||||
'Purchase Receipt Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
||||
'Purchase Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
||||
'Material Request Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
||||
'Employee': [
|
||||
dict(fieldname='ifsc_code', label='IFSC Code',
|
||||
fieldtype='Data', insert_after='bank_ac_no', print_hide=1,
|
||||
|
@ -94,14 +94,13 @@
|
||||
<Nome>{{ doc.customer_data.first_name }}</Nome>
|
||||
<Cognome>{{ doc.customer_data.last_name }}</Cognome>
|
||||
</Anagrafica>
|
||||
{%- else %}
|
||||
{%- if doc.customer_data.is_public_administration %}
|
||||
<CodiceFiscale>{{ doc.customer_data.fiscal_code }}</CodiceFiscale>
|
||||
{%- else %}
|
||||
<IdFiscaleIVA>
|
||||
<IdPaese>{{ doc.customer_address_data.country_code }}</IdPaese>
|
||||
<IdCodice>{{ doc.tax_id | replace("IT","") }}</IdCodice>
|
||||
</IdFiscaleIVA>
|
||||
{%- if doc.customer_data.fiscal_code %}
|
||||
<CodiceFiscale>{{ doc.customer_data.fiscal_code }}</CodiceFiscale>
|
||||
{%- endif %}
|
||||
<Anagrafica>
|
||||
<Denominazione>{{ doc.customer_name }}</Denominazione>
|
||||
@ -128,22 +127,42 @@
|
||||
<ImportoBollo>{{ format_float(doc.stamp_duty) }}</ImportoBollo>
|
||||
</DatiBollo>
|
||||
{%- endif %}
|
||||
<ImportoTotaleDocumento>{{ format_float(doc.grand_total) }}</ImportoTotaleDocumento>
|
||||
{%- if doc.discount_amount %}
|
||||
<ScontoMaggiorazione>
|
||||
{%- if doc.discount_amount > 0.0 %}
|
||||
<Tipo>SC</Tipo>
|
||||
{%- else %}
|
||||
<Tipo>MG</Tipo>
|
||||
{%- endif %}
|
||||
{%- if doc.additional_discount_percentage > 0.0 %}
|
||||
<Percentuale>{{ format_float(doc.additional_discount_percentage) }}</Percentuale>
|
||||
{%- endif %}
|
||||
<Importo>{{ format_float(doc.discount_amount) }}</Importo>
|
||||
</ScontoMaggiorazione>
|
||||
{%- endif %}
|
||||
<ImportoTotaleDocumento>{{ format_float(doc.rounded_total or doc.grand_total) }}</ImportoTotaleDocumento>
|
||||
<Causale>VENDITA</Causale>
|
||||
</DatiGeneraliDocumento>
|
||||
{%- if doc.po_no %}
|
||||
{%- for po_no, po_date in doc.customer_po_data.items() %}
|
||||
<DatiOrdineAcquisto>
|
||||
<IdDocumento>{{ doc.po_no }}</IdDocumento>
|
||||
{%- if doc.po_date %}
|
||||
<Data>{{ doc.po_date }}</Data>
|
||||
{%- endif %}
|
||||
<IdDocumento>{{ po_no }}</IdDocumento>
|
||||
<Data>{{ po_date }}</Data>
|
||||
</DatiOrdineAcquisto>
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
{%- if doc.is_return and doc.return_against_unamended %}
|
||||
<DatiFattureCollegate>
|
||||
<IdDocumento>{{ doc.return_against_unamended }}</IdDocumento>
|
||||
</DatiFattureCollegate>
|
||||
{%- endif %}
|
||||
{%- for row in doc.e_invoice_items %}
|
||||
{%- if row.delivery_note %}
|
||||
<DatiDDT>
|
||||
<NumeroDDT>{{ row.delivery_note }}</NumeroDDT>
|
||||
<DataDDT>{{ frappe.db.get_value('Delivery Note', row.delivery_note, 'posting_date') }}</DataDDT>
|
||||
<RiferimentoNumeroLinea>{{ row.idx }}</RiferimentoNumeroLinea>
|
||||
</DatiDDT>
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
{%- if doc.shipping_address_data %}
|
||||
<DatiTrasporto>
|
||||
<IndirizzoResa>
|
||||
@ -165,7 +184,11 @@
|
||||
<UnitaMisura>{{ item.stock_uom }}</UnitaMisura>
|
||||
<PrezzoUnitario>{{ format_float(item.price_list_rate or item.rate) }}</PrezzoUnitario>
|
||||
{{ render_discount_or_margin(item) }}
|
||||
{%- if (item.discount_amount or item.rate_with_margin) %}
|
||||
<PrezzoTotale>{{ format_float(item.net_amount) }}</PrezzoTotale>
|
||||
{%- else %}
|
||||
<PrezzoTotale>{{ format_float(item.amount) }}</PrezzoTotale>
|
||||
{%- endif %}
|
||||
<AliquotaIVA>{{ format_float(item.tax_rate) }}</AliquotaIVA>
|
||||
{%- if item.tax_exemption_reason %}
|
||||
<Natura>{{ item.tax_exemption_reason.split("-")[0] }}</Natura>
|
||||
@ -199,7 +222,9 @@
|
||||
<ModalitaPagamento>{{ payment_term.mode_of_payment_code.split("-")[0] }}</ModalitaPagamento>
|
||||
<DataScadenzaPagamento>{{ payment_term.due_date }}</DataScadenzaPagamento>
|
||||
<ImportoPagamento>{{ format_float(payment_term.payment_amount) }}</ImportoPagamento>
|
||||
{%- if payment_term.bank_account_name %}
|
||||
<IstitutoFinanziario>{{ payment_term.bank_account_name }}</IstitutoFinanziario>
|
||||
{%- endif %}
|
||||
{%- if payment_term.bank_account_iban %}
|
||||
<IBAN>{{ payment_term.bank_account_iban }}</IBAN>
|
||||
<ABI>{{ payment_term.bank_account_iban[5:10] }}</ABI>
|
||||
|
@ -3,15 +3,26 @@ erpnext.setup_e_invoice_button = (doctype) => {
|
||||
refresh: (frm) => {
|
||||
if(frm.doc.docstatus == 1) {
|
||||
frm.add_custom_button('Generate E-Invoice', () => {
|
||||
frm.call({
|
||||
method: "erpnext.regional.italy.utils.generate_single_invoice",
|
||||
args: {
|
||||
docname: frm.doc.name
|
||||
},
|
||||
callback: function(r) {
|
||||
frm.reload_doc();
|
||||
if(r.message) {
|
||||
var w = window.open(
|
||||
frappe.urllib.get_full_url(
|
||||
"/api/method/erpnext.regional.italy.utils.generate_single_invoice?"
|
||||
+ "docname=" + frm.doc.name
|
||||
"/api/method/erpnext.regional.italy.utils.download_e_invoice_file?"
|
||||
+ "file_name=" + r.message
|
||||
)
|
||||
)
|
||||
if (!w) {
|
||||
frappe.msgprint(__("Please enable pop-ups")); return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,22 @@ def make_custom_fields(update=True):
|
||||
print_hide=1, hidden=1, read_only=1, options="currency")
|
||||
]
|
||||
|
||||
customer_po_fields = [
|
||||
dict(fieldname='customer_po_details', label='Customer PO',
|
||||
fieldtype='Section Break', insert_after='image'),
|
||||
dict(fieldname='customer_po_no', label='Customer PO No',
|
||||
fieldtype='Data', insert_after='customer_po_details',
|
||||
fetch_from = 'sales_order.po_no',
|
||||
print_hide=1, allow_on_submit=1, fetch_if_empty= 1, read_only=1, no_copy=1),
|
||||
dict(fieldname='customer_po_clm_brk', label='',
|
||||
fieldtype='Column Break', insert_after='customer_po_no',
|
||||
print_hide=1, read_only=1),
|
||||
dict(fieldname='customer_po_date', label='Customer PO Date',
|
||||
fieldtype='Date', insert_after='customer_po_clm_brk',
|
||||
fetch_from = 'sales_order.po_date',
|
||||
print_hide=1, allow_on_submit=1, fetch_if_empty= 1, read_only=1, no_copy=1)
|
||||
]
|
||||
|
||||
custom_fields = {
|
||||
'Company': [
|
||||
dict(fieldname='sb_e_invoicing', label='E-Invoicing',
|
||||
@ -128,7 +144,7 @@ def make_custom_fields(update=True):
|
||||
'Purchase Invoice Item': invoice_item_fields,
|
||||
'Sales Order Item': invoice_item_fields,
|
||||
'Delivery Note Item': invoice_item_fields,
|
||||
'Sales Invoice Item': invoice_item_fields,
|
||||
'Sales Invoice Item': invoice_item_fields + customer_po_fields,
|
||||
'Quotation Item': invoice_item_fields,
|
||||
'Purchase Order Item': invoice_item_fields,
|
||||
'Purchase Receipt Item': invoice_item_fields,
|
||||
|
@ -5,6 +5,7 @@ from frappe.utils import flt, cstr
|
||||
from erpnext.controllers.taxes_and_totals import get_itemised_tax
|
||||
from frappe import _
|
||||
from frappe.core.doctype.file.file import remove_file
|
||||
from six import string_types
|
||||
from frappe.desk.form.load import get_attachments
|
||||
from erpnext.regional.italy import state_codes
|
||||
|
||||
@ -82,6 +83,14 @@ def prepare_invoice(invoice, progressive_number):
|
||||
if item.tax_rate == 0.0 and item.tax_amount == 0.0:
|
||||
item.tax_exemption_reason = tax_data["0.0"]["tax_exemption_reason"]
|
||||
|
||||
customer_po_data = {}
|
||||
for d in invoice.e_invoice_items:
|
||||
if (d.customer_po_no and d.customer_po_date
|
||||
and d.customer_po_no not in customer_po_data):
|
||||
customer_po_data[d.customer_po_no] = d.customer_po_date
|
||||
|
||||
invoice.customer_po_data = customer_po_data
|
||||
|
||||
return invoice
|
||||
|
||||
def get_conditions(filters):
|
||||
@ -134,6 +143,7 @@ def get_invoice_summary(items, taxes):
|
||||
idx=len(items)+1,
|
||||
item_code=reference_row.description,
|
||||
item_name=reference_row.description,
|
||||
description=reference_row.description,
|
||||
rate=reference_row.tax_amount,
|
||||
qty=1.0,
|
||||
amount=reference_row.tax_amount,
|
||||
@ -142,7 +152,7 @@ def get_invoice_summary(items, taxes):
|
||||
tax_amount=(reference_row.tax_amount * tax.rate) / 100,
|
||||
net_amount=reference_row.tax_amount,
|
||||
taxable_amount=reference_row.tax_amount,
|
||||
item_tax_rate="{}",
|
||||
item_tax_rate={tax.account_head: tax.rate},
|
||||
charges=True
|
||||
)
|
||||
)
|
||||
@ -150,10 +160,16 @@ def get_invoice_summary(items, taxes):
|
||||
#Check item tax rates if tax rate is zero.
|
||||
if tax.rate == 0:
|
||||
for item in items:
|
||||
item_tax_rate = item.item_tax_rate
|
||||
if isinstance(item.item_tax_rate, string_types):
|
||||
item_tax_rate = json.loads(item.item_tax_rate)
|
||||
if tax.account_head in item_tax_rate:
|
||||
|
||||
if item_tax_rate and tax.account_head in item_tax_rate:
|
||||
key = cstr(item_tax_rate[tax.account_head])
|
||||
summary_data.setdefault(key, {"tax_amount": 0.0, "taxable_amount": 0.0, "tax_exemption_reason": "", "tax_exemption_law": ""})
|
||||
if key not in summary_data:
|
||||
summary_data.setdefault(key, {"tax_amount": 0.0, "taxable_amount": 0.0,
|
||||
"tax_exemption_reason": "", "tax_exemption_law": ""})
|
||||
|
||||
summary_data[key]["tax_amount"] += item.tax_amount
|
||||
summary_data[key]["taxable_amount"] += item.net_amount
|
||||
if key == "0.0":
|
||||
@ -198,19 +214,25 @@ def sales_invoice_validate(doc):
|
||||
else:
|
||||
doc.company_fiscal_regime = company_fiscal_regime
|
||||
|
||||
doc.company_tax_id = frappe.get_cached_value("Company", doc.company, 'tax_id')
|
||||
doc.company_fiscal_code = frappe.get_cached_value("Company", doc.company, 'fiscal_code')
|
||||
if not doc.company_tax_id and not doc.company_fiscal_code:
|
||||
frappe.throw(_("Please set either the Tax ID or Fiscal Code on Company '%s'" % doc.company), title=_("E-Invoicing Information Missing"))
|
||||
|
||||
#Validate customer details
|
||||
customer_type, is_public_administration = frappe.db.get_value("Customer", doc.customer, ["customer_type", "is_public_administration"])
|
||||
if customer_type == _("Individual"):
|
||||
customer = frappe.get_doc("Customer", doc.customer)
|
||||
|
||||
if customer.customer_type == _("Individual"):
|
||||
doc.customer_fiscal_code = customer.fiscal_code
|
||||
if not doc.customer_fiscal_code:
|
||||
frappe.throw(_("Please set Fiscal Code for the customer '%s'" % doc.customer), title=_("E-Invoicing Information Missing"))
|
||||
else:
|
||||
if is_public_administration:
|
||||
if customer.is_public_administration:
|
||||
doc.customer_fiscal_code = customer.fiscal_code
|
||||
if not doc.customer_fiscal_code:
|
||||
frappe.throw(_("Please set Fiscal Code for the public administration '%s'" % doc.customer), title=_("E-Invoicing Information Missing"))
|
||||
else:
|
||||
doc.tax_id = customer.tax_id
|
||||
if not doc.tax_id:
|
||||
frappe.throw(_("Please set Tax ID for the customer '%s'" % doc.customer), title=_("E-Invoicing Information Missing"))
|
||||
|
||||
@ -276,13 +298,18 @@ def prepare_and_attach_invoice(doc, replace=False):
|
||||
def generate_single_invoice(docname):
|
||||
doc = frappe.get_doc("Sales Invoice", docname)
|
||||
|
||||
|
||||
e_invoice = prepare_and_attach_invoice(doc, True)
|
||||
|
||||
return e_invoice.file_name
|
||||
|
||||
@frappe.whitelist()
|
||||
def download_e_invoice_file(file_name):
|
||||
content = None
|
||||
with open(frappe.get_site_path('private', 'files', e_invoice.file_name), "r") as f:
|
||||
with open(frappe.get_site_path('private', 'files', file_name), "r") as f:
|
||||
content = f.read()
|
||||
|
||||
frappe.local.response.filename = e_invoice.file_name
|
||||
frappe.local.response.filename = file_name
|
||||
frappe.local.response.filecontent = content
|
||||
frappe.local.response.type = "download"
|
||||
|
||||
|
@ -49,5 +49,20 @@ frappe.query_reports["GSTR-1"] = {
|
||||
"options": ["B2B", "B2C Large", "B2C Small", "CDNR", "EXPORT"],
|
||||
"default": "B2B"
|
||||
}
|
||||
]
|
||||
],
|
||||
onload: function (report) {
|
||||
|
||||
report.page.add_inner_button(__("Download as Json"), function () {
|
||||
var filters = report.get_values();
|
||||
|
||||
const args = {
|
||||
cmd: 'erpnext.regional.report.gstr_1.gstr_1.get_json',
|
||||
data: report.data,
|
||||
report_name: report.report_name,
|
||||
filters: filters
|
||||
};
|
||||
|
||||
open_url_post(frappe.request.url, args);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,10 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe, json
|
||||
from frappe import _
|
||||
from frappe.utils import flt, formatdate
|
||||
from frappe.utils import flt, formatdate, now_datetime, getdate
|
||||
from datetime import date
|
||||
from six import iteritems
|
||||
from erpnext.regional.doctype.gstr_3b_report.gstr_3b_report import get_period
|
||||
|
||||
def execute(filters=None):
|
||||
return Gstr1Report(filters).run()
|
||||
@ -38,7 +39,7 @@ class Gstr1Report(object):
|
||||
shipping_bill_date,
|
||||
reason_for_issuing_document
|
||||
"""
|
||||
self.customer_type = "Company" if self.filters.get("type_of_business") == "B2B" else "Individual"
|
||||
# self.customer_type = "Company" if self.filters.get("type_of_business") == "B2B" else "Individual"
|
||||
|
||||
def run(self):
|
||||
self.get_columns()
|
||||
@ -113,9 +114,14 @@ class Gstr1Report(object):
|
||||
if self.filters.get(opts[0]):
|
||||
conditions += opts[1]
|
||||
|
||||
customers = frappe.get_all("Customer", filters={"customer_type": self.customer_type})
|
||||
# customers = frappe.get_all("Customer", filters={"customer_type": self.customer_type})
|
||||
|
||||
if self.filters.get("type_of_business") == "B2B":
|
||||
customers = frappe.get_all("Customer",
|
||||
filters={
|
||||
"gst_category": ["in", ["Registered Regular", "Deemed Export", "SEZ"]]
|
||||
})
|
||||
|
||||
conditions += """ and ifnull(gst_category, '') != 'Overseas' and is_return != 1
|
||||
and customer in ({0})""".format(", ".join([frappe.db.escape(c.name) for c in customers]))
|
||||
|
||||
@ -124,6 +130,11 @@ class Gstr1Report(object):
|
||||
if not b2c_limit:
|
||||
frappe.throw(_("Please set B2C Limit in GST Settings."))
|
||||
|
||||
customers = frappe.get_all("Customer",
|
||||
filters={
|
||||
"gst_category": ["in", ["Unregistered"]]
|
||||
})
|
||||
|
||||
if self.filters.get("type_of_business") == "B2C Large":
|
||||
conditions += """ and SUBSTR(place_of_supply, 1, 2) != SUBSTR(company_gstin, 1, 2)
|
||||
and grand_total > {0} and is_return != 1 and customer in ({1})""".\
|
||||
@ -494,3 +505,158 @@ class Gstr1Report(object):
|
||||
}
|
||||
]
|
||||
self.columns = self.invoice_columns + self.tax_columns + self.other_columns
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_json():
|
||||
data = frappe._dict(frappe.local.form_dict)
|
||||
|
||||
del data["cmd"]
|
||||
if "csrf_token" in data:
|
||||
del data["csrf_token"]
|
||||
|
||||
filters = json.loads(data["filters"])
|
||||
report_data = json.loads(data["data"])
|
||||
report_name = data["report_name"]
|
||||
gstin = get_company_gstin_number(filters["company"])
|
||||
|
||||
fp = "%02d%s" % (getdate(filters["to_date"]).month, getdate(filters["to_date"]).year)
|
||||
|
||||
gst_json = {"gstin": "", "version": "GST2.2.9",
|
||||
"hash": "hash", "gstin": gstin, "fp": fp}
|
||||
|
||||
res = {}
|
||||
if filters["type_of_business"] == "B2B":
|
||||
for item in report_data:
|
||||
res.setdefault(item["customer_gstin"], {}).setdefault(item["invoice_number"],[]).append(item)
|
||||
|
||||
out = get_b2b_json(res, gstin)
|
||||
gst_json["b2b"] = out
|
||||
elif filters["type_of_business"] == "B2C Large":
|
||||
for item in report_data:
|
||||
res.setdefault(item["place_of_supply"], []).append(item)
|
||||
|
||||
out = get_b2cl_json(res, gstin)
|
||||
gst_json["b2cl"] = out
|
||||
elif filters["type_of_business"] == "EXPORT":
|
||||
for item in report_data:
|
||||
res.setdefault(item["export_type"], []).append(item)
|
||||
|
||||
out = get_export_json(res)
|
||||
gst_json["exp"] = out
|
||||
|
||||
download_json_file(report_name, filters["type_of_business"], gst_json)
|
||||
|
||||
def get_b2b_json(res, gstin):
|
||||
inv_type, out = {"Registered Regular": "R", "Deemed Export": "DE", "URD": "URD", "SEZ": "SEZ"}, []
|
||||
for gst_in in res:
|
||||
b2b_item, inv = {"ctin": gst_in, "inv": []}, []
|
||||
if not gst_in: continue
|
||||
|
||||
for number, invoice in iteritems(res[gst_in]):
|
||||
inv_item = get_basic_invoice_detail(invoice[0])
|
||||
inv_item["pos"] = "%02d" % int(invoice[0]["place_of_supply"].split('-')[0])
|
||||
inv_item["rchrg"] = invoice[0]["reverse_charge"]
|
||||
inv_item["inv_typ"] = inv_type.get(invoice[0].get("gst_category", ""),"")
|
||||
|
||||
if inv_item["pos"]=="00": continue
|
||||
inv_item["itms"] = []
|
||||
|
||||
for item in invoice:
|
||||
inv_item["itms"].append(get_rate_and_tax_details(item, gstin))
|
||||
|
||||
inv.append(inv_item)
|
||||
|
||||
if not inv: continue
|
||||
b2b_item["inv"] = inv
|
||||
out.append(b2b_item)
|
||||
|
||||
return out
|
||||
|
||||
def get_b2cl_json(res, gstin):
|
||||
out = []
|
||||
for pos in res:
|
||||
b2cl_item, inv = {"pos": "%02d" % int(pos.split('-')[0]), "inv": []}, []
|
||||
|
||||
for row in res[pos]:
|
||||
inv_item = get_basic_invoice_detail(row)
|
||||
if row.get("sale_from_bonded_wh"):
|
||||
inv_item["inv_typ"] = "CBW"
|
||||
|
||||
inv_item["itms"] = [get_rate_and_tax_details(row, gstin)]
|
||||
|
||||
inv.append(inv_item)
|
||||
|
||||
b2cl_item["inv"] = inv
|
||||
out.append(b2cl_item)
|
||||
|
||||
return out
|
||||
|
||||
def get_export_json(res):
|
||||
out = []
|
||||
for exp_type in res:
|
||||
exp_item, inv = {"exp_typ": exp_type, "inv": []}, []
|
||||
|
||||
for row in res[exp_type]:
|
||||
inv_item = get_basic_invoice_detail(row)
|
||||
inv_item["itms"] = [{
|
||||
"txval": flt(row["taxable_value"], 2),
|
||||
"rt": row["rate"] or 0,
|
||||
"iamt": 0,
|
||||
"csamt": 0
|
||||
}]
|
||||
|
||||
inv.append(inv_item)
|
||||
|
||||
exp_item["inv"] = inv
|
||||
out.append(exp_item)
|
||||
|
||||
return out
|
||||
|
||||
def get_basic_invoice_detail(row):
|
||||
return {
|
||||
"inum": row["invoice_number"],
|
||||
"idt": getdate(row["posting_date"]).strftime('%d-%m-%Y'),
|
||||
"val": flt(row["invoice_value"], 2)
|
||||
}
|
||||
|
||||
def get_rate_and_tax_details(row, gstin):
|
||||
itm_det = {"txval": flt(row["taxable_value"], 2),
|
||||
"rt": row["rate"],
|
||||
"csamt": (flt(row.get("cess_amount"), 2) or 0)
|
||||
}
|
||||
|
||||
# calculate rate
|
||||
num = 1 if not row["rate"] else "%d%02d" % (row["rate"], 1)
|
||||
rate = row.get("rate") or 0
|
||||
|
||||
# calculate tax amount added
|
||||
tax = flt((row["taxable_value"]*rate)/100.0, 2)
|
||||
frappe.errprint([tax, tax/2])
|
||||
if row.get("customer_gstin") and gstin[0:2] == row["customer_gstin"][0:2]:
|
||||
itm_det.update({"camt": flt(tax/2.0, 2), "samt": flt(tax/2.0, 2)})
|
||||
else:
|
||||
itm_det.update({"iamt": tax})
|
||||
|
||||
return {"num": int(num), "itm_det": itm_det}
|
||||
|
||||
def get_company_gstin_number(company):
|
||||
filters = [
|
||||
["is_your_company_address", "=", 1],
|
||||
["Dynamic Link", "link_doctype", "=", "Company"],
|
||||
["Dynamic Link", "link_name", "=", company],
|
||||
["Dynamic Link", "parenttype", "=", "Address"],
|
||||
]
|
||||
|
||||
gstin = frappe.get_all("Address", filters=filters, fields=["gstin"])
|
||||
|
||||
if gstin:
|
||||
return gstin[0]["gstin"]
|
||||
else:
|
||||
frappe.throw(_("No GST No. found for the Company."))
|
||||
|
||||
def download_json_file(filename, report_type, data):
|
||||
''' download json content in a file '''
|
||||
frappe.response['filename'] = frappe.scrub("{0} {1}".format(filename, report_type)) + '.json'
|
||||
frappe.response['filecontent'] = json.dumps(data)
|
||||
frappe.response['content_type'] = 'application/json'
|
||||
frappe.response['type'] = 'download'
|
||||
|
@ -97,6 +97,8 @@ class Quotation(SellingController):
|
||||
self.update_lead()
|
||||
|
||||
def on_cancel(self):
|
||||
super(Quotation, self).on_cancel()
|
||||
|
||||
#update enquiry status
|
||||
self.set_status(update=True)
|
||||
self.update_opportunity()
|
||||
|
@ -183,6 +183,8 @@ class SalesOrder(SellingController):
|
||||
self.update_blanket_order()
|
||||
|
||||
def on_cancel(self):
|
||||
super(SalesOrder, self).on_cancel()
|
||||
|
||||
# Cannot cancel closed SO
|
||||
if self.status == 'Closed':
|
||||
frappe.throw(_("Closed order cannot be cancelled. Unclose to cancel."))
|
||||
|
@ -2,7 +2,7 @@
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.utils import flt, add_days
|
||||
from frappe.utils import flt, add_days, nowdate
|
||||
import frappe.permissions
|
||||
import unittest
|
||||
from erpnext.selling.doctype.sales_order.sales_order \
|
||||
@ -13,7 +13,6 @@ from erpnext.controllers.accounts_controller import update_child_qty_rate
|
||||
import json
|
||||
from erpnext.selling.doctype.sales_order.sales_order import make_raw_material_request
|
||||
|
||||
|
||||
class TestSalesOrder(unittest.TestCase):
|
||||
def tearDown(self):
|
||||
frappe.set_user("Administrator")
|
||||
@ -710,6 +709,28 @@ class TestSalesOrder(unittest.TestCase):
|
||||
se.cancel()
|
||||
self.assertFalse(frappe.db.exists("Serial No", {"sales_order": so.name}))
|
||||
|
||||
def test_advance_payment_entry_unlink_against_sales_order(self):
|
||||
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
|
||||
frappe.db.set_value("Accounts Settings", "Accounts Settings",
|
||||
"unlink_advance_payment_on_cancelation_of_order", 0)
|
||||
|
||||
so = make_sales_order()
|
||||
|
||||
pe = get_payment_entry("Sales Order", so.name, bank_account="_Test Bank - _TC")
|
||||
pe.reference_no = "1"
|
||||
pe.reference_date = nowdate()
|
||||
pe.paid_from_account_currency = so.currency
|
||||
pe.paid_to_account_currency = so.currency
|
||||
pe.source_exchange_rate = 1
|
||||
pe.target_exchange_rate = 1
|
||||
pe.paid_amount = so.grand_total
|
||||
pe.save(ignore_permissions=True)
|
||||
pe.submit()
|
||||
|
||||
so_doc = frappe.get_doc('Sales Order', so.name)
|
||||
|
||||
self.assertRaises(frappe.LinkExistsError, so_doc.cancel)
|
||||
|
||||
def test_request_for_raw_materials(self):
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
item = make_item("_Test Finished Item", {"is_stock_item": 1,
|
||||
|
@ -233,9 +233,21 @@ erpnext.pos.PointOfSale = class PointOfSale {
|
||||
} else {
|
||||
this.update_item_in_frm(item, field, value)
|
||||
.then(() => {
|
||||
frappe.dom.unfreeze();
|
||||
frappe.run_serially([
|
||||
() => {
|
||||
let items = this.frm.doc.items.map(item => item.name);
|
||||
if (items && items.length > 0 && items.includes(item.name)) {
|
||||
this.frm.doc.items.forEach(item_row => {
|
||||
// update cart
|
||||
this.update_cart_data(item);
|
||||
this.set_form_action();
|
||||
this.on_qty_change(item_row);
|
||||
});
|
||||
} else {
|
||||
this.on_qty_change(item);
|
||||
}
|
||||
},
|
||||
() => this.post_qty_change(item)
|
||||
]);
|
||||
});
|
||||
}
|
||||
return;
|
||||
@ -251,7 +263,28 @@ erpnext.pos.PointOfSale = class PointOfSale {
|
||||
frappe.flags.hide_serial_batch_dialog = true;
|
||||
|
||||
frappe.run_serially([
|
||||
() => this.frm.script_manager.trigger('item_code', item.doctype, item.name),
|
||||
() => {
|
||||
this.frm.script_manager.trigger('item_code', item.doctype, item.name)
|
||||
.then(() => {
|
||||
this.frm.script_manager.trigger('qty', item.doctype, item.name)
|
||||
.then(() => {
|
||||
frappe.run_serially([
|
||||
() => {
|
||||
let items = this.frm.doc.items.map(i => i.name);
|
||||
if (items && items.length > 0 && items.includes(item.name)) {
|
||||
this.frm.doc.items.forEach(item_row => {
|
||||
// update cart
|
||||
this.on_qty_change(item_row);
|
||||
});
|
||||
} else {
|
||||
this.on_qty_change(item);
|
||||
}
|
||||
},
|
||||
() => this.post_qty_change(item)
|
||||
]);
|
||||
});
|
||||
});
|
||||
},
|
||||
() => {
|
||||
const show_dialog = item.has_serial_no || item.has_batch_no;
|
||||
|
||||
@ -261,14 +294,25 @@ erpnext.pos.PointOfSale = class PointOfSale {
|
||||
(item.has_serial_no) || (item.actual_batch_qty != item.actual_qty)) ) {
|
||||
// check has serial no/batch no and update cart
|
||||
this.select_batch_and_serial_no(item);
|
||||
} else {
|
||||
// update cart
|
||||
this.update_cart_data(item);
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
on_qty_change(item) {
|
||||
frappe.run_serially([
|
||||
() => this.update_cart_data(item),
|
||||
]);
|
||||
}
|
||||
|
||||
post_qty_change(item) {
|
||||
this.cart.update_taxes_and_totals();
|
||||
this.cart.update_grand_total();
|
||||
this.cart.update_qty_total();
|
||||
this.cart.scroll_to_item(item.item_code);
|
||||
this.set_form_action();
|
||||
}
|
||||
|
||||
select_batch_and_serial_no(row) {
|
||||
frappe.dom.unfreeze();
|
||||
|
||||
@ -283,7 +327,8 @@ erpnext.pos.PointOfSale = class PointOfSale {
|
||||
frappe.model.clear_doc(item.doctype, item.name);
|
||||
}
|
||||
},
|
||||
() => this.update_cart_data(item)
|
||||
() => this.update_cart_data(item),
|
||||
() => this.post_qty_change(item)
|
||||
]);
|
||||
});
|
||||
})
|
||||
@ -300,9 +345,6 @@ erpnext.pos.PointOfSale = class PointOfSale {
|
||||
|
||||
update_cart_data(item) {
|
||||
this.cart.add_item(item);
|
||||
this.cart.update_taxes_and_totals();
|
||||
this.cart.update_grand_total();
|
||||
this.cart.update_qty_total();
|
||||
frappe.dom.unfreeze();
|
||||
}
|
||||
|
||||
@ -446,16 +488,15 @@ erpnext.pos.PointOfSale = class PointOfSale {
|
||||
}
|
||||
|
||||
setup_company() {
|
||||
this.company = frappe.sys_defaults.company;
|
||||
return new Promise(resolve => {
|
||||
if(!this.company) {
|
||||
if(!frappe.sys_defaults.company) {
|
||||
frappe.prompt({fieldname:"company", options: "Company", fieldtype:"Link",
|
||||
label: __("Select Company"), reqd: 1}, (data) => {
|
||||
this.company = data.company;
|
||||
resolve(this.company);
|
||||
}, __("Select Company"));
|
||||
} else {
|
||||
resolve(this.company);
|
||||
resolve();
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -509,7 +550,9 @@ erpnext.pos.PointOfSale = class PointOfSale {
|
||||
}
|
||||
|
||||
set_pos_profile_data() {
|
||||
if (this.company) {
|
||||
this.frm.doc.company = this.company;
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
return this.frm.call({
|
||||
@ -953,7 +996,6 @@ class POSCart {
|
||||
$item.appendTo(this.$cart_items);
|
||||
}
|
||||
this.highlight_item(item.item_code);
|
||||
this.scroll_to_item(item.item_code);
|
||||
}
|
||||
|
||||
update_item(item) {
|
||||
@ -1206,7 +1248,10 @@ class POSItems {
|
||||
clearTimeout(this.last_search);
|
||||
this.last_search = setTimeout(() => {
|
||||
const search_term = e.target.value;
|
||||
this.filter_items({ search_term });
|
||||
const item_group = this.item_group_field ?
|
||||
this.item_group_field.get_value() : '';
|
||||
|
||||
this.filter_items({ search_term:search_term, item_group: item_group});
|
||||
}, 300);
|
||||
});
|
||||
|
||||
|
@ -29,7 +29,7 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p
|
||||
batch_no = data.get("batch_no") if data.get("batch_no") else ""
|
||||
barcode = data.get("barcode") if data.get("barcode") else ""
|
||||
|
||||
item_code, condition = get_conditions(item_code, serial_no, batch_no, barcode)
|
||||
condition = get_conditions(item_code, serial_no, batch_no, barcode)
|
||||
|
||||
if pos_profile:
|
||||
condition += get_item_group_condition(pos_profile)
|
||||
@ -86,7 +86,6 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p
|
||||
and {condition} limit {start}, {page_length}""".format
|
||||
(start=start,page_length=page_length,lft=lft, rgt=rgt, condition=condition),
|
||||
{
|
||||
'item_code': item_code,
|
||||
'price_list': price_list,
|
||||
'warehouse': warehouse
|
||||
} , as_dict=1)
|
||||
@ -133,12 +132,10 @@ def search_serial_or_batch_or_barcode_number(search_value):
|
||||
|
||||
def get_conditions(item_code, serial_no, batch_no, barcode):
|
||||
if serial_no or batch_no or barcode:
|
||||
return frappe.db.escape(item_code), "i.name = %(item_code)s"
|
||||
return "i.name = {0}".format(frappe.db.escape(item_code))
|
||||
|
||||
condition = """(i.name like %(item_code)s
|
||||
or i.item_name like %(item_code)s)"""
|
||||
|
||||
return frappe.db.escape('%' + item_code + '%'), condition
|
||||
return """(i.name like {item_code}
|
||||
or i.item_name like {item_code})""".format(item_code = frappe.db.escape('%' + item_code + '%'))
|
||||
|
||||
def get_item_group_condition(pos_profile):
|
||||
cond = "and 1=1"
|
||||
|
@ -0,0 +1,211 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import flt
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
from erpnext.accounts.report.financial_statements import get_period_list
|
||||
from erpnext.accounts.doctype.monthly_distribution.monthly_distribution import get_periodwise_distribution_data
|
||||
|
||||
def get_data_column(filters, partner_doctype):
|
||||
data = []
|
||||
period_list = get_period_list(filters.fiscal_year, filters.fiscal_year,
|
||||
filters.period, company=filters.company)
|
||||
|
||||
rows = get_data(filters, period_list, partner_doctype)
|
||||
columns = get_columns(filters, period_list, partner_doctype)
|
||||
|
||||
if not rows:
|
||||
return columns, data
|
||||
|
||||
for key, value in rows.items():
|
||||
value.update({
|
||||
frappe.scrub(partner_doctype): key[0],
|
||||
'item_group': key[1]
|
||||
})
|
||||
|
||||
data.append(value)
|
||||
|
||||
return columns, data
|
||||
|
||||
def get_data(filters, period_list, partner_doctype):
|
||||
sales_field = frappe.scrub(partner_doctype)
|
||||
sales_users_data = get_parents_data(filters, partner_doctype)
|
||||
|
||||
if not sales_users_data: return
|
||||
sales_users, item_groups = [], []
|
||||
|
||||
for d in sales_users_data:
|
||||
if d.parent not in sales_users:
|
||||
sales_users.append(d.parent)
|
||||
|
||||
if d.item_group not in item_groups:
|
||||
item_groups.append(d.item_group)
|
||||
|
||||
date_field = ("transaction_date"
|
||||
if filters.get('doctype') == "Sales Order" else "posting_date")
|
||||
|
||||
actual_data = get_actual_data(filters, item_groups, sales_users, date_field, sales_field)
|
||||
|
||||
return prepare_data(filters, sales_users_data,
|
||||
actual_data, date_field, period_list, sales_field)
|
||||
|
||||
def get_columns(filters, period_list, partner_doctype):
|
||||
fieldtype, options = "Currency", "currency"
|
||||
|
||||
if filters.get("target_on") == 'Quantity':
|
||||
fieldtype, options = "Float", ""
|
||||
|
||||
columns = [{
|
||||
"fieldname": frappe.scrub(partner_doctype),
|
||||
"label": _(partner_doctype),
|
||||
"fieldtype": "Link",
|
||||
"options": partner_doctype,
|
||||
"width": 100
|
||||
}, {
|
||||
"fieldname": "item_group",
|
||||
"label": _("Item Group"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Item Group",
|
||||
"width": 100
|
||||
}]
|
||||
|
||||
for period in period_list:
|
||||
target_key = 'target_{}'.format(period.key)
|
||||
variance_key = 'variance_{}'.format(period.key)
|
||||
|
||||
columns.extend([{
|
||||
"fieldname": target_key,
|
||||
"label": _("Target ({})".format(period.label)),
|
||||
"fieldtype": fieldtype,
|
||||
"options": options,
|
||||
"width": 100
|
||||
}, {
|
||||
"fieldname": period.key,
|
||||
"label": _("Achieved ({})".format(period.label)),
|
||||
"fieldtype": fieldtype,
|
||||
"options": options,
|
||||
"width": 100
|
||||
}, {
|
||||
"fieldname": variance_key,
|
||||
"label": _("Variance ({})".format(period.label)),
|
||||
"fieldtype": fieldtype,
|
||||
"options": options,
|
||||
"width": 100
|
||||
}])
|
||||
|
||||
columns.extend([{
|
||||
"fieldname": "total_target",
|
||||
"label": _("Total Target"),
|
||||
"fieldtype": fieldtype,
|
||||
"options": options,
|
||||
"width": 100
|
||||
}, {
|
||||
"fieldname": "total_achieved",
|
||||
"label": _("Total Achieved"),
|
||||
"fieldtype": fieldtype,
|
||||
"options": options,
|
||||
"width": 100
|
||||
}, {
|
||||
"fieldname": "total_variance",
|
||||
"label": _("Total Variance"),
|
||||
"fieldtype": fieldtype,
|
||||
"options": options,
|
||||
"width": 100
|
||||
}])
|
||||
|
||||
return columns
|
||||
|
||||
def prepare_data(filters, sales_users_data, actual_data, date_field, period_list, sales_field):
|
||||
rows = {}
|
||||
|
||||
target_qty_amt_field = ("target_qty"
|
||||
if filters.get("target_on") == 'Quantity' else "target_amount")
|
||||
|
||||
qty_or_amount_field = ("stock_qty"
|
||||
if filters.get("target_on") == 'Quantity' else "base_net_amount")
|
||||
|
||||
for d in sales_users_data:
|
||||
key = (d.parent, d.item_group)
|
||||
dist_data = get_periodwise_distribution_data(d.distribution_id, period_list, filters.get("period"))
|
||||
|
||||
if key not in rows:
|
||||
rows.setdefault(key,{
|
||||
'total_target': 0,
|
||||
'total_achieved': 0,
|
||||
'total_variance': 0
|
||||
})
|
||||
|
||||
details = rows[key]
|
||||
for period in period_list:
|
||||
p_key = period.key
|
||||
if p_key not in details:
|
||||
details[p_key] = 0
|
||||
|
||||
target_key = 'target_{}'.format(p_key)
|
||||
variance_key = 'variance_{}'.format(p_key)
|
||||
details[target_key] = (d.get(target_qty_amt_field) * dist_data.get(p_key)) / 100
|
||||
details[variance_key] = 0
|
||||
details["total_target"] += details[target_key]
|
||||
|
||||
for r in actual_data:
|
||||
if (r.get(sales_field) == d.parent and r.item_group == d.item_group and
|
||||
period.from_date <= r.get(date_field) and r.get(date_field) <= period.to_date):
|
||||
details[p_key] += r.get(qty_or_amount_field, 0)
|
||||
details[variance_key] = details.get(target_key) - details.get(p_key)
|
||||
|
||||
details["total_achieved"] += details.get(p_key)
|
||||
details["total_variance"] = details.get("total_target") - details.get("total_achieved")
|
||||
|
||||
return rows
|
||||
|
||||
def get_actual_data(filters, item_groups, sales_users_or_territory_data, date_field, sales_field):
|
||||
fiscal_year = get_fiscal_year(fiscal_year=filters.get("fiscal_year"), as_dict=1)
|
||||
dates = [fiscal_year.year_start_date, fiscal_year.year_end_date]
|
||||
|
||||
select_field = "`tab{0}`.{1}".format(filters.get("doctype"), sales_field)
|
||||
child_table = "`tab{0}`".format(filters.get("doctype") + ' Item')
|
||||
|
||||
if sales_field == 'sales_person':
|
||||
select_field = "`tabSales Team`.sales_person"
|
||||
child_table = "`tab{0}`, `tabSales Team`".format(filters.get("doctype") + ' Item')
|
||||
cond = """`tabSales Team`.parent = `tab{0}`.name and
|
||||
`tabSales Team`.sales_person in ({1}) """.format(filters.get("doctype"),
|
||||
','.join(['%s'] * len(sales_users_or_territory_data)))
|
||||
else:
|
||||
cond = "`tab{0}`.{1} in ({2})".format(filters.get("doctype"), sales_field,
|
||||
','.join(['%s'] * len(sales_users_or_territory_data)))
|
||||
|
||||
return frappe.db.sql(""" SELECT `tab{child_doc}`.item_group,
|
||||
`tab{child_doc}`.stock_qty, `tab{child_doc}`.base_net_amount,
|
||||
{select_field}, `tab{parent_doc}`.{date_field}
|
||||
FROM `tab{parent_doc}`, {child_table}
|
||||
WHERE
|
||||
`tab{child_doc}`.parent = `tab{parent_doc}`.name
|
||||
and `tab{parent_doc}`.docstatus = 1 and {cond}
|
||||
and `tab{child_doc}`.item_group in ({item_groups})
|
||||
and `tab{parent_doc}`.{date_field} between %s and %s"""
|
||||
.format(
|
||||
cond = cond,
|
||||
date_field = date_field,
|
||||
select_field = select_field,
|
||||
child_table = child_table,
|
||||
parent_doc = filters.get("doctype"),
|
||||
child_doc = filters.get("doctype") + ' Item',
|
||||
item_groups = ','.join(['%s'] * len(item_groups))
|
||||
), tuple(sales_users_or_territory_data + item_groups + dates), as_dict=1)
|
||||
|
||||
def get_parents_data(filters, partner_doctype):
|
||||
filters_dict = {'parenttype': partner_doctype}
|
||||
|
||||
target_qty_amt_field = ("target_qty"
|
||||
if filters.get("target_on") == 'Quantity' else "target_amount")
|
||||
|
||||
if filters.get("fiscal_year"):
|
||||
filters_dict["fiscal_year"] = filters.get("fiscal_year")
|
||||
|
||||
return frappe.get_all('Target Detail',
|
||||
filters = filters_dict,
|
||||
fields = ["parent", "item_group", target_qty_amt_field, "fiscal_year", "distribution_id"])
|
@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
/* eslint-disable */
|
||||
|
||||
frappe.query_reports["Sales Partner Target Variance based on Item Group"] = {
|
||||
"filters": [
|
||||
{
|
||||
fieldname:"company",
|
||||
label: __("Company"),
|
||||
fieldtype: "Link",
|
||||
options: "Company",
|
||||
default: frappe.defaults.get_user_default("Company")
|
||||
},
|
||||
{
|
||||
fieldname: "fiscal_year",
|
||||
label: __("Fiscal Year"),
|
||||
fieldtype: "Link",
|
||||
options: "Fiscal Year",
|
||||
default: frappe.sys_defaults.fiscal_year
|
||||
},
|
||||
{
|
||||
fieldname: "doctype",
|
||||
label: __("Document Type"),
|
||||
fieldtype: "Select",
|
||||
options: "Sales Order\nDelivery Note\nSales Invoice",
|
||||
default: "Sales Order"
|
||||
},
|
||||
{
|
||||
fieldname: "period",
|
||||
label: __("Period"),
|
||||
fieldtype: "Select",
|
||||
options: [
|
||||
{ "value": "Monthly", "label": __("Monthly") },
|
||||
{ "value": "Quarterly", "label": __("Quarterly") },
|
||||
{ "value": "Half-Yearly", "label": __("Half-Yearly") },
|
||||
{ "value": "Yearly", "label": __("Yearly") }
|
||||
],
|
||||
default: "Monthly"
|
||||
},
|
||||
{
|
||||
fieldname: "target_on",
|
||||
label: __("Target On"),
|
||||
fieldtype: "Select",
|
||||
options: "Quantity\nAmount",
|
||||
default: "Quantity"
|
||||
},
|
||||
]
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
{
|
||||
"add_total_row": 0,
|
||||
"creation": "2019-03-25 18:22:37.323995",
|
||||
"disable_prepared_report": 0,
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"letter_head": "Gadgets International",
|
||||
"modified": "2019-03-25 18:22:37.323995",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Partner Target Variance based on Item Group",
|
||||
"owner": "Administrator",
|
||||
"prepared_report": 0,
|
||||
"ref_doctype": "Sales Order",
|
||||
"report_name": "Sales Partner Target Variance based on Item Group",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
||||
"role": "Sales User"
|
||||
},
|
||||
{
|
||||
"role": "Sales Manager"
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User"
|
||||
},
|
||||
{
|
||||
"role": "Accounts User"
|
||||
},
|
||||
{
|
||||
"role": "Stock User"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from erpnext.selling.report.sales_partner_target_variance_based_on_item_group.item_group_wise_sales_target_variance import get_data_column
|
||||
|
||||
def execute(filters=None):
|
||||
data = []
|
||||
|
||||
return get_data_column(filters, "Sales Partner")
|
||||
|
@ -2,7 +2,7 @@
|
||||
// For license information, please see license.txt
|
||||
/* eslint-disable */
|
||||
|
||||
frappe.query_reports["Sales Partner-wise Transaction Summary"] = {
|
||||
frappe.query_reports["Sales Partner Transaction Summary"] = {
|
||||
"filters": [
|
||||
{
|
||||
fieldname: "sales_partner",
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"add_total_row": 1,
|
||||
"creation": "2019-03-15 16:21:16.088831",
|
||||
"creation": "2019-03-25 18:15:09.920739",
|
||||
"disable_prepared_report": 0,
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
@ -8,14 +8,14 @@
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"letter_head": "Gadgets International",
|
||||
"modified": "2019-03-15 16:21:16.088831",
|
||||
"modified": "2019-03-25 18:15:09.920739",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Partner-wise Transaction Summary",
|
||||
"name": "Sales Partner Transaction Summary",
|
||||
"owner": "Administrator",
|
||||
"prepared_report": 0,
|
||||
"ref_doctype": "Sales Order",
|
||||
"report_name": "Sales Partner-wise Transaction Summary",
|
||||
"report_name": "Sales Partner Transaction Summary",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
@ -1,8 +1,16 @@
|
||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
/* eslint-disable */
|
||||
|
||||
frappe.query_reports["Territory Target Variance Item Group-Wise"] = {
|
||||
frappe.query_reports["Sales Person Target Variance Based On Item Group"] = {
|
||||
"filters": [
|
||||
{
|
||||
fieldname:"company",
|
||||
label: __("Company"),
|
||||
fieldtype: "Link",
|
||||
options: "Company",
|
||||
default: frappe.defaults.get_user_default("Company")
|
||||
},
|
||||
{
|
||||
fieldname: "fiscal_year",
|
||||
label: __("Fiscal Year"),
|
||||
@ -10,6 +18,13 @@ frappe.query_reports["Territory Target Variance Item Group-Wise"] = {
|
||||
options: "Fiscal Year",
|
||||
default: frappe.sys_defaults.fiscal_year
|
||||
},
|
||||
{
|
||||
fieldname: "doctype",
|
||||
label: __("Document Type"),
|
||||
fieldtype: "Select",
|
||||
options: "Sales Order\nDelivery Note\nSales Invoice",
|
||||
default: "Sales Order"
|
||||
},
|
||||
{
|
||||
fieldname: "period",
|
||||
label: __("Period"),
|
@ -1,19 +1,21 @@
|
||||
{
|
||||
"add_total_row": 0,
|
||||
"apply_user_permissions": 1,
|
||||
"creation": "2013-06-21 12:15:00",
|
||||
"creation": "2019-03-25 22:16:49.040998",
|
||||
"disable_prepared_report": 0,
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 3,
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2017-02-24 20:13:29.705321",
|
||||
"letter_head": "Gadgets International",
|
||||
"modified": "2019-03-25 22:16:49.040998",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Territory Target Variance Item Group-Wise",
|
||||
"name": "Sales Person Target Variance Based On Item Group",
|
||||
"owner": "Administrator",
|
||||
"prepared_report": 0,
|
||||
"ref_doctype": "Sales Order",
|
||||
"report_name": "Territory Target Variance Item Group-Wise",
|
||||
"report_name": "Sales Person Target Variance Based On Item Group",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
@ -0,0 +1,11 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from erpnext.selling.report.sales_partner_target_variance_based_on_item_group.item_group_wise_sales_target_variance import get_data_column
|
||||
|
||||
def execute(filters=None):
|
||||
data = []
|
||||
|
||||
return get_data_column(filters, "Sales Person")
|
@ -1,178 +0,0 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _, msgprint
|
||||
from frappe.utils import flt
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
from erpnext.controllers.trends import get_period_date_ranges, get_period_month_ranges
|
||||
|
||||
def execute(filters=None):
|
||||
if not filters: filters = {}
|
||||
|
||||
columns = get_columns(filters)
|
||||
period_month_ranges = get_period_month_ranges(filters["period"], filters["fiscal_year"])
|
||||
sim_map = get_salesperson_item_month_map(filters)
|
||||
|
||||
data = []
|
||||
for salesperson, salesperson_items in sim_map.items():
|
||||
for item_group, monthwise_data in salesperson_items.items():
|
||||
row = [salesperson, item_group]
|
||||
totals = [0, 0, 0]
|
||||
for relevant_months in period_month_ranges:
|
||||
period_data = [0, 0, 0]
|
||||
for month in relevant_months:
|
||||
month_data = monthwise_data.get(month, {})
|
||||
for i, fieldname in enumerate(["target", "achieved", "variance"]):
|
||||
value = flt(month_data.get(fieldname))
|
||||
period_data[i] += value
|
||||
totals[i] += value
|
||||
period_data[2] = period_data[0] - period_data[1]
|
||||
row += period_data
|
||||
totals[2] = totals[0] - totals[1]
|
||||
row += totals
|
||||
data.append(row)
|
||||
|
||||
return columns, sorted(data, key=lambda x: (x[0], x[1]))
|
||||
|
||||
def get_columns(filters):
|
||||
for fieldname in ["fiscal_year", "period", "target_on"]:
|
||||
if not filters.get(fieldname):
|
||||
label = (" ".join(fieldname.split("_"))).title()
|
||||
msgprint(_("Please specify") + ": " + label,
|
||||
raise_exception=True)
|
||||
|
||||
columns = [_("Sales Person") + ":Link/Sales Person:120", _("Item Group") + ":Link/Item Group:120"]
|
||||
|
||||
group_months = False if filters["period"] == "Monthly" else True
|
||||
|
||||
for from_date, to_date in get_period_date_ranges(filters["period"], filters["fiscal_year"]):
|
||||
for label in [_("Target") + " (%s)", _("Achieved") + " (%s)", _("Variance") + " (%s)"]:
|
||||
if group_months:
|
||||
label = label % (_(from_date.strftime("%b")) + " - " + _(to_date.strftime("%b")))
|
||||
else:
|
||||
label = label % _(from_date.strftime("%b"))
|
||||
|
||||
columns.append(label+":Float:120")
|
||||
|
||||
return columns + [_("Total Target") + ":Float:120", _("Total Achieved") + ":Float:120",
|
||||
_("Total Variance") + ":Float:120"]
|
||||
|
||||
#Get sales person & item group details
|
||||
def get_salesperson_details(filters):
|
||||
return frappe.db.sql("""
|
||||
select
|
||||
sp.name, td.item_group, td.target_qty, td.target_amount, sp.distribution_id
|
||||
from
|
||||
`tabSales Person` sp, `tabTarget Detail` td
|
||||
where
|
||||
td.parent=sp.name and td.fiscal_year=%s order by sp.name
|
||||
""", (filters["fiscal_year"]), as_dict=1)
|
||||
|
||||
#Get target distribution details of item group
|
||||
def get_target_distribution_details(filters):
|
||||
target_details = {}
|
||||
|
||||
for d in frappe.db.sql("""
|
||||
select
|
||||
md.name, mdp.month, mdp.percentage_allocation
|
||||
from
|
||||
`tabMonthly Distribution Percentage` mdp, `tabMonthly Distribution` md
|
||||
where
|
||||
mdp.parent=md.name and md.fiscal_year=%s
|
||||
""", (filters["fiscal_year"]), as_dict=1):
|
||||
target_details.setdefault(d.name, {}).setdefault(d.month, flt(d.percentage_allocation))
|
||||
|
||||
return target_details
|
||||
|
||||
#Get achieved details from sales order
|
||||
def get_achieved_details(filters, sales_person, all_sales_persons, target_item_group, item_groups):
|
||||
start_date, end_date = get_fiscal_year(fiscal_year = filters["fiscal_year"])[1:]
|
||||
|
||||
item_details = frappe.db.sql("""
|
||||
SELECT st.sales_person, MONTHNAME(so.transaction_date) as month_name,
|
||||
CASE
|
||||
WHEN so.status = "Closed" THEN sum(soi.delivered_qty * soi.conversion_factor * (st.allocated_percentage/100))
|
||||
ELSE sum(soi.stock_qty * (st.allocated_percentage/100))
|
||||
END as qty,
|
||||
CASE
|
||||
WHEN so.status = "Closed" THEN sum(soi.delivered_qty * soi.conversion_factor * soi.base_net_rate * (st.allocated_percentage/100))
|
||||
ELSE sum(soi.base_net_amount * (st.allocated_percentage/100))
|
||||
END as amount
|
||||
from
|
||||
`tabSales Order Item` soi, `tabSales Order` so, `tabSales Team` st
|
||||
where
|
||||
soi.parent=so.name and so.docstatus=1 and st.parent=so.name
|
||||
and so.transaction_date>=%s and so.transaction_date<=%s
|
||||
and exists(SELECT name from `tabSales Person` where lft >= %s and rgt <= %s and name=st.sales_person)
|
||||
and exists(SELECT name from `tabItem Group` where lft >= %s and rgt <= %s and name=soi.item_group)
|
||||
group by
|
||||
sales_person, month_name
|
||||
""",
|
||||
(start_date, end_date, all_sales_persons[sales_person].lft, all_sales_persons[sales_person].rgt,
|
||||
item_groups[target_item_group].lft, item_groups[target_item_group].rgt), as_dict=1)
|
||||
|
||||
actual_details = {}
|
||||
for d in item_details:
|
||||
actual_details.setdefault(d.month_name, frappe._dict({
|
||||
"quantity" : 0,
|
||||
"amount" : 0
|
||||
}))
|
||||
|
||||
value_dict = actual_details[d.month_name]
|
||||
value_dict.quantity += flt(d.qty)
|
||||
value_dict.amount += flt(d.amount)
|
||||
|
||||
return actual_details
|
||||
|
||||
def get_salesperson_item_month_map(filters):
|
||||
import datetime
|
||||
salesperson_details = get_salesperson_details(filters)
|
||||
tdd = get_target_distribution_details(filters)
|
||||
item_groups = get_item_groups()
|
||||
sales_persons = get_sales_persons()
|
||||
|
||||
sales_person_achievement_dict = {}
|
||||
for sd in salesperson_details:
|
||||
achieved_details = get_achieved_details(filters, sd.name, sales_persons, sd.item_group, item_groups)
|
||||
|
||||
for month_id in range(1, 13):
|
||||
month = datetime.date(2013, month_id, 1).strftime('%B')
|
||||
sales_person_achievement_dict.setdefault(sd.name, {}).setdefault(sd.item_group, {})\
|
||||
.setdefault(month, frappe._dict({
|
||||
"target": 0.0, "achieved": 0.0
|
||||
}))
|
||||
|
||||
sales_target_achieved = sales_person_achievement_dict[sd.name][sd.item_group][month]
|
||||
month_percentage = tdd.get(sd.distribution_id, {}).get(month, 0) \
|
||||
if sd.distribution_id else 100.0/12
|
||||
|
||||
if (filters["target_on"] == "Quantity"):
|
||||
sales_target_achieved.target = flt(sd.target_qty) * month_percentage / 100
|
||||
else:
|
||||
sales_target_achieved.target = flt(sd.target_amount) * month_percentage / 100
|
||||
|
||||
sales_target_achieved.achieved = achieved_details.get(month, frappe._dict())\
|
||||
.get(filters["target_on"].lower())
|
||||
|
||||
return sales_person_achievement_dict
|
||||
|
||||
def get_item_groups():
|
||||
item_groups = frappe._dict()
|
||||
for d in frappe.get_all("Item Group", fields=["name", "lft", "rgt"]):
|
||||
item_groups.setdefault(d.name, frappe._dict({
|
||||
"lft": d.lft,
|
||||
"rgt": d.rgt
|
||||
}))
|
||||
return item_groups
|
||||
|
||||
def get_sales_persons():
|
||||
sales_persons = frappe._dict()
|
||||
for d in frappe.get_all("Sales Person", fields=["name", "lft", "rgt"]):
|
||||
sales_persons.setdefault(d.name, frappe._dict({
|
||||
"lft": d.lft,
|
||||
"rgt": d.rgt
|
||||
}))
|
||||
return sales_persons
|
||||
|
@ -1,8 +1,16 @@
|
||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
/* eslint-disable */
|
||||
|
||||
frappe.query_reports["Sales Person Target Variance Item Group-Wise"] = {
|
||||
frappe.query_reports["Territory Target Variance Based On Item Group"] = {
|
||||
"filters": [
|
||||
{
|
||||
fieldname:"company",
|
||||
label: __("Company"),
|
||||
fieldtype: "Link",
|
||||
options: "Company",
|
||||
default: frappe.defaults.get_user_default("Company")
|
||||
},
|
||||
{
|
||||
fieldname: "fiscal_year",
|
||||
label: __("Fiscal Year"),
|
||||
@ -10,6 +18,13 @@ frappe.query_reports["Sales Person Target Variance Item Group-Wise"] = {
|
||||
options: "Fiscal Year",
|
||||
default: frappe.sys_defaults.fiscal_year
|
||||
},
|
||||
{
|
||||
fieldname: "doctype",
|
||||
label: __("Document Type"),
|
||||
fieldtype: "Select",
|
||||
options: "Sales Order\nDelivery Note\nSales Invoice",
|
||||
default: "Sales Order"
|
||||
},
|
||||
{
|
||||
fieldname: "period",
|
||||
label: __("Period"),
|
@ -1,19 +1,21 @@
|
||||
{
|
||||
"add_total_row": 0,
|
||||
"apply_user_permissions": 1,
|
||||
"creation": "2013-06-21 12:14:15",
|
||||
"creation": "2019-03-25 22:20:59.033199",
|
||||
"disable_prepared_report": 0,
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 3,
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2017-02-24 20:14:50.589149",
|
||||
"letter_head": "Gadgets International",
|
||||
"modified": "2019-03-25 22:20:59.033199",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Person Target Variance Item Group-Wise",
|
||||
"name": "Territory Target Variance Based On Item Group",
|
||||
"owner": "Administrator",
|
||||
"prepared_report": 0,
|
||||
"ref_doctype": "Sales Order",
|
||||
"report_name": "Sales Person Target Variance Item Group-Wise",
|
||||
"report_name": "Territory Target Variance Based On Item Group",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
@ -0,0 +1,11 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from erpnext.selling.report.sales_partner_target_variance_based_on_item_group.item_group_wise_sales_target_variance import get_data_column
|
||||
|
||||
def execute(filters=None):
|
||||
data = []
|
||||
|
||||
return get_data_column(filters, "Territory")
|
@ -1,157 +0,0 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _, msgprint
|
||||
from frappe.utils import flt
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
from erpnext.controllers.trends import get_period_date_ranges, get_period_month_ranges
|
||||
|
||||
def execute(filters=None):
|
||||
if not filters: filters = {}
|
||||
|
||||
columns = get_columns(filters)
|
||||
period_month_ranges = get_period_month_ranges(filters["period"], filters["fiscal_year"])
|
||||
territory_item_group_dict = get_territory_item_month_map(filters)
|
||||
|
||||
data = []
|
||||
for territory, territory_items in territory_item_group_dict.items():
|
||||
for item_group, monthwise_data in territory_items.items():
|
||||
row = [territory, item_group]
|
||||
totals = [0, 0, 0]
|
||||
for relevant_months in period_month_ranges:
|
||||
period_data = [0, 0, 0]
|
||||
for month in relevant_months:
|
||||
month_data = monthwise_data.get(month, {})
|
||||
for i, fieldname in enumerate(["target", "achieved", "variance"]):
|
||||
value = flt(month_data.get(fieldname))
|
||||
period_data[i] += value
|
||||
totals[i] += value
|
||||
period_data[2] = period_data[0] - period_data[1]
|
||||
row += period_data
|
||||
totals[2] = totals[0] - totals[1]
|
||||
row += totals
|
||||
data.append(row)
|
||||
|
||||
return columns, sorted(data, key=lambda x: (x[0], x[1]))
|
||||
|
||||
def get_columns(filters):
|
||||
for fieldname in ["fiscal_year", "period", "target_on"]:
|
||||
if not filters.get(fieldname):
|
||||
label = (" ".join(fieldname.split("_"))).title()
|
||||
msgprint(_("Please specify") + ": " + label, raise_exception=True)
|
||||
|
||||
columns = [_("Territory") + ":Link/Territory:120", _("Item Group") + ":Link/Item Group:120"]
|
||||
|
||||
group_months = False if filters["period"] == "Monthly" else True
|
||||
|
||||
for from_date, to_date in get_period_date_ranges(filters["period"], filters["fiscal_year"]):
|
||||
for label in [_("Target") +" (%s)", _("Achieved") + " (%s)", _("Variance") + " (%s)"]:
|
||||
if group_months:
|
||||
label = label % (_(from_date.strftime("%b")) + " - " + _(to_date.strftime("%b")))
|
||||
else:
|
||||
label = label % _(from_date.strftime("%b"))
|
||||
columns.append(label+":Float:120")
|
||||
|
||||
return columns + [_("Total Target") + ":Float:120", _("Total Achieved") + ":Float:120",
|
||||
_("Total Variance") + ":Float:120"]
|
||||
|
||||
#Get territory & item group details
|
||||
def get_territory_details(filters):
|
||||
return frappe.db.sql("""
|
||||
select
|
||||
t.name, td.item_group, td.target_qty, td.target_amount, t.distribution_id
|
||||
from
|
||||
`tabTerritory` t, `tabTarget Detail` td
|
||||
where
|
||||
td.parent=t.name and td.fiscal_year=%s order by t.name
|
||||
""", (filters["fiscal_year"]), as_dict=1)
|
||||
|
||||
#Get target distribution details of item group
|
||||
def get_target_distribution_details(filters):
|
||||
target_details = {}
|
||||
|
||||
for d in frappe.db.sql("""
|
||||
select
|
||||
md.name, mdp.month, mdp.percentage_allocation
|
||||
from
|
||||
`tabMonthly Distribution Percentage` mdp, `tabMonthly Distribution` md
|
||||
where
|
||||
mdp.parent=md.name and md.fiscal_year=%s
|
||||
""", (filters["fiscal_year"]), as_dict=1):
|
||||
target_details.setdefault(d.name, {}).setdefault(d.month, flt(d.percentage_allocation))
|
||||
|
||||
return target_details
|
||||
|
||||
#Get achieved details from sales order
|
||||
def get_achieved_details(filters, territory, item_groups):
|
||||
start_date, end_date = get_fiscal_year(fiscal_year = filters["fiscal_year"])[1:]
|
||||
|
||||
lft, rgt = frappe.db.get_value("Territory", territory, ["lft", "rgt"])
|
||||
|
||||
item_details = frappe.db.sql("""
|
||||
select
|
||||
soi.item_code, sum(soi.stock_qty) as qty, sum(soi.base_net_amount) as amount,
|
||||
MONTHNAME(so.transaction_date) as month_name
|
||||
from
|
||||
`tabSales Order Item` soi, `tabSales Order` so
|
||||
where
|
||||
soi.parent=so.name and so.docstatus=1
|
||||
and so.transaction_date>=%s and so.transaction_date<=%s
|
||||
and exists(select name from `tabTerritory` where lft >=%s and rgt <= %s and name=so.territory)
|
||||
group by
|
||||
month_name, item_code
|
||||
""", (start_date, end_date, lft, rgt), as_dict=1)
|
||||
|
||||
item_actual_details = {}
|
||||
for d in item_details:
|
||||
item_group = item_groups[d.item_code]
|
||||
item_actual_details.setdefault(item_group, frappe._dict())\
|
||||
.setdefault(d.month_name, frappe._dict({
|
||||
"quantity": 0,
|
||||
"amount": 0
|
||||
}))
|
||||
|
||||
value_dict = item_actual_details[item_group][d.month_name]
|
||||
value_dict.quantity += flt(d.qty)
|
||||
value_dict.amount += flt(d.amount)
|
||||
|
||||
return item_actual_details
|
||||
|
||||
def get_territory_item_month_map(filters):
|
||||
import datetime
|
||||
territory_details = get_territory_details(filters)
|
||||
tdd = get_target_distribution_details(filters)
|
||||
item_groups = get_item_groups()
|
||||
|
||||
territory_item_group_dict = {}
|
||||
|
||||
for td in territory_details:
|
||||
achieved_details = get_achieved_details(filters, td.name, item_groups)
|
||||
|
||||
for month_id in range(1, 13):
|
||||
month = datetime.date(2013, month_id, 1).strftime('%B')
|
||||
|
||||
territory_item_group_dict.setdefault(td.name, {}).setdefault(td.item_group, {})\
|
||||
.setdefault(month, frappe._dict({
|
||||
"target": 0.0, "achieved": 0.0
|
||||
}))
|
||||
|
||||
target_achieved = territory_item_group_dict[td.name][td.item_group][month]
|
||||
month_percentage = tdd.get(td.distribution_id, {}).get(month, 0) \
|
||||
if td.distribution_id else 100.0/12
|
||||
|
||||
|
||||
if (filters["target_on"] == "Quantity"):
|
||||
target_achieved.target = flt(td.target_qty) * month_percentage / 100
|
||||
else:
|
||||
target_achieved.target = flt(td.target_amount) * month_percentage / 100
|
||||
|
||||
target_achieved.achieved = achieved_details.get(td.item_group, {}).get(month, {})\
|
||||
.get(filters["target_on"].lower())
|
||||
|
||||
return territory_item_group_dict
|
||||
|
||||
def get_item_groups():
|
||||
return dict(frappe.get_all("Item", fields=["name", "item_group"], as_list=1))
|
@ -22,6 +22,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "details",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -54,6 +55,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "company_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
@ -88,6 +90,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "abbr",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
@ -122,6 +125,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal && in_list(frappe.user_roles, \"System Manager\")",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "change_abbr",
|
||||
"fieldtype": "Button",
|
||||
"hidden": 0,
|
||||
@ -153,6 +157,7 @@
|
||||
"bold": 1,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "is_group",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@ -185,6 +190,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "default_finance_book",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -218,6 +224,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "cb0",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@ -248,6 +255,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "domain",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -280,6 +288,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "parent_company",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -313,6 +322,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "sb_about",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -345,6 +355,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "company_logo",
|
||||
"fieldtype": "Attach Image",
|
||||
"hidden": 0,
|
||||
@ -377,6 +388,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "company_description",
|
||||
"fieldtype": "Text Editor",
|
||||
"hidden": 0,
|
||||
@ -409,6 +421,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "sales_settings",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -441,6 +454,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "sales_monthly_history",
|
||||
"fieldtype": "Small Text",
|
||||
"hidden": 1,
|
||||
@ -473,6 +487,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "transactions_annual_history",
|
||||
"fieldtype": "Code",
|
||||
"hidden": 1,
|
||||
@ -505,6 +520,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "monthly_sales_target",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
@ -538,6 +554,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_goals",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@ -569,6 +586,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "total_monthly_sales",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
@ -602,6 +620,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "charts_section",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -633,6 +652,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "default_currency",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -665,6 +685,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "default_letter_head",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -698,6 +719,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "default_holiday_list",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -731,6 +753,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "standard_working_hours",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
@ -763,6 +786,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "default_terms",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -795,6 +819,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_10",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@ -826,6 +851,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "country",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -858,6 +884,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "create_chart_of_accounts_based_on",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
@ -892,6 +919,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.create_chart_of_accounts_based_on===\"Standard Template\"",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "chart_of_accounts",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
@ -926,6 +954,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.create_chart_of_accounts_based_on===\"Existing Company\"",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "existing_company",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -959,6 +988,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "tax_id",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
@ -991,6 +1021,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "date_of_establishment",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
@ -1023,6 +1054,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "default_settings",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -1056,6 +1088,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "default_bank_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1091,6 +1124,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "default_cash_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1124,6 +1158,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "default_receivable_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1158,6 +1193,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "round_off_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1191,6 +1227,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "round_off_cost_center",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1224,6 +1261,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "write_off_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1257,6 +1295,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "discount_allowed_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1290,6 +1329,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "discount_received_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1323,6 +1363,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "exchange_gain_loss_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1356,6 +1397,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "unrealized_exchange_gain_loss_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1389,6 +1431,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break0",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@ -1414,6 +1457,40 @@
|
||||
"unique": 0,
|
||||
"width": "50%"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.parent_company",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "allow_account_creation_against_child_company",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Allow Account Creation Against Child Company",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
@ -1422,6 +1499,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "default_payable_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1456,6 +1534,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "default_employee_advance_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1490,6 +1569,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "default_expense_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1523,6 +1603,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "default_income_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1556,6 +1637,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "default_deferred_revenue_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1590,6 +1672,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "default_deferred_expense_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1624,6 +1707,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "default_payroll_payable_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1658,6 +1742,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "default_expense_claim_payable_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1691,6 +1776,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_22",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -1723,6 +1809,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "cost_center",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1755,6 +1842,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_26",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@ -1787,6 +1875,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "credit_limit",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
@ -1822,6 +1911,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "payment_terms",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1856,6 +1946,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "auto_accounting_for_stock_settings",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -1888,6 +1979,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "1",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "enable_perpetual_inventory",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@ -1920,6 +2012,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "default_inventory_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1953,6 +2046,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "stock_adjustment_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1985,6 +2079,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_32",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@ -2016,6 +2111,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "stock_received_but_not_billed",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -2048,6 +2144,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "expenses_included_in_valuation",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -2080,6 +2177,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "fixed_asset_depreciation_settings",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -2112,6 +2210,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "accumulated_depreciation_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -2145,6 +2244,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "depreciation_expense_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -2178,6 +2278,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "series_for_depreciation_entry",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
@ -2210,6 +2311,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "expenses_included_in_asset_valuation",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -2243,6 +2345,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_40",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@ -2274,6 +2377,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "disposal_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -2307,6 +2411,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "depreciation_cost_center",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -2340,6 +2445,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "capital_work_in_progress_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -2373,6 +2479,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "asset_received_but_not_billed",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -2406,6 +2513,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "budget_detail",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -2438,6 +2546,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "exception_budget_approver_role",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -2472,6 +2581,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "For reference only.",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "company_info",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -2503,6 +2613,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "date_of_incorporation",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
@ -2535,6 +2646,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "address_html",
|
||||
"fieldtype": "HTML",
|
||||
"hidden": 0,
|
||||
@ -2566,6 +2678,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break1",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@ -2599,6 +2712,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.date_of_incorporation",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "date_of_commencement",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
@ -2631,6 +2745,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "phone_no",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
@ -2665,6 +2780,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "fax",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
@ -2699,6 +2815,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "email",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
@ -2733,6 +2850,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "website",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
@ -2767,6 +2885,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "registration_info",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -2801,6 +2920,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Company registration numbers for your reference. Tax numbers etc.",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "registration_details",
|
||||
"fieldtype": "Code",
|
||||
"hidden": 0,
|
||||
@ -2834,6 +2954,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "delete_company_transactions",
|
||||
"fieldtype": "Button",
|
||||
"hidden": 0,
|
||||
@ -2866,6 +2987,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "lft",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 1,
|
||||
@ -2898,6 +3020,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "rgt",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 1,
|
||||
@ -2930,6 +3053,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "old_parent",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
@ -2969,7 +3093,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2019-01-15 13:29:54.510379",
|
||||
"modified": "2019-03-26 17:15:50.390548",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Company",
|
||||
|
@ -13,5 +13,16 @@ frappe.ui.form.on('Sales Partner', {
|
||||
unhide_field(['address_html', 'contact_html', 'address_contacts']);
|
||||
frappe.contacts.render_address_and_contact(frm);
|
||||
}
|
||||
},
|
||||
|
||||
setup: function(frm) {
|
||||
frm.fields_dict["targets"].grid.get_field("distribution_id").get_query = function(doc, cdt, cdn){
|
||||
var row = locals[cdt][cdn];
|
||||
return {
|
||||
filters: {
|
||||
'fiscal_year': row.fiscal_year
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
@ -21,6 +22,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "partner_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
@ -45,7 +47,7 @@
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
@ -54,6 +56,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "partner_type",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -89,6 +92,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "territory",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -121,6 +125,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break0",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@ -153,6 +158,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "commission_rate",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
@ -186,6 +192,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "address_contacts",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -218,6 +225,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.__islocal",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "address_desc",
|
||||
"fieldtype": "HTML",
|
||||
"hidden": 0,
|
||||
@ -249,6 +257,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "address_html",
|
||||
"fieldtype": "HTML",
|
||||
"hidden": 0,
|
||||
@ -280,6 +289,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break1",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@ -311,6 +321,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.__islocal",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "contact_desc",
|
||||
"fieldtype": "HTML",
|
||||
"hidden": 0,
|
||||
@ -342,6 +353,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "contact_html",
|
||||
"fieldtype": "HTML",
|
||||
"hidden": 0,
|
||||
@ -373,6 +385,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "partner_target_details_section_break",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -405,6 +418,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "targets",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
@ -439,41 +453,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Select Monthly Distribution to unevenly distribute targets across months.",
|
||||
"fieldname": "distribution_id",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Target Distribution",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "distribution_id",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Monthly Distribution",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "website",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -505,6 +485,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "show_in_website",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@ -537,6 +518,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "show_in_website",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_17",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -567,6 +549,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "route",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
@ -599,6 +582,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_20",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@ -629,6 +613,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "logo",
|
||||
"fieldtype": "Attach",
|
||||
"hidden": 0,
|
||||
@ -661,6 +646,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "partner_website",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
@ -693,6 +679,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "show_in_website",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_22",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -723,6 +710,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "introduction",
|
||||
"fieldtype": "Text",
|
||||
"hidden": 0,
|
||||
@ -754,6 +742,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Text Editor",
|
||||
"hidden": 0,
|
||||
@ -790,7 +779,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-06-11 13:47:04.182339",
|
||||
"modified": "2019-03-21 16:26:45.447265",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Sales Partner",
|
||||
@ -860,5 +849,6 @@
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_order": "ASC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
@ -8,6 +8,17 @@ frappe.ui.form.on('Sales Person', {
|
||||
frm.dashboard.add_indicator(__('Total Contribution Amount: {0}',
|
||||
[format_currency(info.allocated_amount, info.currency)]), 'blue');
|
||||
}
|
||||
},
|
||||
|
||||
setup: function(frm) {
|
||||
frm.fields_dict["targets"].grid.get_field("distribution_id").get_query = function(doc, cdt, cdn){
|
||||
var row = locals[cdt][cdn];
|
||||
return {
|
||||
filters: {
|
||||
'fiscal_year': row.fiscal_year
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "name_and_employee_id",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -54,6 +55,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "sales_person_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
@ -88,6 +90,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Select company name first.",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "parent_sales_person",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -122,6 +125,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "commission_rate",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
@ -154,6 +158,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "is_group",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@ -189,6 +194,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "1",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "enabled",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@ -221,6 +227,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "cb0",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@ -251,6 +258,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "employee",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -284,6 +292,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "employee.department",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "department",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -317,6 +326,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "lft",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 1,
|
||||
@ -350,6 +360,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "rgt",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 1,
|
||||
@ -383,6 +394,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "old_parent",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
@ -417,6 +429,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Set targets Item Group-wise for this Sales Person.",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "target_details_section_break",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@ -450,6 +463,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "targets",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
@ -476,41 +490,6 @@
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Select Monthly Distribution to unevenly distribute targets across months.",
|
||||
"fieldname": "distribution_id",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Target Distribution",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "distribution_id",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Monthly Distribution",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
@ -524,7 +503,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-01-30 11:28:16.966735",
|
||||
"modified": "2019-03-21 16:26:01.706129",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Sales Person",
|
||||
|
@ -19,6 +19,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "item_group",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -53,6 +54,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "fiscal_year",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -87,6 +89,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "target_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
@ -120,6 +123,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "target_amount",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
@ -145,6 +149,40 @@
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "distribution_id",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Target Distribution",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Monthly Distribution",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
@ -157,7 +195,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-01-07 16:56:48.179709",
|
||||
"modified": "2019-03-20 16:59:03.578274",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Target Detail",
|
||||
|
@ -1,6 +1,18 @@
|
||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
frappe.ui.form.on("Territory", {
|
||||
setup: function(frm) {
|
||||
frm.fields_dict["targets"].grid.get_field("distribution_id").get_query = function(doc, cdt, cdn){
|
||||
var row = locals[cdt][cdn];
|
||||
return {
|
||||
filters: {
|
||||
'fiscal_year': row.fiscal_year
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
|
||||
cur_frm.cscript.set_root_readonly(doc);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user