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 erpnext.hooks import regional_overrides
|
||||||
from frappe.utils import getdate
|
from frappe.utils import getdate
|
||||||
|
|
||||||
__version__ = '11.1.16'
|
__version__ = '11.1.17'
|
||||||
|
|
||||||
def get_default_company(user=None):
|
def get_default_company(user=None):
|
||||||
'''Get default company for user'''
|
'''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
|
import frappe
|
||||||
from frappe import _
|
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.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):
|
def validate_service_stop_date(doc):
|
||||||
''' Validates service_stop_date for Purchase Invoice and Sales Invoice '''
|
''' 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)))
|
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):
|
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
|
# check for the purchase invoice for which GL entries has to be done
|
||||||
invoices = frappe.db.sql_list('''
|
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
|
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 each invoice, book deferred expense
|
||||||
for invoice in invoices:
|
for invoice in invoices:
|
||||||
doc = frappe.get_doc("Purchase Invoice", invoice)
|
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):
|
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
|
# check for the sales invoice for which GL entries has to be done
|
||||||
invoices = frappe.db.sql_list('''
|
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
|
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:
|
for invoice in invoices:
|
||||||
doc = frappe.get_doc("Sales Invoice", invoice)
|
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"
|
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('''
|
prev_gl_entry = frappe.db.sql('''
|
||||||
select name, posting_date from `tabGL Entry` where company=%s and account=%s and
|
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
|
order by posting_date desc limit 1
|
||||||
''', (doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True)
|
''', (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:
|
if prev_gl_entry:
|
||||||
booking_start_date = item.service_start_date
|
start_date = getdate(add_days(prev_gl_entry[0].posting_date, 1))
|
||||||
elif prev_gl_entry:
|
else:
|
||||||
booking_start_date = getdate(add_days(prev_gl_entry[0].posting_date, 1))
|
start_date = item.service_start_date
|
||||||
skip = True if booking_start_date > booking_end_date else False
|
|
||||||
|
|
||||||
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):
|
if end_date > getdate(posting_date):
|
||||||
account_currency = get_account_currency(item.expense_account)
|
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":
|
if doc.doctype == "Sales Invoice":
|
||||||
total_credit_debit, total_credit_debit_currency = "debit", "debit_in_account_currency"
|
total_credit_debit, total_credit_debit_currency = "debit", "debit_in_account_currency"
|
||||||
deferred_account = "deferred_revenue_account"
|
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
|
return amount, base_amount
|
||||||
|
|
||||||
def book_deferred_income_or_expense(doc, start_date=None, end_date=None):
|
def book_deferred_income_or_expense(doc, posting_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
|
|
||||||
enable_check = "enable_deferred_revenue" \
|
enable_check = "enable_deferred_revenue" \
|
||||||
if doc.doctype=="Sales Invoice" else "enable_deferred_expense"
|
if doc.doctype=="Sales Invoice" else "enable_deferred_expense"
|
||||||
|
|
||||||
gl_entries = []
|
def _book_deferred_revenue_or_expense(item):
|
||||||
for item in doc.get('items'):
|
start_date, end_date, last_gl_entry = get_booking_dates(doc, item, posting_date=posting_date)
|
||||||
if not item.get(enable_check): continue
|
if not (start_date and end_date): return
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
account_currency = get_account_currency(item.expense_account)
|
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":
|
if doc.doctype == "Sales Invoice":
|
||||||
against, project = doc.customer, doc.project
|
against, project = doc.customer, doc.project
|
||||||
credit_account, debit_account = item.income_account, item.deferred_revenue_account
|
credit_account, debit_account = item.income_account, item.deferred_revenue_account
|
||||||
@ -152,36 +152,62 @@ def book_deferred_income_or_expense(doc, start_date=None, end_date=None):
|
|||||||
against, project = doc.supplier, item.project
|
against, project = doc.supplier, item.project
|
||||||
credit_account, debit_account = item.deferred_expense_account, item.expense_account
|
credit_account, debit_account = item.deferred_expense_account, item.expense_account
|
||||||
|
|
||||||
# GL Entry for crediting the amount in the deferred expense
|
total_days = date_diff(item.service_end_date, item.service_start_date) + 1
|
||||||
gl_entries.append(
|
total_booking_days = date_diff(end_date, start_date) + 1
|
||||||
doc.get_gl_dict({
|
|
||||||
"account": credit_account,
|
amount, base_amount = calculate_amount(doc, item, last_gl_entry,
|
||||||
"against": against,
|
total_days, total_booking_days, account_currency)
|
||||||
"credit": base_amount,
|
|
||||||
"credit_in_account_currency": amount,
|
make_gl_entries(doc, credit_account, debit_account, against,
|
||||||
"cost_center": item.cost_center,
|
amount, base_amount, end_date, project, account_currency, item.cost_center, item.name)
|
||||||
"voucher_detail_no": item.name,
|
|
||||||
'posting_date': booking_end_date,
|
if getdate(end_date) < getdate(posting_date) and not last_gl_entry:
|
||||||
'project': project
|
_book_deferred_revenue_or_expense(item)
|
||||||
}, account_currency)
|
|
||||||
)
|
|
||||||
# GL Entry to debit the amount from the expense
|
for item in doc.get('items'):
|
||||||
gl_entries.append(
|
if item.get(enable_check):
|
||||||
doc.get_gl_dict({
|
_book_deferred_revenue_or_expense(item)
|
||||||
"account": debit_account,
|
|
||||||
"against": against,
|
def make_gl_entries(doc, credit_account, debit_account, against,
|
||||||
"debit": base_amount,
|
amount, base_amount, posting_date, project, account_currency, cost_center, voucher_detail_no):
|
||||||
"debit_in_account_currency": amount,
|
# GL Entry for crediting the amount in the deferred expense
|
||||||
"cost_center": item.cost_center,
|
from erpnext.accounts.general_ledger import make_gl_entries
|
||||||
"voucher_detail_no": item.name,
|
|
||||||
'posting_date': booking_end_date,
|
gl_entries = []
|
||||||
'project': project
|
gl_entries.append(
|
||||||
}, account_currency)
|
doc.get_gl_dict({
|
||||||
)
|
"account": credit_account,
|
||||||
|
"against": against,
|
||||||
|
"credit": base_amount,
|
||||||
|
"credit_in_account_currency": amount,
|
||||||
|
"cost_center": cost_center,
|
||||||
|
"voucher_detail_no": voucher_detail_no,
|
||||||
|
'posting_date': posting_date,
|
||||||
|
'project': project
|
||||||
|
}, account_currency)
|
||||||
|
)
|
||||||
|
# GL Entry to debit the amount from the expense
|
||||||
|
gl_entries.append(
|
||||||
|
doc.get_gl_dict({
|
||||||
|
"account": debit_account,
|
||||||
|
"against": against,
|
||||||
|
"debit": base_amount,
|
||||||
|
"debit_in_account_currency": amount,
|
||||||
|
"cost_center": cost_center,
|
||||||
|
"voucher_detail_no": voucher_detail_no,
|
||||||
|
'posting_date': posting_date,
|
||||||
|
'project': project
|
||||||
|
}, account_currency)
|
||||||
|
)
|
||||||
|
|
||||||
if gl_entries:
|
if gl_entries:
|
||||||
try:
|
try:
|
||||||
make_gl_entries(gl_entries, cancel=(doc.docstatus == 2), merge_entries=True)
|
make_gl_entries(gl_entries, cancel=(doc.docstatus == 2), merge_entries=True)
|
||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
except:
|
except:
|
||||||
frappe.db.rollback()
|
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)
|
ancestors = get_root_company(self.company)
|
||||||
if ancestors:
|
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]))
|
frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0]))
|
||||||
else:
|
else:
|
||||||
descendants = get_descendants_of('Company', self.company)
|
descendants = get_descendants_of('Company', self.company)
|
||||||
@ -110,6 +112,8 @@ class Account(NestedSet):
|
|||||||
["company", "name"], as_dict=True):
|
["company", "name"], as_dict=True):
|
||||||
acc_name_map[d["company"]] = d["name"]
|
acc_name_map[d["company"]] = d["name"]
|
||||||
|
|
||||||
|
if not acc_name_map: return
|
||||||
|
|
||||||
for company in descendants:
|
for company in descendants:
|
||||||
doc = frappe.copy_doc(self)
|
doc = frappe.copy_doc(self)
|
||||||
doc.flags.ignore_root_company_validation = True
|
doc.flags.ignore_root_company_validation = True
|
||||||
|
@ -23,6 +23,10 @@ frappe.treeview_settings["Account"] = {
|
|||||||
if(r.message) {
|
if(r.message) {
|
||||||
let root_company = r.message.length ? r.message[0] : "";
|
let root_company = r.message.length ? r.message[0] : "";
|
||||||
me.page.fields_dict.root_company.set_value(root_company);
|
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"),
|
label:__("Add Child"),
|
||||||
condition: function(node) {
|
condition: function(node) {
|
||||||
return frappe.boot.user.can_create.indexOf("Account") !== -1 &&
|
return frappe.boot.user.can_create.indexOf("Account") !== -1
|
||||||
!frappe.treeview_settings['Account'].treeview.page.fields_dict.root_company.get_value() &&
|
&& (!frappe.treeview_settings['Account'].treeview.page.fields_dict.root_company.get_value()
|
||||||
node.expandable && !node.hide_add;
|
|| frappe.flags.ignore_root_company_validation)
|
||||||
|
&& node.expandable && !node.hide_add;
|
||||||
},
|
},
|
||||||
click: function() {
|
click: function() {
|
||||||
var me = frappe.treeview_settings['Account'].treeview;
|
var me = frappe.treeview_settings['Account'].treeview;
|
||||||
|
@ -146,7 +146,7 @@ def _make_test_records(verbose):
|
|||||||
|
|
||||||
# related to Account Inventory Integration
|
# related to Account Inventory Integration
|
||||||
["_Test Account Stock In Hand", "Current Assets", 0, None, None],
|
["_Test Account Stock In Hand", "Current Assets", 0, None, None],
|
||||||
|
|
||||||
# fixed asset depreciation
|
# fixed asset depreciation
|
||||||
["_Test Fixed Asset", "Current Assets", 0, "Fixed Asset", None],
|
["_Test Fixed Asset", "Current Assets", 0, "Fixed Asset", None],
|
||||||
["_Test Accumulated Depreciations", "Current Assets", 0, None, None],
|
["_Test Accumulated Depreciations", "Current Assets", 0, None, None],
|
||||||
@ -183,13 +183,17 @@ def get_inventory_account(company, warehouse=None):
|
|||||||
return account
|
return account
|
||||||
|
|
||||||
def create_account(**kwargs):
|
def create_account(**kwargs):
|
||||||
account = frappe.get_doc(dict(
|
account = frappe.db.get_value("Account", filters={"account_name": kwargs.get("account_name"), "company": kwargs.get("company")})
|
||||||
doctype = "Account",
|
if account:
|
||||||
account_name = kwargs.get('account_name'),
|
return account
|
||||||
account_type = kwargs.get('account_type'),
|
else:
|
||||||
parent_account = kwargs.get('parent_account'),
|
account = frappe.get_doc(dict(
|
||||||
company = kwargs.get('company')
|
doctype = "Account",
|
||||||
))
|
account_name = kwargs.get('account_name'),
|
||||||
|
account_type = kwargs.get('account_type'),
|
||||||
account.save()
|
parent_account = kwargs.get('parent_account'),
|
||||||
return account.name
|
company = kwargs.get('company')
|
||||||
|
))
|
||||||
|
|
||||||
|
account.save()
|
||||||
|
return account.name
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
"columns": 0,
|
"columns": 0,
|
||||||
"default": "1",
|
"default": "1",
|
||||||
"description": "If enabled, the system will post accounting entries for inventory automatically.",
|
"description": "If enabled, the system will post accounting entries for inventory automatically.",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "auto_accounting_for_stock",
|
"fieldname": "auto_accounting_for_stock",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
@ -55,6 +56,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"description": "Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.",
|
"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",
|
"fieldname": "acc_frozen_upto",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -87,6 +89,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"description": "Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts",
|
"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",
|
"fieldname": "frozen_accounts_modifier",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -121,6 +124,7 @@
|
|||||||
"columns": 0,
|
"columns": 0,
|
||||||
"default": "Billing Address",
|
"default": "Billing Address",
|
||||||
"description": "Address used to determine Tax Category in transactions.",
|
"description": "Address used to determine Tax Category in transactions.",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "determine_address_tax_category_from",
|
"fieldname": "determine_address_tax_category_from",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -154,6 +158,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "column_break_4",
|
"fieldname": "column_break_4",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -186,6 +191,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"description": "Role that is allowed to submit transactions that exceed credit limits set.",
|
"description": "Role that is allowed to submit transactions that exceed credit limits set.",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "credit_controller",
|
"fieldname": "credit_controller",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -218,6 +224,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "check_supplier_invoice_uniqueness",
|
"fieldname": "check_supplier_invoice_uniqueness",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -250,6 +257,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "make_payment_via_journal_entry",
|
"fieldname": "make_payment_via_journal_entry",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -283,6 +291,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"default": "1",
|
"default": "1",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "unlink_payment_on_cancellation_of_invoice",
|
"fieldname": "unlink_payment_on_cancellation_of_invoice",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -316,6 +325,41 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"default": "1",
|
"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",
|
"fieldname": "book_asset_depreciation_entry_automatically",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -348,6 +392,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "allow_cost_center_in_entry_of_bs_account",
|
"fieldname": "allow_cost_center_in_entry_of_bs_account",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -381,6 +426,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"default": "1",
|
"default": "1",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "add_taxes_from_item_tax_template",
|
"fieldname": "add_taxes_from_item_tax_template",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -413,6 +459,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "print_settings",
|
"fieldname": "print_settings",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -445,6 +492,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "show_inclusive_tax_in_print",
|
"fieldname": "show_inclusive_tax_in_print",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -477,6 +525,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "column_break_12",
|
"fieldname": "column_break_12",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -508,6 +557,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "show_payment_schedule_in_print",
|
"fieldname": "show_payment_schedule_in_print",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -540,6 +590,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "currency_exchange_section",
|
"fieldname": "currency_exchange_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -573,6 +624,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"default": "1",
|
"default": "1",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "allow_stale",
|
"fieldname": "allow_stale",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -607,6 +659,7 @@
|
|||||||
"columns": 0,
|
"columns": 0,
|
||||||
"default": "1",
|
"default": "1",
|
||||||
"depends_on": "eval:doc.allow_stale==0",
|
"depends_on": "eval:doc.allow_stale==0",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "stale_days",
|
"fieldname": "stale_days",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -639,6 +692,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "report_settings_sb",
|
"fieldname": "report_settings_sb",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -673,6 +727,7 @@
|
|||||||
"columns": 0,
|
"columns": 0,
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"description": "Only select if you have setup Cash Flow Mapper documents",
|
"description": "Only select if you have setup Cash Flow Mapper documents",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "use_custom_cash_flow",
|
"fieldname": "use_custom_cash_flow",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -700,17 +755,15 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"has_web_view": 0,
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
"hide_toolbar": 0,
|
||||||
"icon": "icon-cog",
|
"icon": "icon-cog",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
"in_create": 0,
|
||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2019-01-07 00:42:34.510150",
|
"modified": "2019-04-06 12:28:43.026250",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Accounts Settings",
|
"name": "Accounts Settings",
|
||||||
@ -776,10 +829,9 @@
|
|||||||
],
|
],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
"show_name_in_global_search": 0,
|
||||||
"sort_order": "ASC",
|
"sort_order": "ASC",
|
||||||
"track_changes": 1,
|
"track_changes": 1,
|
||||||
"track_seen": 0,
|
"track_seen": 0,
|
||||||
"track_views": 0
|
"track_views": 0
|
||||||
}
|
}
|
@ -23,36 +23,36 @@ class BankReconciliation(Document):
|
|||||||
|
|
||||||
|
|
||||||
journal_entries = frappe.db.sql("""
|
journal_entries = frappe.db.sql("""
|
||||||
select
|
select
|
||||||
"Journal Entry" as payment_document, t1.name as payment_entry,
|
"Journal Entry" as payment_document, t1.name as payment_entry,
|
||||||
t1.cheque_no as cheque_number, t1.cheque_date,
|
t1.cheque_no as cheque_number, t1.cheque_date,
|
||||||
sum(t2.debit_in_account_currency) as debit, sum(t2.credit_in_account_currency) as credit,
|
sum(t2.debit_in_account_currency) as debit, sum(t2.credit_in_account_currency) as credit,
|
||||||
t1.posting_date, t2.against_account, t1.clearance_date, t2.account_currency
|
t1.posting_date, t2.against_account, t1.clearance_date, t2.account_currency
|
||||||
from
|
from
|
||||||
`tabJournal Entry` t1, `tabJournal Entry Account` t2
|
`tabJournal Entry` t1, `tabJournal Entry Account` t2
|
||||||
where
|
where
|
||||||
t2.parent = t1.name and t2.account = %s and t1.docstatus=1
|
t2.parent = t1.name and t2.account = %s and t1.docstatus=1
|
||||||
and t1.posting_date >= %s and t1.posting_date <= %s
|
and t1.posting_date >= %s and t1.posting_date <= %s
|
||||||
and ifnull(t1.is_opening, 'No') = 'No' {0}
|
and ifnull(t1.is_opening, 'No') = 'No' {0}
|
||||||
group by t2.account, t1.name
|
group by t2.account, t1.name
|
||||||
order by t1.posting_date ASC, t1.name DESC
|
order by t1.posting_date ASC, t1.name DESC
|
||||||
""".format(condition), (self.bank_account, self.from_date, self.to_date), as_dict=1)
|
""".format(condition), (self.bank_account, self.from_date, self.to_date), as_dict=1)
|
||||||
|
|
||||||
payment_entries = frappe.db.sql("""
|
payment_entries = frappe.db.sql("""
|
||||||
select
|
select
|
||||||
"Payment Entry" as payment_document, name as payment_entry,
|
"Payment Entry" as payment_document, name as payment_entry,
|
||||||
reference_no as cheque_number, reference_date as cheque_date,
|
reference_no as cheque_number, reference_date as cheque_date,
|
||||||
if(paid_from=%(account)s, paid_amount, "") as credit,
|
if(paid_from=%(account)s, paid_amount, 0) as credit,
|
||||||
if(paid_from=%(account)s, "", received_amount) as debit,
|
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,
|
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
|
if(paid_to=%(account)s, paid_to_account_currency, paid_from_account_currency) as account_currency
|
||||||
from `tabPayment Entry`
|
from `tabPayment Entry`
|
||||||
where
|
where
|
||||||
(paid_from=%(account)s or paid_to=%(account)s) and docstatus=1
|
(paid_from=%(account)s or paid_to=%(account)s) and docstatus=1
|
||||||
and posting_date >= %(from)s and posting_date <= %(to)s {0}
|
and posting_date >= %(from)s and posting_date <= %(to)s {0}
|
||||||
order by
|
order by
|
||||||
posting_date ASC, name DESC
|
posting_date ASC, name DESC
|
||||||
""".format(condition),
|
""".format(condition),
|
||||||
{"account":self.bank_account, "from":self.from_date, "to":self.to_date}, as_dict=1)
|
{"account":self.bank_account, "from":self.from_date, "to":self.to_date}, as_dict=1)
|
||||||
|
|
||||||
pos_entries = []
|
pos_entries = []
|
||||||
@ -79,8 +79,12 @@ class BankReconciliation(Document):
|
|||||||
|
|
||||||
for d in entries:
|
for d in entries:
|
||||||
row = self.append('payment_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("credit")
|
||||||
d.pop("debit")
|
d.pop("debit")
|
||||||
d.pop("account_currency")
|
d.pop("account_currency")
|
||||||
@ -103,10 +107,10 @@ class BankReconciliation(Document):
|
|||||||
d.clearance_date = None
|
d.clearance_date = None
|
||||||
|
|
||||||
frappe.db.set_value(d.payment_document, d.payment_entry, "clearance_date", d.clearance_date)
|
frappe.db.set_value(d.payment_document, d.payment_entry, "clearance_date", d.clearance_date)
|
||||||
frappe.db.sql("""update `tab{0}` set clearance_date = %s, modified = %s
|
frappe.db.sql("""update `tab{0}` set clearance_date = %s, modified = %s
|
||||||
where name=%s""".format(d.payment_document),
|
where name=%s""".format(d.payment_document),
|
||||||
(d.clearance_date, nowdate(), d.payment_entry))
|
(d.clearance_date, nowdate(), d.payment_entry))
|
||||||
|
|
||||||
clearance_date_updated = True
|
clearance_date_updated = True
|
||||||
|
|
||||||
if clearance_date_updated:
|
if clearance_date_updated:
|
||||||
|
@ -52,11 +52,6 @@ class JournalEntry(AccountsController):
|
|||||||
self.update_loan()
|
self.update_loan()
|
||||||
self.update_inter_company_jv()
|
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):
|
def get_title(self):
|
||||||
return self.pay_to_recd_from or self.accounts[0].account
|
return self.pay_to_recd_from or self.accounts[0].account
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import flt
|
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
from frappe.utils import (flt, add_months)
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
class MonthlyDistribution(Document):
|
class MonthlyDistribution(Document):
|
||||||
@ -25,3 +25,33 @@ class MonthlyDistribution(Document):
|
|||||||
if flt(total, 2) != 100.0:
|
if flt(total, 2) != 100.0:
|
||||||
frappe.throw(_("Percentage Allocation should be equal to 100%") + \
|
frappe.throw(_("Percentage Allocation should be equal to 100%") + \
|
||||||
" ({0}%)".format(str(flt(total, 2))))
|
" ({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_advance_paid()
|
||||||
self.update_expense_claim()
|
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):
|
def on_cancel(self):
|
||||||
self.setup_party_account_field()
|
self.setup_party_account_field()
|
||||||
@ -754,7 +749,7 @@ def get_outstanding_on_journal_entry(name):
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_reference_details(reference_doctype, reference_name, party_account_currency):
|
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)
|
ref_doc = frappe.get_doc(reference_doctype, reference_name)
|
||||||
company_currency = ref_doc.get("company_currency") or erpnext.get_company_currency(ref_doc.company)
|
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"):
|
if reference_doctype in ("Sales Invoice", "Purchase Invoice"):
|
||||||
outstanding_amount = ref_doc.get("outstanding_amount")
|
outstanding_amount = ref_doc.get("outstanding_amount")
|
||||||
|
bill_no = ref_doc.get("bill_no")
|
||||||
elif reference_doctype == "Expense Claim":
|
elif reference_doctype == "Expense Claim":
|
||||||
outstanding_amount = flt(ref_doc.get("total_sanctioned_amount")) \
|
outstanding_amount = flt(ref_doc.get("total_sanctioned_amount")) \
|
||||||
- flt(ref_doc.get("total_amount+reimbursed")) - flt(ref_doc.get("total_advance_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"),
|
"due_date": ref_doc.get("due_date"),
|
||||||
"total_amount": total_amount,
|
"total_amount": total_amount,
|
||||||
"outstanding_amount": outstanding_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):
|
def set_default_profile(pos_profile, company):
|
||||||
modified = now()
|
modified = now()
|
||||||
user = frappe.session.user
|
user = frappe.session.user
|
||||||
company = frappe.db.escape(company)
|
|
||||||
|
|
||||||
if pos_profile and company:
|
if pos_profile and company:
|
||||||
frappe.db.sql(""" update `tabPOS Profile User` pfu, `tabPOS Profile` pf
|
frappe.db.sql(""" update `tabPOS Profile User` pfu, `tabPOS Profile` pf
|
||||||
|
@ -119,7 +119,7 @@ class PricingRule(Document):
|
|||||||
#--------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def apply_pricing_rule(args):
|
def apply_pricing_rule(args, doc=None):
|
||||||
"""
|
"""
|
||||||
args = {
|
args = {
|
||||||
"items": [{"doctype": "", "name": "", "item_code": "", "brand": "", "item_group": ""}, ...],
|
"items": [{"doctype": "", "name": "", "item_code": "", "brand": "", "item_group": ""}, ...],
|
||||||
@ -139,6 +139,7 @@ def apply_pricing_rule(args):
|
|||||||
"ignore_pricing_rule": "something"
|
"ignore_pricing_rule": "something"
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if isinstance(args, string_types):
|
if isinstance(args, string_types):
|
||||||
args = json.loads(args)
|
args = json.loads(args)
|
||||||
|
|
||||||
@ -161,10 +162,11 @@ def apply_pricing_rule(args):
|
|||||||
for item in item_list:
|
for item in item_list:
|
||||||
args_copy = copy.deepcopy(args)
|
args_copy = copy.deepcopy(args)
|
||||||
args_copy.update(item)
|
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)
|
out.append(data)
|
||||||
if set_serial_nos_based_on_fifo and not args.get('is_return'):
|
if not item.get("serial_no") and set_serial_nos_based_on_fifo and not args.get('is_return'):
|
||||||
out.append(get_serial_no_for_item(args_copy))
|
out[0].update(get_serial_no_for_item(args_copy))
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def get_serial_no_for_item(args):
|
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):
|
def get_pricing_rule_for_item(args, price_list_rate=0, doc=None):
|
||||||
from erpnext.accounts.doctype.pricing_rule.utils import get_pricing_rules
|
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
|
if (args.get('is_free_item') or
|
||||||
args.get("parenttype") == "Material Request"): return {}
|
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:
|
if pricing_rules:
|
||||||
rules = []
|
rules = []
|
||||||
|
|
||||||
item_details.discount_percentage = 0
|
|
||||||
item_details.discount_amount = 0
|
|
||||||
for pricing_rule in pricing_rules:
|
for pricing_rule in pricing_rules:
|
||||||
if not pricing_rule or pricing_rule.get('suggestion'): continue
|
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))
|
rules.append(get_pricing_rule_details(args, pricing_rule))
|
||||||
if pricing_rule.mixed_conditions or pricing_rule.apply_rule_on_other:
|
if pricing_rule.mixed_conditions or pricing_rule.apply_rule_on_other:
|
||||||
continue
|
continue
|
||||||
@ -243,8 +251,8 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None):
|
|||||||
item_details.has_pricing_rule = 1
|
item_details.has_pricing_rule = 1
|
||||||
|
|
||||||
# if discount is applied on the rate and not on price list rate
|
# if discount is applied on the rate and not on price list rate
|
||||||
if price_list_rate:
|
# if price_list_rate:
|
||||||
set_discount_amount(price_list_rate, item_details)
|
# set_discount_amount(price_list_rate, item_details)
|
||||||
|
|
||||||
item_details.pricing_rules = ','.join([d.pricing_rule for d in rules])
|
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,
|
'pricing_rule': pricing_rule.name,
|
||||||
'rate_or_discount': pricing_rule.rate_or_discount,
|
'rate_or_discount': pricing_rule.rate_or_discount,
|
||||||
'margin_type': pricing_rule.margin_type,
|
'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')
|
'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)
|
discount_field = "{0}_on_rate".format(field)
|
||||||
item_details[discount_field].append(pricing_rule.get(field, 0))
|
item_details[discount_field].append(pricing_rule.get(field, 0))
|
||||||
else:
|
else:
|
||||||
|
if field not in item_details:
|
||||||
|
item_details.setdefault(field, 0)
|
||||||
|
|
||||||
item_details[field] += (pricing_rule.get(field, 0)
|
item_details[field] += (pricing_rule.get(field, 0)
|
||||||
if pricing_rule else args.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
|
item_details.rate = rate
|
||||||
|
|
||||||
def remove_pricing_rule_for_item(pricing_rules, item_details, item_code=None):
|
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(','):
|
for d in pricing_rules.split(','):
|
||||||
if not d: continue
|
if not d: continue
|
||||||
pricing_rule = frappe.get_doc('Pricing Rule', d)
|
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')
|
item_details.remove_free_item = (item_code if pricing_rule.get('same_item')
|
||||||
else pricing_rule.get('free_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 = ''
|
item_details.pricing_rules = ''
|
||||||
|
|
||||||
return item_details
|
return item_details
|
||||||
@ -368,35 +385,6 @@ def make_pricing_rule(doctype, docname):
|
|||||||
|
|
||||||
return doc
|
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):
|
def get_item_uoms(doctype, txt, searchfield, start, page_len, filters):
|
||||||
items = [filters.get('value')]
|
items = [filters.get('value')]
|
||||||
if filters.get('apply_on') != 'Item Code':
|
if filters.get('apply_on') != 'Item Code':
|
||||||
|
@ -4,490 +4,531 @@
|
|||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe, copy, json
|
||||||
import json
|
|
||||||
import copy
|
|
||||||
from frappe import throw, _
|
from frappe import throw, _
|
||||||
|
from six import string_types
|
||||||
from frappe.utils import flt, cint, get_datetime
|
from frappe.utils import flt, cint, get_datetime
|
||||||
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
|
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
|
||||||
from erpnext.stock.get_item_details import get_conversion_factor
|
from erpnext.stock.get_item_details import get_conversion_factor
|
||||||
|
|
||||||
class MultiplePricingRuleConflict(frappe.ValidationError): pass
|
class MultiplePricingRuleConflict(frappe.ValidationError): pass
|
||||||
|
|
||||||
|
apply_on_table = {
|
||||||
|
'Item Code': 'items',
|
||||||
|
'Item Group': 'item_groups',
|
||||||
|
'Brand': 'brands'
|
||||||
|
}
|
||||||
|
|
||||||
def get_pricing_rules(args, doc=None):
|
def get_pricing_rules(args, doc=None):
|
||||||
pricing_rules = []
|
pricing_rules = []
|
||||||
values = {}
|
values = {}
|
||||||
|
|
||||||
for apply_on in ['Item Code', 'Item Group', 'Brand']:
|
for apply_on in ['Item Code', 'Item Group', 'Brand']:
|
||||||
pricing_rules.extend(_get_pricing_rules(apply_on, args, values))
|
pricing_rules.extend(_get_pricing_rules(apply_on, args, values))
|
||||||
if pricing_rules and not apply_multiple_pricing_rules(pricing_rules):
|
if pricing_rules and not apply_multiple_pricing_rules(pricing_rules):
|
||||||
break
|
break
|
||||||
|
|
||||||
rules = []
|
rules = []
|
||||||
|
|
||||||
if not pricing_rules: return []
|
if not pricing_rules: return []
|
||||||
|
|
||||||
if apply_multiple_pricing_rules(pricing_rules):
|
if apply_multiple_pricing_rules(pricing_rules):
|
||||||
for pricing_rule in pricing_rules:
|
for pricing_rule in pricing_rules:
|
||||||
pricing_rule = filter_pricing_rules(args, pricing_rule, doc)
|
pricing_rule = filter_pricing_rules(args, pricing_rule, doc)
|
||||||
if pricing_rule:
|
if pricing_rule:
|
||||||
rules.append(pricing_rule)
|
rules.append(pricing_rule)
|
||||||
else:
|
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
|
return rules
|
||||||
|
|
||||||
def _get_pricing_rules(apply_on, args, values):
|
def _get_pricing_rules(apply_on, args, values):
|
||||||
apply_on_field = frappe.scrub(apply_on)
|
apply_on_field = frappe.scrub(apply_on)
|
||||||
|
|
||||||
if not args.get(apply_on_field): return []
|
if not args.get(apply_on_field): return []
|
||||||
|
|
||||||
child_doc = '`tabPricing Rule {0}`'.format(apply_on)
|
child_doc = '`tabPricing Rule {0}`'.format(apply_on)
|
||||||
|
|
||||||
conditions = item_variant_condition = item_conditions = ""
|
conditions = item_variant_condition = item_conditions = ""
|
||||||
values[apply_on_field] = args.get(apply_on_field)
|
values[apply_on_field] = args.get(apply_on_field)
|
||||||
if apply_on_field in ['item_code', 'brand']:
|
if apply_on_field in ['item_code', 'brand']:
|
||||||
item_conditions = "{child_doc}.{apply_on_field}= %({apply_on_field})s".format(child_doc=child_doc,
|
item_conditions = "{child_doc}.{apply_on_field}= %({apply_on_field})s".format(child_doc=child_doc,
|
||||||
apply_on_field = apply_on_field)
|
apply_on_field = apply_on_field)
|
||||||
|
|
||||||
if apply_on_field == 'item_code':
|
if apply_on_field == 'item_code':
|
||||||
if "variant_of" not in args:
|
if "variant_of" not in args:
|
||||||
args.variant_of = frappe.get_cached_value("Item", args.item_code, "variant_of")
|
args.variant_of = frappe.get_cached_value("Item", args.item_code, "variant_of")
|
||||||
|
|
||||||
if args.variant_of:
|
if args.variant_of:
|
||||||
item_variant_condition = ' or {child_doc}.item_code=%(variant_of)s '.format(child_doc=child_doc)
|
item_variant_condition = ' or {child_doc}.item_code=%(variant_of)s '.format(child_doc=child_doc)
|
||||||
values['variant_of'] = args.variant_of
|
values['variant_of'] = args.variant_of
|
||||||
elif apply_on_field == 'item_group':
|
elif apply_on_field == 'item_group':
|
||||||
item_conditions = _get_tree_conditions(args, "Item Group", child_doc, False)
|
item_conditions = _get_tree_conditions(args, "Item Group", child_doc, False)
|
||||||
|
|
||||||
conditions += get_other_conditions(conditions, values, args)
|
conditions += get_other_conditions(conditions, values, args)
|
||||||
warehouse_conditions = _get_tree_conditions(args, "Warehouse", '`tabPricing Rule`')
|
warehouse_conditions = _get_tree_conditions(args, "Warehouse", '`tabPricing Rule`')
|
||||||
if warehouse_conditions:
|
if warehouse_conditions:
|
||||||
warehouse_conditions = " and {0}".format(warehouse_conditions)
|
warehouse_conditions = " and {0}".format(warehouse_conditions)
|
||||||
|
|
||||||
if not args.price_list: args.price_list = None
|
if not args.price_list: args.price_list = None
|
||||||
|
|
||||||
conditions += " and ifnull(`tabPricing Rule`.for_price_list, '') in (%(price_list)s, '')"
|
conditions += " and ifnull(`tabPricing Rule`.for_price_list, '') in (%(price_list)s, '')"
|
||||||
values["price_list"] = args.get("price_list")
|
values["price_list"] = args.get("price_list")
|
||||||
|
|
||||||
pricing_rules = frappe.db.sql("""select `tabPricing Rule`.*,
|
pricing_rules = frappe.db.sql("""select `tabPricing Rule`.*,
|
||||||
{child_doc}.{apply_on_field}, {child_doc}.uom
|
{child_doc}.{apply_on_field}, {child_doc}.uom
|
||||||
from `tabPricing Rule`, {child_doc}
|
from `tabPricing Rule`, {child_doc}
|
||||||
where ({item_conditions} or (`tabPricing Rule`.apply_rule_on_other is not null
|
where ({item_conditions} or (`tabPricing Rule`.apply_rule_on_other is not null
|
||||||
and `tabPricing Rule`.{apply_on_other_field}=%({apply_on_field})s) {item_variant_condition})
|
and `tabPricing Rule`.{apply_on_other_field}=%({apply_on_field})s) {item_variant_condition})
|
||||||
and {child_doc}.parent = `tabPricing Rule`.name
|
and {child_doc}.parent = `tabPricing Rule`.name
|
||||||
and `tabPricing Rule`.disable = 0 and
|
and `tabPricing Rule`.disable = 0 and
|
||||||
`tabPricing Rule`.{transaction_type} = 1 {warehouse_cond} {conditions}
|
`tabPricing Rule`.{transaction_type} = 1 {warehouse_cond} {conditions}
|
||||||
order by `tabPricing Rule`.priority desc,
|
order by `tabPricing Rule`.priority desc,
|
||||||
`tabPricing Rule`.name desc""".format(
|
`tabPricing Rule`.name desc""".format(
|
||||||
child_doc = child_doc,
|
child_doc = child_doc,
|
||||||
apply_on_field = apply_on_field,
|
apply_on_field = apply_on_field,
|
||||||
item_conditions = item_conditions,
|
item_conditions = item_conditions,
|
||||||
item_variant_condition = item_variant_condition,
|
item_variant_condition = item_variant_condition,
|
||||||
transaction_type = args.transaction_type,
|
transaction_type = args.transaction_type,
|
||||||
warehouse_cond = warehouse_conditions,
|
warehouse_cond = warehouse_conditions,
|
||||||
apply_on_other_field = "other_{0}".format(apply_on_field),
|
apply_on_other_field = "other_{0}".format(apply_on_field),
|
||||||
conditions = conditions), values, as_dict=1) or []
|
conditions = conditions), values, as_dict=1) or []
|
||||||
|
|
||||||
return pricing_rules
|
return pricing_rules
|
||||||
|
|
||||||
def apply_multiple_pricing_rules(pricing_rules):
|
def apply_multiple_pricing_rules(pricing_rules):
|
||||||
apply_multiple_rule = [d.apply_multiple_pricing_rules
|
apply_multiple_rule = [d.apply_multiple_pricing_rules
|
||||||
for d in pricing_rules if d.apply_multiple_pricing_rules]
|
for d in pricing_rules if d.apply_multiple_pricing_rules]
|
||||||
|
|
||||||
if not apply_multiple_rule: return False
|
if not apply_multiple_rule: return False
|
||||||
|
|
||||||
if (apply_multiple_rule
|
if (apply_multiple_rule
|
||||||
and len(apply_multiple_rule) == len(pricing_rules)):
|
and len(apply_multiple_rule) == len(pricing_rules)):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _get_tree_conditions(args, parenttype, table, allow_blank=True):
|
def _get_tree_conditions(args, parenttype, table, allow_blank=True):
|
||||||
field = frappe.scrub(parenttype)
|
field = frappe.scrub(parenttype)
|
||||||
condition = ""
|
condition = ""
|
||||||
if args.get(field):
|
if args.get(field):
|
||||||
if not frappe.flags.tree_conditions:
|
if not frappe.flags.tree_conditions:
|
||||||
frappe.flags.tree_conditions = {}
|
frappe.flags.tree_conditions = {}
|
||||||
key = (parenttype, args.get(field))
|
key = (parenttype, args.get(field))
|
||||||
if key in frappe.flags.tree_conditions:
|
if key in frappe.flags.tree_conditions:
|
||||||
return frappe.flags.tree_conditions[key]
|
return frappe.flags.tree_conditions[key]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
lft, rgt = frappe.db.get_value(parenttype, args.get(field), ["lft", "rgt"])
|
lft, rgt = frappe.db.get_value(parenttype, args.get(field), ["lft", "rgt"])
|
||||||
except TypeError:
|
except TypeError:
|
||||||
frappe.throw(_("Invalid {0}").format(args.get(field)))
|
frappe.throw(_("Invalid {0}").format(args.get(field)))
|
||||||
|
|
||||||
parent_groups = frappe.db.sql_list("""select name from `tab%s`
|
parent_groups = frappe.db.sql_list("""select name from `tab%s`
|
||||||
where lft<=%s and rgt>=%s""" % (parenttype, '%s', '%s'), (lft, rgt))
|
where lft<=%s and rgt>=%s""" % (parenttype, '%s', '%s'), (lft, rgt))
|
||||||
|
|
||||||
if parent_groups:
|
if parent_groups:
|
||||||
if allow_blank: parent_groups.append('')
|
if allow_blank: parent_groups.append('')
|
||||||
condition = "ifnull({table}.{field}, '') in ({parent_groups})".format(
|
condition = "ifnull({table}.{field}, '') in ({parent_groups})".format(
|
||||||
table=table,
|
table=table,
|
||||||
field=field,
|
field=field,
|
||||||
parent_groups=", ".join([frappe.db.escape(d) for d in parent_groups])
|
parent_groups=", ".join([frappe.db.escape(d) for d in parent_groups])
|
||||||
)
|
)
|
||||||
|
|
||||||
frappe.flags.tree_conditions[key] = condition
|
frappe.flags.tree_conditions[key] = condition
|
||||||
return condition
|
return condition
|
||||||
|
|
||||||
def get_other_conditions(conditions, values, args):
|
def get_other_conditions(conditions, values, args):
|
||||||
for field in ["company", "customer", "supplier", "campaign", "sales_partner"]:
|
for field in ["company", "customer", "supplier", "campaign", "sales_partner"]:
|
||||||
if args.get(field):
|
if args.get(field):
|
||||||
conditions += " and ifnull(`tabPricing Rule`.{0}, '') in (%({1})s, '')".format(field, field)
|
conditions += " and ifnull(`tabPricing Rule`.{0}, '') in (%({1})s, '')".format(field, field)
|
||||||
values[field] = args.get(field)
|
values[field] = args.get(field)
|
||||||
else:
|
else:
|
||||||
conditions += " and ifnull(`tabPricing Rule`.{0}, '') = ''".format(field)
|
conditions += " and ifnull(`tabPricing Rule`.{0}, '') = ''".format(field)
|
||||||
|
|
||||||
for parenttype in ["Customer Group", "Territory", "Supplier Group"]:
|
for parenttype in ["Customer Group", "Territory", "Supplier Group"]:
|
||||||
group_condition = _get_tree_conditions(args, parenttype, '`tabPricing Rule`')
|
group_condition = _get_tree_conditions(args, parenttype, '`tabPricing Rule`')
|
||||||
if group_condition:
|
if group_condition:
|
||||||
conditions += " and " + group_condition
|
conditions += " and " + group_condition
|
||||||
|
|
||||||
if args.get("transaction_date"):
|
if args.get("transaction_date"):
|
||||||
conditions += """ and %(transaction_date)s between ifnull(`tabPricing Rule`.valid_from, '2000-01-01')
|
conditions += """ and %(transaction_date)s between ifnull(`tabPricing Rule`.valid_from, '2000-01-01')
|
||||||
and ifnull(`tabPricing Rule`.valid_upto, '2500-12-31')"""
|
and ifnull(`tabPricing Rule`.valid_upto, '2500-12-31')"""
|
||||||
values['transaction_date'] = args.get('transaction_date')
|
values['transaction_date'] = args.get('transaction_date')
|
||||||
|
|
||||||
return conditions
|
return conditions
|
||||||
|
|
||||||
def filter_pricing_rules(args, pricing_rules, doc=None):
|
def filter_pricing_rules(args, pricing_rules, doc=None):
|
||||||
if not isinstance(pricing_rules, list):
|
if not isinstance(pricing_rules, list):
|
||||||
pricing_rules = [pricing_rules]
|
pricing_rules = [pricing_rules]
|
||||||
|
|
||||||
original_pricing_rule = copy.copy(pricing_rules)
|
original_pricing_rule = copy.copy(pricing_rules)
|
||||||
|
|
||||||
# filter for qty
|
# filter for qty
|
||||||
if pricing_rules:
|
if pricing_rules:
|
||||||
stock_qty = flt(args.get('stock_qty'))
|
stock_qty = flt(args.get('stock_qty'))
|
||||||
amount = flt(args.get('price_list_rate')) * flt(args.get('qty'))
|
amount = flt(args.get('price_list_rate')) * flt(args.get('qty'))
|
||||||
|
|
||||||
if pricing_rules[0].apply_rule_on_other:
|
if pricing_rules[0].apply_rule_on_other:
|
||||||
field = frappe.scrub(pricing_rules[0].apply_rule_on_other)
|
field = frappe.scrub(pricing_rules[0].apply_rule_on_other)
|
||||||
|
|
||||||
if (field and pricing_rules[0].get('other_' + field) != args.get(field)): return
|
if (field and pricing_rules[0].get('other_' + field) != args.get(field)): return
|
||||||
|
|
||||||
pr_doc = frappe.get_doc('Pricing Rule', pricing_rules[0].name)
|
pr_doc = frappe.get_doc('Pricing Rule', pricing_rules[0].name)
|
||||||
|
|
||||||
if pricing_rules[0].mixed_conditions and doc:
|
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:
|
elif pricing_rules[0].is_cumulative:
|
||||||
items = [args.get(frappe.scrub(pr_doc.get('apply_on')))]
|
items = [args.get(frappe.scrub(pr_doc.get('apply_on')))]
|
||||||
data = get_qty_amount_data_for_cumulative(pr_doc, args, items)
|
data = get_qty_amount_data_for_cumulative(pr_doc, args, items)
|
||||||
|
|
||||||
if data:
|
if data:
|
||||||
stock_qty += data[0]
|
stock_qty += data[0]
|
||||||
amount += data[1]
|
amount += data[1]
|
||||||
|
|
||||||
if pricing_rules[0].apply_rule_on_other and not pricing_rules[0].mixed_conditions and doc:
|
if pricing_rules[0].apply_rule_on_other and not pricing_rules[0].mixed_conditions and doc:
|
||||||
pricing_rules = get_qty_and_rate_for_other_item(doc, pr_doc, pricing_rules) or []
|
pricing_rules = get_qty_and_rate_for_other_item(doc, pr_doc, pricing_rules) or []
|
||||||
else:
|
else:
|
||||||
pricing_rules = filter_pricing_rules_for_qty_amount(stock_qty, amount, pricing_rules, args)
|
pricing_rules = filter_pricing_rules_for_qty_amount(stock_qty, amount, pricing_rules, args)
|
||||||
|
|
||||||
if not pricing_rules:
|
if not pricing_rules:
|
||||||
for d in original_pricing_rule:
|
for d in original_pricing_rule:
|
||||||
if not d.threshold_percentage: continue
|
if not d.threshold_percentage: continue
|
||||||
|
|
||||||
msg = validate_quantity_and_amount_for_suggestion(d, stock_qty,
|
msg = validate_quantity_and_amount_for_suggestion(d, stock_qty,
|
||||||
amount, args.get('item_code'), args.get('transaction_type'))
|
amount, args.get('item_code'), args.get('transaction_type'))
|
||||||
|
|
||||||
if msg:
|
if msg:
|
||||||
return {'suggestion': msg, 'item_code': args.get('item_code')}
|
return {'suggestion': msg, 'item_code': args.get('item_code')}
|
||||||
|
|
||||||
# add variant_of property in pricing rule
|
# add variant_of property in pricing rule
|
||||||
for p in pricing_rules:
|
for p in pricing_rules:
|
||||||
if p.item_code and args.variant_of:
|
if p.item_code and args.variant_of:
|
||||||
p.variant_of = args.variant_of
|
p.variant_of = args.variant_of
|
||||||
else:
|
else:
|
||||||
p.variant_of = None
|
p.variant_of = None
|
||||||
|
|
||||||
# find pricing rule with highest priority
|
# find pricing rule with highest priority
|
||||||
if pricing_rules:
|
if pricing_rules:
|
||||||
max_priority = max([cint(p.priority) for p in pricing_rules])
|
max_priority = max([cint(p.priority) for p in pricing_rules])
|
||||||
if max_priority:
|
if max_priority:
|
||||||
pricing_rules = list(filter(lambda x: cint(x.priority)==max_priority, pricing_rules))
|
pricing_rules = list(filter(lambda x: cint(x.priority)==max_priority, pricing_rules))
|
||||||
|
|
||||||
# apply internal priority
|
# apply internal priority
|
||||||
all_fields = ["item_code", "item_group", "brand", "customer", "customer_group", "territory",
|
all_fields = ["item_code", "item_group", "brand", "customer", "customer_group", "territory",
|
||||||
"supplier", "supplier_group", "campaign", "sales_partner", "variant_of"]
|
"supplier", "supplier_group", "campaign", "sales_partner", "variant_of"]
|
||||||
|
|
||||||
if len(pricing_rules) > 1:
|
if len(pricing_rules) > 1:
|
||||||
for field_set in [["item_code", "variant_of", "item_group", "brand"],
|
for field_set in [["item_code", "variant_of", "item_group", "brand"],
|
||||||
["customer", "customer_group", "territory"], ["supplier", "supplier_group"]]:
|
["customer", "customer_group", "territory"], ["supplier", "supplier_group"]]:
|
||||||
remaining_fields = list(set(all_fields) - set(field_set))
|
remaining_fields = list(set(all_fields) - set(field_set))
|
||||||
if if_all_rules_same(pricing_rules, remaining_fields):
|
if if_all_rules_same(pricing_rules, remaining_fields):
|
||||||
pricing_rules = apply_internal_priority(pricing_rules, field_set, args)
|
pricing_rules = apply_internal_priority(pricing_rules, field_set, args)
|
||||||
break
|
break
|
||||||
|
|
||||||
if pricing_rules and not isinstance(pricing_rules, list):
|
if pricing_rules and not isinstance(pricing_rules, list):
|
||||||
pricing_rules = list(pricing_rules)
|
pricing_rules = list(pricing_rules)
|
||||||
|
|
||||||
if len(pricing_rules) > 1:
|
if len(pricing_rules) > 1:
|
||||||
rate_or_discount = list(set([d.rate_or_discount for d in pricing_rules]))
|
rate_or_discount = list(set([d.rate_or_discount for d in pricing_rules]))
|
||||||
if len(rate_or_discount) == 1 and rate_or_discount[0] == "Discount Percentage":
|
if len(rate_or_discount) == 1 and rate_or_discount[0] == "Discount Percentage":
|
||||||
pricing_rules = filter(lambda x: x.for_price_list==args.price_list, pricing_rules) \
|
pricing_rules = filter(lambda x: x.for_price_list==args.price_list, pricing_rules) \
|
||||||
or pricing_rules
|
or pricing_rules
|
||||||
|
|
||||||
if len(pricing_rules) > 1 and not args.for_shopping_cart:
|
if len(pricing_rules) > 1 and not args.for_shopping_cart:
|
||||||
frappe.throw(_("Multiple Price Rules exists with same criteria, please resolve conflict by assigning priority. Price Rules: {0}")
|
frappe.throw(_("Multiple Price Rules exists with same criteria, please resolve conflict by assigning priority. Price Rules: {0}")
|
||||||
.format("\n".join([d.name for d in pricing_rules])), MultiplePricingRuleConflict)
|
.format("\n".join([d.name for d in pricing_rules])), MultiplePricingRuleConflict)
|
||||||
elif pricing_rules:
|
elif pricing_rules:
|
||||||
return pricing_rules[0]
|
return pricing_rules[0]
|
||||||
|
|
||||||
def validate_quantity_and_amount_for_suggestion(args, qty, amount, item_code, transaction_type):
|
def validate_quantity_and_amount_for_suggestion(args, qty, amount, item_code, transaction_type):
|
||||||
fieldname, msg = '', ''
|
fieldname, msg = '', ''
|
||||||
type_of_transaction = 'purcahse' if transaction_type == "buying" else "sale"
|
type_of_transaction = 'purcahse' if transaction_type == "buying" else "sale"
|
||||||
|
|
||||||
for field, value in {'min_qty': qty, 'min_amt': amount}.items():
|
for field, value in {'min_qty': qty, 'min_amt': amount}.items():
|
||||||
if (args.get(field) and value < args.get(field)
|
if (args.get(field) and value < args.get(field)
|
||||||
and (args.get(field) - cint(args.get(field) * args.threshold_percentage * 0.01)) <= value):
|
and (args.get(field) - cint(args.get(field) * args.threshold_percentage * 0.01)) <= value):
|
||||||
fieldname = field
|
fieldname = field
|
||||||
|
|
||||||
for field, value in {'max_qty': qty, 'max_amt': amount}.items():
|
for field, value in {'max_qty': qty, 'max_amt': amount}.items():
|
||||||
if (args.get(field) and value > args.get(field)
|
if (args.get(field) and value > args.get(field)
|
||||||
and (args.get(field) + cint(args.get(field) * args.threshold_percentage * 0.01)) >= value):
|
and (args.get(field) + cint(args.get(field) * args.threshold_percentage * 0.01)) >= value):
|
||||||
fieldname = field
|
fieldname = field
|
||||||
|
|
||||||
if fieldname:
|
if fieldname:
|
||||||
msg = _("""If you {0} {1} quantities of the item <b>{2}</b>, the scheme <b>{3}</b>
|
msg = _("""If you {0} {1} quantities of the item <b>{2}</b>, the scheme <b>{3}</b>
|
||||||
will be applied on the item.""").format(type_of_transaction, args.get(fieldname), item_code, args.rule_description)
|
will be applied on the item.""").format(type_of_transaction, args.get(fieldname), item_code, args.rule_description)
|
||||||
|
|
||||||
if fieldname in ['min_amt', 'max_amt']:
|
if fieldname in ['min_amt', 'max_amt']:
|
||||||
msg = _("""If you {0} {1} worth item <b>{2}</b>, the scheme <b>{3}</b> will be applied on the item.
|
msg = _("""If you {0} {1} worth item <b>{2}</b>, the scheme <b>{3}</b> will be applied on the item.
|
||||||
""").format(frappe.fmt_money(type_of_transaction, args.get(fieldname)), item_code, args.rule_description)
|
""").format(frappe.fmt_money(type_of_transaction, args.get(fieldname)), item_code, args.rule_description)
|
||||||
|
|
||||||
frappe.msgprint(msg)
|
frappe.msgprint(msg)
|
||||||
|
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
def filter_pricing_rules_for_qty_amount(qty, rate, pricing_rules, args=None):
|
def filter_pricing_rules_for_qty_amount(qty, rate, pricing_rules, args=None):
|
||||||
rules = []
|
rules = []
|
||||||
|
|
||||||
for rule in pricing_rules:
|
for rule in pricing_rules:
|
||||||
status = False
|
status = False
|
||||||
conversion_factor = 1
|
conversion_factor = 1
|
||||||
|
|
||||||
if rule.get("uom"):
|
if rule.get("uom"):
|
||||||
conversion_factor = get_conversion_factor(rule.item_code, rule.uom).get("conversion_factor", 1)
|
conversion_factor = get_conversion_factor(rule.item_code, rule.uom).get("conversion_factor", 1)
|
||||||
|
|
||||||
if (flt(qty) >= (flt(rule.min_qty) * conversion_factor)
|
if (flt(qty) >= (flt(rule.min_qty) * conversion_factor)
|
||||||
and (flt(qty)<= (rule.max_qty * conversion_factor) if rule.max_qty else True)):
|
and (flt(qty)<= (rule.max_qty * conversion_factor) if rule.max_qty else True)):
|
||||||
status = True
|
status = True
|
||||||
|
|
||||||
# if user has created item price against the transaction UOM
|
# if user has created item price against the transaction UOM
|
||||||
if rule.get("uom") == args.get("uom"):
|
if rule.get("uom") == args.get("uom"):
|
||||||
conversion_factor = 1.0
|
conversion_factor = 1.0
|
||||||
|
|
||||||
if status and (flt(rate) >= (flt(rule.min_amt) * conversion_factor)
|
if status and (flt(rate) >= (flt(rule.min_amt) * conversion_factor)
|
||||||
and (flt(rate)<= (rule.max_amt * conversion_factor) if rule.max_amt else True)):
|
and (flt(rate)<= (rule.max_amt * conversion_factor) if rule.max_amt else True)):
|
||||||
status = True
|
status = True
|
||||||
else:
|
else:
|
||||||
status = False
|
status = False
|
||||||
|
|
||||||
if status:
|
if status:
|
||||||
rules.append(rule)
|
rules.append(rule)
|
||||||
|
|
||||||
return rules
|
return rules
|
||||||
|
|
||||||
def if_all_rules_same(pricing_rules, fields):
|
def if_all_rules_same(pricing_rules, fields):
|
||||||
all_rules_same = True
|
all_rules_same = True
|
||||||
val = [pricing_rules[0].get(k) for k in fields]
|
val = [pricing_rules[0].get(k) for k in fields]
|
||||||
for p in pricing_rules[1:]:
|
for p in pricing_rules[1:]:
|
||||||
if val != [p.get(k) for k in fields]:
|
if val != [p.get(k) for k in fields]:
|
||||||
all_rules_same = False
|
all_rules_same = False
|
||||||
break
|
break
|
||||||
|
|
||||||
return all_rules_same
|
return all_rules_same
|
||||||
|
|
||||||
def apply_internal_priority(pricing_rules, field_set, args):
|
def apply_internal_priority(pricing_rules, field_set, args):
|
||||||
filtered_rules = []
|
filtered_rules = []
|
||||||
for field in field_set:
|
for field in field_set:
|
||||||
if args.get(field):
|
if args.get(field):
|
||||||
filtered_rules = filter(lambda x: x[field]==args[field], pricing_rules)
|
filtered_rules = filter(lambda x: x[field]==args[field], pricing_rules)
|
||||||
if filtered_rules: break
|
if filtered_rules: break
|
||||||
|
|
||||||
return filtered_rules or pricing_rules
|
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]
|
sum_qty, sum_amt = [0, 0]
|
||||||
items = get_pricing_rule_items(pr_doc) or []
|
items = get_pricing_rule_items(pr_doc) or []
|
||||||
apply_on = frappe.scrub(pr_doc.get('apply_on'))
|
apply_on = frappe.scrub(pr_doc.get('apply_on'))
|
||||||
|
|
||||||
if items and doc.get("items"):
|
if items and doc.get("items"):
|
||||||
for row in doc.get('items'):
|
for row in doc.get('items'):
|
||||||
if row.get(apply_on) not in items: continue
|
if row.get(apply_on) not in items: continue
|
||||||
|
|
||||||
if pr_doc.mixed_conditions:
|
if pr_doc.mixed_conditions:
|
||||||
sum_qty += row.stock_qty
|
amt = args.get('qty') * args.get("price_list_rate")
|
||||||
sum_amt += row.amount
|
if args.get("item_code") != row.get("item_code"):
|
||||||
|
amt = row.get('qty') * row.get("price_list_rate")
|
||||||
|
|
||||||
if pr_doc.is_cumulative:
|
sum_qty += row.get("stock_qty") or args.get("stock_qty")
|
||||||
data = get_qty_amount_data_for_cumulative(pr_doc, doc, items)
|
sum_amt += amt
|
||||||
|
|
||||||
if data and data[0]:
|
if pr_doc.is_cumulative:
|
||||||
sum_qty += data[0]
|
data = get_qty_amount_data_for_cumulative(pr_doc, doc, items)
|
||||||
sum_amt += data[1]
|
|
||||||
|
|
||||||
return sum_qty, sum_amt
|
if data and data[0]:
|
||||||
|
sum_qty += data[0]
|
||||||
|
sum_amt += data[1]
|
||||||
|
|
||||||
|
return sum_qty, sum_amt
|
||||||
|
|
||||||
def get_qty_and_rate_for_other_item(doc, pr_doc, pricing_rules):
|
def get_qty_and_rate_for_other_item(doc, pr_doc, pricing_rules):
|
||||||
for d in get_pricing_rule_items(pr_doc):
|
for d in get_pricing_rule_items(pr_doc):
|
||||||
for row in doc.items:
|
for row in doc.items:
|
||||||
if d == row.get(frappe.scrub(pr_doc.apply_on)):
|
if d == row.get(frappe.scrub(pr_doc.apply_on)):
|
||||||
pricing_rules = filter_pricing_rules_for_qty_amount(row.stock_qty,
|
pricing_rules = filter_pricing_rules_for_qty_amount(row.get("stock_qty"),
|
||||||
row.amount, pricing_rules, row)
|
row.get("amount"), pricing_rules, row)
|
||||||
|
|
||||||
if pricing_rules and pricing_rules[0]:
|
if pricing_rules and pricing_rules[0]:
|
||||||
return pricing_rules
|
return pricing_rules
|
||||||
|
|
||||||
def get_qty_amount_data_for_cumulative(pr_doc, doc, items=[]):
|
def get_qty_amount_data_for_cumulative(pr_doc, doc, items=[]):
|
||||||
sum_qty, sum_amt = [0, 0]
|
sum_qty, sum_amt = [0, 0]
|
||||||
doctype = doc.get('parenttype') or doc.doctype
|
doctype = doc.get('parenttype') or doc.doctype
|
||||||
|
|
||||||
date_field = ('transaction_date'
|
date_field = ('transaction_date'
|
||||||
if doc.get('transaction_date') else 'posting_date')
|
if doc.get('transaction_date') else 'posting_date')
|
||||||
|
|
||||||
child_doctype = '{0} Item'.format(doctype)
|
child_doctype = '{0} Item'.format(doctype)
|
||||||
apply_on = frappe.scrub(pr_doc.get('apply_on'))
|
apply_on = frappe.scrub(pr_doc.get('apply_on'))
|
||||||
|
|
||||||
values = [pr_doc.valid_from, pr_doc.valid_upto]
|
values = [pr_doc.valid_from, pr_doc.valid_upto]
|
||||||
condition = ""
|
condition = ""
|
||||||
|
|
||||||
if pr_doc.warehouse:
|
if pr_doc.warehouse:
|
||||||
warehouses = get_child_warehouses(pr_doc.warehouse)
|
warehouses = get_child_warehouses(pr_doc.warehouse)
|
||||||
|
|
||||||
condition += """ and `tab{child_doc}`.warehouse in ({warehouses})
|
condition += """ and `tab{child_doc}`.warehouse in ({warehouses})
|
||||||
""".format(child_doc=child_doctype, warehouses = ','.join(['%s'] * len(warehouses)))
|
""".format(child_doc=child_doctype, warehouses = ','.join(['%s'] * len(warehouses)))
|
||||||
|
|
||||||
values.extend(warehouses)
|
values.extend(warehouses)
|
||||||
|
|
||||||
if items:
|
if items:
|
||||||
condition = " and `tab{child_doc}`.{apply_on} in ({items})".format(child_doc = child_doctype,
|
condition = " and `tab{child_doc}`.{apply_on} in ({items})".format(child_doc = child_doctype,
|
||||||
apply_on = apply_on, items = ','.join(['%s'] * len(items)))
|
apply_on = apply_on, items = ','.join(['%s'] * len(items)))
|
||||||
|
|
||||||
values.extend(items)
|
values.extend(items)
|
||||||
|
|
||||||
data_set = frappe.db.sql(""" SELECT `tab{child_doc}`.stock_qty,
|
data_set = frappe.db.sql(""" SELECT `tab{child_doc}`.stock_qty,
|
||||||
`tab{child_doc}`.amount
|
`tab{child_doc}`.amount
|
||||||
FROM `tab{child_doc}`, `tab{parent_doc}`
|
FROM `tab{child_doc}`, `tab{parent_doc}`
|
||||||
WHERE
|
WHERE
|
||||||
`tab{child_doc}`.parent = `tab{parent_doc}`.name and {date_field}
|
`tab{child_doc}`.parent = `tab{parent_doc}`.name and {date_field}
|
||||||
between %s and %s and `tab{parent_doc}`.docstatus = 1
|
between %s and %s and `tab{parent_doc}`.docstatus = 1
|
||||||
{condition} group by `tab{child_doc}`.name
|
{condition} group by `tab{child_doc}`.name
|
||||||
""".format(parent_doc = doctype,
|
""".format(parent_doc = doctype,
|
||||||
child_doc = child_doctype,
|
child_doc = child_doctype,
|
||||||
condition = condition,
|
condition = condition,
|
||||||
date_field = date_field
|
date_field = date_field
|
||||||
), tuple(values), as_dict=1)
|
), tuple(values), as_dict=1)
|
||||||
|
|
||||||
for data in data_set:
|
for data in data_set:
|
||||||
sum_qty += data.get('stock_qty')
|
sum_qty += data.get('stock_qty')
|
||||||
sum_amt += data.get('amount')
|
sum_amt += data.get('amount')
|
||||||
|
|
||||||
return [sum_qty, sum_amt]
|
return [sum_qty, sum_amt]
|
||||||
|
|
||||||
def validate_pricing_rules(doc):
|
def validate_pricing_rules(doc):
|
||||||
validate_pricing_rule_on_transactions(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)
|
||||||
|
|
||||||
for d in doc.items:
|
doc.calculate_taxes_and_totals()
|
||||||
validate_pricing_rule_on_items(doc, d)
|
|
||||||
|
|
||||||
doc.calculate_taxes_and_totals()
|
def validate_pricing_rule_on_items(doc, item_row, do_not_validate = False):
|
||||||
|
value = 0
|
||||||
|
for pricing_rule in get_applied_pricing_rules(doc, item_row):
|
||||||
|
pr_doc = frappe.get_doc('Pricing Rule', pricing_rule)
|
||||||
|
|
||||||
def validate_pricing_rule_on_items(doc, item_row):
|
if pr_doc.get('apply_on') == 'Transaction': continue
|
||||||
value = 0
|
|
||||||
for pr_row in get_applied_pricing_rules(doc, item_row):
|
|
||||||
pr_doc = frappe.get_doc('Pricing Rule', pr_row.pricing_rule)
|
|
||||||
|
|
||||||
if pr_doc.get('apply_on') == 'Transaction': continue
|
if pr_doc.get('price_or_product_discount') == 'Product':
|
||||||
|
apply_pricing_rule_for_free_items(doc, pr_doc)
|
||||||
|
else:
|
||||||
|
for field in ['discount_percentage', 'discount_amount', 'rate']:
|
||||||
|
if not pr_doc.get(field): continue
|
||||||
|
|
||||||
if pr_doc.get('price_or_product_discount') == 'Product':
|
value += pr_doc.get(field)
|
||||||
apply_pricing_rule_for_free_items(doc, pr_doc)
|
apply_pricing_rule(doc, pr_doc, item_row, value, do_not_validate)
|
||||||
else:
|
|
||||||
for field in ['discount_percentage', 'discount_amount', 'rate']:
|
|
||||||
if not pr_doc.get(field): continue
|
|
||||||
|
|
||||||
value += pr_doc.get(field)
|
|
||||||
apply_pricing_rule(doc, pr_doc, pr_row, item_row, value)
|
|
||||||
|
|
||||||
def validate_pricing_rule_on_transactions(doc):
|
def validate_pricing_rule_on_transactions(doc):
|
||||||
conditions = "apply_on = 'Transaction'"
|
conditions = "apply_on = 'Transaction'"
|
||||||
|
|
||||||
values = {}
|
values = {}
|
||||||
conditions = get_other_conditions(conditions, values, doc)
|
conditions = get_other_conditions(conditions, values, doc)
|
||||||
|
|
||||||
pricing_rules = frappe.db.sql(""" Select `tabPricing Rule`.* from `tabPricing Rule`
|
pricing_rules = frappe.db.sql(""" Select `tabPricing Rule`.* from `tabPricing Rule`
|
||||||
where {conditions} """.format(conditions = conditions), values, as_dict=1)
|
where {conditions} """.format(conditions = conditions), values, as_dict=1)
|
||||||
|
|
||||||
if pricing_rules:
|
if pricing_rules:
|
||||||
pricing_rules = filter_pricing_rules_for_qty_amount(doc.total_qty,
|
pricing_rules = filter_pricing_rules_for_qty_amount(doc.total_qty,
|
||||||
doc.total, pricing_rules)
|
doc.total, pricing_rules)
|
||||||
|
|
||||||
for d in pricing_rules:
|
for d in pricing_rules:
|
||||||
if d.price_or_product_discount == 'Price':
|
if d.price_or_product_discount == 'Price':
|
||||||
if d.apply_discount_on:
|
if d.apply_discount_on:
|
||||||
doc.set('apply_discount_on', d.apply_discount_on)
|
doc.set('apply_discount_on', d.apply_discount_on)
|
||||||
|
|
||||||
for field in ['additional_discount_percentage', 'discount_amount']:
|
for field in ['additional_discount_percentage', 'discount_amount']:
|
||||||
if not d.get(field): continue
|
if not d.get(field): continue
|
||||||
|
|
||||||
pr_field = ('discount_percentage'
|
pr_field = ('discount_percentage'
|
||||||
if field == 'additional_discount_percentage' else field)
|
if field == 'additional_discount_percentage' else field)
|
||||||
|
|
||||||
if d.validate_applied_rule and doc.get(field) < d.get(pr_field):
|
if d.validate_applied_rule and doc.get(field) < d.get(pr_field):
|
||||||
frappe.msgprint(_("User has not applied rule on the invoice {0}")
|
frappe.msgprint(_("User has not applied rule on the invoice {0}")
|
||||||
.format(doc.name))
|
.format(doc.name))
|
||||||
else:
|
else:
|
||||||
doc.set(field, d.get(pr_field))
|
doc.set(field, d.get(pr_field))
|
||||||
elif d.price_or_product_discount == 'Product':
|
elif d.price_or_product_discount == 'Product':
|
||||||
apply_pricing_rule_for_free_items(doc, d)
|
apply_pricing_rule_for_free_items(doc, d)
|
||||||
|
|
||||||
def get_applied_pricing_rules(doc, item_row):
|
def get_applied_pricing_rules(doc, item_row):
|
||||||
return [d for d in doc.pricing_rules
|
return (item_row.get("pricing_rules").split(',')
|
||||||
if d.child_docname == item_row.name]
|
if item_row.get("pricing_rules") else [])
|
||||||
|
|
||||||
def apply_pricing_rule_for_free_items(doc, pricing_rule):
|
def apply_pricing_rule_for_free_items(doc, pricing_rule):
|
||||||
if pricing_rule.get('free_item'):
|
if pricing_rule.get('free_item'):
|
||||||
items = [d.item_code for d in doc.items
|
items = [d.item_code for d in doc.items
|
||||||
if d.item_code == (d.item_code
|
if d.item_code == (d.item_code
|
||||||
if pricing_rule.get('same_item') else pricing_rule.get('free_item')) and d.is_free_item]
|
if pricing_rule.get('same_item') else pricing_rule.get('free_item')) and d.is_free_item]
|
||||||
|
|
||||||
if not items:
|
if not items:
|
||||||
doc.append('items', {
|
doc.append('items', {
|
||||||
'item_code': pricing_rule.get('free_item'),
|
'item_code': pricing_rule.get('free_item'),
|
||||||
'qty': pricing_rule.get('free_qty'),
|
'qty': pricing_rule.get('free_qty'),
|
||||||
'uom': pricing_rule.get('free_item_uom'),
|
'uom': pricing_rule.get('free_item_uom'),
|
||||||
'rate': pricing_rule.get('free_item_rate'),
|
'rate': pricing_rule.get('free_item_rate'),
|
||||||
'is_free_item': 1
|
'is_free_item': 1
|
||||||
})
|
})
|
||||||
|
|
||||||
doc.set_missing_values()
|
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 = frappe.scrub(pr_doc.get('apply_on'))
|
apply_on, items = get_apply_on_and_items(pr_doc, item_row)
|
||||||
items = (get_pricing_rule_items(pr_doc)
|
|
||||||
if pr_doc.mixed_conditions else [item_row.get(apply_on)])
|
|
||||||
|
|
||||||
if pr_doc.apply_rule_on_other:
|
rule_applied = {}
|
||||||
apply_on = frappe.scrub(pr_doc.apply_rule_on_other)
|
|
||||||
items = [pr_doc.get(apply_on)]
|
|
||||||
|
|
||||||
rule_applied = 1
|
for item in doc.get("items"):
|
||||||
if item_row.get(apply_on) in items:
|
if not item.pricing_rules:
|
||||||
for field in ['discount_percentage', 'discount_amount', 'rate']:
|
item.pricing_rules = item_row.pricing_rules
|
||||||
if not pr_doc.get(field): continue
|
|
||||||
|
|
||||||
if not pr_doc.validate_applied_rule:
|
if item.get(apply_on) in items:
|
||||||
item_row.set(field, value)
|
for field in ['discount_percentage', 'discount_amount', 'rate']:
|
||||||
elif item_row.get(field) < value:
|
if not pr_doc.get(field): continue
|
||||||
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
|
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)])
|
||||||
|
|
||||||
|
if pr_doc.apply_rule_on_other:
|
||||||
|
apply_on = frappe.scrub(pr_doc.apply_rule_on_other)
|
||||||
|
items = [pr_doc.get(apply_on)]
|
||||||
|
|
||||||
|
return apply_on, items
|
||||||
|
|
||||||
def get_pricing_rule_items(pr_doc):
|
def get_pricing_rule_items(pr_doc):
|
||||||
apply_on = frappe.scrub(pr_doc.get('apply_on'))
|
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){
|
cur_frm.cscript.cost_center = function(doc, cdt, cdn){
|
||||||
var d = locals[cdt][cdn];
|
var d = locals[cdt][cdn];
|
||||||
if(d.idx == 1 && d.cost_center){
|
if(d.cost_center){
|
||||||
var cl = doc.items || [];
|
var cl = doc.items || [];
|
||||||
for(var i = 0; i < cl.length; i++){
|
for(var i = 0; i < cl.length; i++){
|
||||||
if(!cl[i].cost_center) cl[i].cost_center = d.cost_center;
|
if(!cl[i].cost_center) cl[i].cost_center = d.cost_center;
|
||||||
|
@ -55,11 +55,6 @@ class PurchaseInvoice(BuyingController):
|
|||||||
if not self.on_hold:
|
if not self.on_hold:
|
||||||
self.release_date = ''
|
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):
|
def invoice_is_blocked(self):
|
||||||
return self.on_hold and (not self.release_date or self.release_date > getdate(nowdate()))
|
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()
|
self.update_status_updater_args()
|
||||||
|
|
||||||
if not self.is_return:
|
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_prevdoc_status()
|
||||||
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
|
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
|
||||||
self.update_billing_status_in_pr()
|
self.update_billing_status_in_pr()
|
||||||
|
@ -89,6 +89,12 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
|||||||
}, __('Create'));
|
}, __('Create'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (doc.docstatus === 1) {
|
||||||
|
cur_frm.add_custom_button(__('Maintenance Schedule'), function () {
|
||||||
|
cur_frm.cscript.make_maintenance_schedule();
|
||||||
|
}, __('Create'));
|
||||||
|
}
|
||||||
|
|
||||||
if(!doc.auto_repeat) {
|
if(!doc.auto_repeat) {
|
||||||
cur_frm.add_custom_button(__('Subscription'), function() {
|
cur_frm.add_custom_button(__('Subscription'), function() {
|
||||||
erpnext.utils.make_subscription(doc.doctype, doc.name)
|
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) {
|
on_submit: function(doc, dt, dn) {
|
||||||
var me = this;
|
var me = this;
|
||||||
|
|
||||||
|
@ -205,18 +205,11 @@ class SalesInvoice(SellingController):
|
|||||||
def before_cancel(self):
|
def before_cancel(self):
|
||||||
self.update_time_sheet(None)
|
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):
|
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
|
self.check_sales_order_on_hold_or_close("sales_order")
|
||||||
if frappe.db.get_single_value('Accounts Settings', 'unlink_payment_on_cancellation_of_invoice'):
|
|
||||||
unlink_ref_doc_from_payment_entries(self)
|
|
||||||
|
|
||||||
if self.is_return and not self.update_billed_amount_in_sales_order:
|
if self.is_return and not self.update_billed_amount_in_sales_order:
|
||||||
# NOTE status updating bypassed for is_return
|
# NOTE status updating bypassed for is_return
|
||||||
@ -1230,6 +1223,22 @@ def get_bank_cash_account(mode_of_payment, company):
|
|||||||
"account": account
|
"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()
|
@frappe.whitelist()
|
||||||
def make_delivery_note(source_name, target_doc=None):
|
def make_delivery_note(source_name, target_doc=None):
|
||||||
def set_missing_values(source, target):
|
def set_missing_values(source, target):
|
||||||
@ -1388,4 +1397,4 @@ def get_loyalty_programs(customer):
|
|||||||
frappe.db.set(customer, 'loyalty_program', lp_details[0])
|
frappe.db.set(customer, 'loyalty_program', lp_details[0])
|
||||||
return []
|
return []
|
||||||
else:
|
else:
|
||||||
return lp_details
|
return lp_details
|
@ -14,8 +14,9 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_per
|
|||||||
from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency
|
from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency
|
||||||
from erpnext.stock.doctype.serial_no.serial_no import SerialNoWarehouseError
|
from erpnext.stock.doctype.serial_no.serial_no import SerialNoWarehouseError
|
||||||
from frappe.model.naming import make_autoname
|
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.controllers.taxes_and_totals import get_itemised_tax_breakup_data
|
||||||
|
from erpnext.stock.doctype.item.test_item import create_item
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
class TestSalesInvoice(unittest.TestCase):
|
class TestSalesInvoice(unittest.TestCase):
|
||||||
def make(self):
|
def make(self):
|
||||||
@ -1572,6 +1573,56 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
|
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
|
||||||
accounts_settings.save()
|
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):
|
def create_sales_invoice(**args):
|
||||||
si = frappe.new_doc("Sales Invoice")
|
si = frappe.new_doc("Sales Invoice")
|
||||||
@ -1669,4 +1720,4 @@ def get_outstanding_amount(against_voucher_type, against_voucher, account, party
|
|||||||
if against_voucher_type == 'Purchase Invoice':
|
if against_voucher_type == 'Purchase Invoice':
|
||||||
bal = bal * -1
|
bal = bal * -1
|
||||||
|
|
||||||
return bal
|
return bal
|
@ -333,6 +333,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
|||||||
var me = this;
|
var me = this;
|
||||||
this.frm = {}
|
this.frm = {}
|
||||||
this.load_data(true);
|
this.load_data(true);
|
||||||
|
this.frm.doc.offline_pos_name = '';
|
||||||
this.setup();
|
this.setup();
|
||||||
this.set_default_customer()
|
this.set_default_customer()
|
||||||
},
|
},
|
||||||
@ -345,7 +346,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
|||||||
|
|
||||||
if (load_doc) {
|
if (load_doc) {
|
||||||
this.frm.doc = JSON.parse(localStorage.getItem('doc'));
|
this.frm.doc = JSON.parse(localStorage.getItem('doc'));
|
||||||
this.frm.doc.offline_pos_name = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$.each(this.meta, function (i, data) {
|
$.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.list_customers_btn.toggleClass("view_customer");
|
||||||
me.pos_bill.show();
|
me.pos_bill.show();
|
||||||
me.list_customers_btn.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();
|
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) {
|
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 () {
|
create_invoice: function () {
|
||||||
var me = this;
|
var me = this;
|
||||||
|
var existing_pos_list = [];
|
||||||
var invoice_data = {};
|
var invoice_data = {};
|
||||||
this.si_docs = this.get_doc_from_localstorage();
|
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()
|
this.update_invoice()
|
||||||
//to retrieve and set the default payment
|
//to retrieve and set the default payment
|
||||||
invoice_data[this.frm.doc.offline_pos_name] = this.frm.doc;
|
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.paid_amount = this.frm.doc.net_total
|
||||||
this.frm.doc.outstanding_amount = 0
|
this.frm.doc.outstanding_amount = 0
|
||||||
} else {
|
} else if(!this.frm.doc.offline_pos_name) {
|
||||||
this.frm.doc.offline_pos_name = $.now();
|
this.frm.doc.offline_pos_name = frappe.datetime.now_datetime();
|
||||||
this.frm.doc.posting_date = frappe.datetime.get_today();
|
this.frm.doc.posting_date = frappe.datetime.get_today();
|
||||||
this.frm.doc.posting_time = frappe.datetime.now_time();
|
this.frm.doc.posting_time = frappe.datetime.now_time();
|
||||||
this.frm.doc.pos_total_qty = this.frm.doc.qty_total;
|
this.frm.doc.pos_total_qty = this.frm.doc.qty_total;
|
||||||
|
@ -592,13 +592,17 @@ def get_party_shipping_address(doctype, name):
|
|||||||
else:
|
else:
|
||||||
return ''
|
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
|
data = frappe.db.sql(""" SELECT party, sum({0}) as amount
|
||||||
FROM `tabGL Entry`
|
FROM `tabGL Entry`
|
||||||
WHERE
|
WHERE
|
||||||
party_type = %s and against_voucher is null
|
party_type = %s and against_voucher is null
|
||||||
GROUP BY party"""
|
and {1} GROUP BY party"""
|
||||||
.format(("credit") if party_type == "Customer" else "debit") , party_type)
|
.format(("credit") if party_type == "Customer" else "debit", cond) , party_type)
|
||||||
|
|
||||||
if data:
|
if data:
|
||||||
return frappe._dict(data)
|
return frappe._dict(data)
|
@ -136,7 +136,8 @@ class AccountsReceivableSummary(ReceivablePayableReport):
|
|||||||
|
|
||||||
partywise_total = self.get_partywise_total(party_naming_by, args)
|
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):
|
for party, party_dict in iteritems(partywise_total):
|
||||||
row = [party]
|
row = [party]
|
||||||
|
|
||||||
@ -144,7 +145,10 @@ class AccountsReceivableSummary(ReceivablePayableReport):
|
|||||||
row += [self.get_party_name(args.get("party_type"), party)]
|
row += [self.get_party_name(args.get("party_type"), party)]
|
||||||
|
|
||||||
row += [partywise_advance_amount.get(party, 0)]
|
row += [partywise_advance_amount.get(party, 0)]
|
||||||
paid_amt = flt(party_dict.paid_amt - 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 += [
|
row += [
|
||||||
party_dict.invoiced_amt, paid_amt, party_dict.credit_amt, party_dict.outstanding_amt,
|
party_dict.invoiced_amt, paid_amt, party_dict.credit_amt, party_dict.outstanding_amt,
|
||||||
|
@ -14,13 +14,13 @@ def execute(filters=None):
|
|||||||
|
|
||||||
def get_column():
|
def get_column():
|
||||||
return [
|
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",
|
_("Suplier") + ":Link/Customer:120", _("Customer Name") + "::120",
|
||||||
_("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120",
|
_("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120",
|
||||||
_("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Pending Amount") + ":Currency:100",
|
_("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Pending Amount") + ":Currency:100",
|
||||||
_("Item Name") + "::120", _("Description") + "::120", _("Company") + ":Link/Company:120",
|
_("Item Name") + "::120", _("Description") + "::120", _("Company") + ":Link/Company:120",
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_args():
|
def get_args():
|
||||||
return {'doctype': 'Delivery Note', 'party': 'customer',
|
return {'doctype': 'Delivery Note', 'party': 'customer',
|
||||||
'date': 'posting_date', 'order': 'name', 'order_by': 'desc'}
|
'date': 'posting_date', 'order': 'name', 'order_by': 'desc'}
|
@ -12,14 +12,14 @@ def get_ordered_to_be_billed_data(args):
|
|||||||
child_tab = doctype + " Item"
|
child_tab = doctype + " Item"
|
||||||
precision = get_field_precision(frappe.get_meta(child_tab).get_field("billed_amt"),
|
precision = get_field_precision(frappe.get_meta(child_tab).get_field("billed_amt"),
|
||||||
currency=get_default_currency()) or 2
|
currency=get_default_currency()) or 2
|
||||||
|
|
||||||
project_field = get_project_field(doctype, party)
|
project_field = get_project_field(doctype, party)
|
||||||
|
|
||||||
return frappe.db.sql("""
|
return frappe.db.sql("""
|
||||||
Select
|
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,
|
{project_field}, `{child_tab}`.item_code, `{child_tab}`.base_amount,
|
||||||
(`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1)),
|
(`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1)),
|
||||||
(`{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))),
|
||||||
`{child_tab}`.item_name, `{child_tab}`.description, `{parent_tab}`.company
|
`{child_tab}`.item_name, `{child_tab}`.description, `{parent_tab}`.company
|
||||||
from
|
from
|
||||||
|
@ -14,13 +14,13 @@ def execute(filters=None):
|
|||||||
|
|
||||||
def get_column():
|
def get_column():
|
||||||
return [
|
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",
|
_("Suplier") + ":Link/Customer:120", _("Customer Name") + "::120",
|
||||||
_("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120",
|
_("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120",
|
||||||
_("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Pending Amount") + ":Currency:100",
|
_("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Pending Amount") + ":Currency:100",
|
||||||
_("Item Name") + "::120", _("Description") + "::120", _("Company") + ":Link/Company:120",
|
_("Item Name") + "::120", _("Description") + "::120", _("Company") + ":Link/Company:120",
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_args():
|
def get_args():
|
||||||
return {'doctype': 'Sales Order', 'party': 'customer',
|
return {'doctype': 'Sales Order', 'party': 'customer',
|
||||||
'date': 'transaction_date', 'order': 'transaction_date', 'order_by': 'asc'}
|
'date': 'transaction_date', 'order': 'transaction_date', 'order_by': 'asc'}
|
@ -133,6 +133,13 @@ def get_columns(filters):
|
|||||||
"options": filters.get("based_on"),
|
"options": filters.get("based_on"),
|
||||||
"width": 300
|
"width": 300
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "currency",
|
||||||
|
"label": _("Currency"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Currency",
|
||||||
|
"hidden": 1
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "income",
|
"fieldname": "income",
|
||||||
"label": _("Income"),
|
"label": _("Income"),
|
||||||
@ -153,13 +160,6 @@ def get_columns(filters):
|
|||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"options": "currency",
|
"options": "currency",
|
||||||
"width": 120
|
"width": 120
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname": "currency",
|
|
||||||
"label": _("Currency"),
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"options": "Currency",
|
|
||||||
"hidden": 1
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -191,4 +191,4 @@ def set_gl_entries_by_account(company, from_date, to_date, based_on, gl_entries_
|
|||||||
for entry in gl_entries:
|
for entry in gl_entries:
|
||||||
gl_entries_by_account.setdefault(entry.based_on, []).append(entry)
|
gl_entries_by_account.setdefault(entry.based_on, []).append(entry)
|
||||||
|
|
||||||
return gl_entries_by_account
|
return gl_entries_by_account
|
||||||
|
@ -14,13 +14,13 @@ def execute(filters=None):
|
|||||||
|
|
||||||
def get_column():
|
def get_column():
|
||||||
return [
|
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",
|
_("Suplier") + ":Link/Supplier:120", _("Suplier Name") + "::120",
|
||||||
_("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120",
|
_("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120",
|
||||||
_("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Amount to Bill") + ":Currency:100",
|
_("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Amount to Bill") + ":Currency:100",
|
||||||
_("Item Name") + "::120", _("Description") + "::120", _("Company") + ":Link/Company:120",
|
_("Item Name") + "::120", _("Description") + "::120", _("Company") + ":Link/Company:120",
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_args():
|
def get_args():
|
||||||
return {'doctype': 'Purchase Order', 'party': 'supplier',
|
return {'doctype': 'Purchase Order', 'party': 'supplier',
|
||||||
'date': 'transaction_date', 'order': 'transaction_date', 'order_by': 'asc'}
|
'date': 'transaction_date', 'order': 'transaction_date', 'order_by': 'asc'}
|
||||||
|
@ -14,7 +14,7 @@ def execute(filters=None):
|
|||||||
|
|
||||||
def get_column():
|
def get_column():
|
||||||
return [
|
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",
|
_("Supplier") + ":Link/Supplier:120", _("Supplier Name") + "::120",
|
||||||
_("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120",
|
_("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120",
|
||||||
_("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Amount to Bill") + ":Currency:100",
|
_("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',
|
frm.set_indicator_formatter('item_code',
|
||||||
function(doc) { return (doc.qty<=doc.received_qty) ? "green" : "orange" })
|
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() {
|
frm.set_query("blanket_order", "items", function() {
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
|
@ -444,7 +444,7 @@ def make_rm_stock_entry(purchase_order, rm_items):
|
|||||||
item_wh = get_item_details(items)
|
item_wh = get_item_details(items)
|
||||||
|
|
||||||
stock_entry = frappe.new_doc("Stock Entry")
|
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.purchase_order = purchase_order.name
|
||||||
stock_entry.supplier = purchase_order.supplier
|
stock_entry.supplier = purchase_order.supplier
|
||||||
stock_entry.supplier_name = purchase_order.supplier_name
|
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.address_display = purchase_order.address_display
|
||||||
stock_entry.company = purchase_order.company
|
stock_entry.company = purchase_order.company
|
||||||
stock_entry.to_warehouse = purchase_order.supplier_warehouse
|
stock_entry.to_warehouse = purchase_order.supplier_warehouse
|
||||||
|
stock_entry.set_stock_entry_type()
|
||||||
|
|
||||||
for item_code in fg_items:
|
for item_code in fg_items:
|
||||||
for rm_item_data in rm_items_list:
|
for rm_item_data in rm_items_list:
|
||||||
|
@ -465,6 +465,33 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
self.assertEquals(se_items, supplied_items)
|
self.assertEquals(se_items, supplied_items)
|
||||||
update_backflush_based_on("BOM")
|
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):
|
def make_subcontracted_item(item_code):
|
||||||
from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
|
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."
|
"description": "Sales pipeline, leads, opportunities and customers."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"module_name": "Help Desk",
|
"module_name": "Support",
|
||||||
"category": "Modules",
|
"category": "Modules",
|
||||||
"label": _("Help Desk"),
|
"label": _("Support"),
|
||||||
"color": "#1abc9c",
|
"color": "#1abc9c",
|
||||||
"icon": "fa fa-check-square-o",
|
"icon": "fa fa-check-square-o",
|
||||||
"type": "module",
|
"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",
|
"name": "Employee Advance",
|
||||||
"dependencies": ["Employee"]
|
"dependencies": ["Employee"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Expense Claim",
|
||||||
|
"dependencies": ["Employee"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "doctype",
|
"type": "doctype",
|
||||||
"name": "Loan Type",
|
"name": "Loan Type",
|
||||||
@ -296,6 +301,10 @@ def get_data():
|
|||||||
"name": "Loan Application",
|
"name": "Loan Application",
|
||||||
"dependencies": ["Employee"]
|
"dependencies": ["Employee"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Loan"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -27,6 +27,13 @@ def get_data():
|
|||||||
"onboard": 1,
|
"onboard": 1,
|
||||||
"dependencies": ["Item", "Customer"],
|
"dependencies": ["Item", "Customer"],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Sales Invoice",
|
||||||
|
"description": _("Invoices for Costumers."),
|
||||||
|
"onboard": 1,
|
||||||
|
"dependencies": ["Item", "Customer"],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "doctype",
|
"type": "doctype",
|
||||||
"name": "Sales Partner",
|
"name": "Sales Partner",
|
||||||
|
@ -10,11 +10,13 @@ def get_data():
|
|||||||
"type": "doctype",
|
"type": "doctype",
|
||||||
"name": "Issue",
|
"name": "Issue",
|
||||||
"description": _("Support queries from customers."),
|
"description": _("Support queries from customers."),
|
||||||
|
"onboard": 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "doctype",
|
"type": "doctype",
|
||||||
"name": "Communication",
|
"name": "Communication",
|
||||||
"description": _("Communication log."),
|
"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"),
|
"label": _("Reports"),
|
||||||
"icon": "fa fa-list",
|
"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()
|
self.validate_non_invoice_documents_schedule()
|
||||||
|
|
||||||
def before_print(self):
|
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',
|
if self.doctype in ['Purchase Order', 'Sales Order', 'Sales Invoice', 'Purchase Invoice',
|
||||||
'Supplier Quotation', 'Purchase Receipt', 'Delivery Note', 'Quotation']:
|
'Supplier Quotation', 'Purchase Receipt', 'Delivery Note', 'Quotation']:
|
||||||
if self.get("group_same_items"):
|
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'):
|
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))
|
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 ?
|
# if user changed the discount percentage then set user's discount percentage ?
|
||||||
item.set("pricing_rules", ret.get("pricing_rules"))
|
item.set("pricing_rules", ret.get("pricing_rules"))
|
||||||
item.set("discount_percentage", ret.get("discount_percentage"))
|
item.set("discount_percentage", ret.get("discount_percentage"))
|
||||||
@ -546,6 +552,19 @@ class AccountsController(TransactionBase):
|
|||||||
from erpnext.accounts.utils import reconcile_against_document
|
from erpnext.accounts.utils import reconcile_against_document
|
||||||
reconcile_against_document(lst)
|
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):
|
def validate_multiple_billing(self, ref_dt, item_ref_dn, based_on, parentfield):
|
||||||
from erpnext.controllers.status_updater import get_tolerance_for
|
from erpnext.controllers.status_updater import get_tolerance_for
|
||||||
item_tolerance = {}
|
item_tolerance = {}
|
||||||
|
@ -538,6 +538,8 @@ class BuyingController(StockController):
|
|||||||
update_last_purchase_rate(self, is_submit = 1)
|
update_last_purchase_rate(self, is_submit = 1)
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
|
super(BuyingController, self).on_cancel()
|
||||||
|
|
||||||
if self.get('is_return'):
|
if self.get('is_return'):
|
||||||
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
|
sed.stock_uom, sed.subcontracted_item as main_item_code, sed.serial_no, sed.batch_no
|
||||||
from `tabStock Entry` se,`tabStock Entry Detail` sed
|
from `tabStock Entry` se,`tabStock Entry Detail` sed
|
||||||
where
|
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, '') != ''
|
and se.purchase_order in (%s) and ifnull(sed.t_warehouse, '') != ''
|
||||||
group by sed.item_code, sed.t_warehouse
|
group by sed.item_code, sed.t_warehouse
|
||||||
""" % (','.join(['%s'] * len(purchase_orders))), tuple(purchase_orders), as_dict=1)
|
""" % (','.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": _("Issues"), "route": "/issues", "reference_doctype": "Issue", "role":"Customer"},
|
||||||
{"title": _("Addresses"), "route": "/addresses", "reference_doctype": "Address"},
|
{"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": _("Timesheets"), "route": "/timesheets", "reference_doctype": "Timesheet", "role":"Customer"},
|
|
||||||
{"title": _("Lab Test"), "route": "/lab-test", "reference_doctype": "Lab Test", "role":"Patient"},
|
{"title": _("Lab Test"), "route": "/lab-test", "reference_doctype": "Lab Test", "role":"Patient"},
|
||||||
{"title": _("Prescription"), "route": "/prescription", "reference_doctype": "Patient Encounter", "role":"Patient"},
|
{"title": _("Prescription"), "route": "/prescription", "reference_doctype": "Patient Encounter", "role":"Patient"},
|
||||||
{"title": _("Patient Appointment"), "route": "/patient-appointments", "reference_doctype": "Patient Appointment", "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.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.accounts.doctype.gl_entry.gl_entry.rename_gle_sle_docs",
|
||||||
"erpnext.projects.doctype.project.project.hourly_reminder",
|
"erpnext.projects.doctype.project.project.hourly_reminder",
|
||||||
"erpnext.projects.doctype.project.project.collect_project_status",
|
"erpnext.projects.doctype.project.project.collect_project_status"
|
||||||
"erpnext.support.doctype.issue.issue.update_support_timer",
|
|
||||||
],
|
],
|
||||||
"daily": [
|
"daily": [
|
||||||
"erpnext.stock.reorder_item.reorder_item",
|
"erpnext.stock.reorder_item.reorder_item",
|
||||||
@ -333,4 +331,4 @@ user_privacy_documents = [
|
|||||||
'match_field': 'contact_email',
|
'match_field': 'contact_email',
|
||||||
'personal_fields': ['contact_mobile', 'contact_display', 'customer_name'],
|
'personal_fields': ['contact_mobile', 'contact_display', 'customer_name'],
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -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))
|
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):
|
def get_leaves_for_period(employee, leave_type, from_date, to_date, status, docname=None):
|
||||||
leave_applications = frappe.db.sql("""
|
leave_applications = frappe.db.sql("""
|
||||||
select name, employee, leave_type, from_date, to_date, total_leave_days
|
select name, employee, leave_type, from_date, to_date, total_leave_days
|
||||||
|
@ -441,7 +441,7 @@ class SalarySlip(TransactionBase):
|
|||||||
def calculate_net_pay(self):
|
def calculate_net_pay(self):
|
||||||
if self.salary_structure:
|
if self.salary_structure:
|
||||||
self.calculate_component_amounts()
|
self.calculate_component_amounts()
|
||||||
|
|
||||||
disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, "disable_rounded_total"))
|
disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, "disable_rounded_total"))
|
||||||
precision = frappe.defaults.get_global_default("currency_precision")
|
precision = frappe.defaults.get_global_default("currency_precision")
|
||||||
self.total_deduction = 0
|
self.total_deduction = 0
|
||||||
@ -452,10 +452,13 @@ class SalarySlip(TransactionBase):
|
|||||||
|
|
||||||
self.set_loan_repayment()
|
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.rounded_total = rounded(self.net_pay,
|
||||||
self.precision("net_pay") if disable_rounded_total else 0)
|
self.precision("net_pay") if disable_rounded_total else 0)
|
||||||
|
|
||||||
if self.net_pay < 0:
|
if self.net_pay < 0:
|
||||||
frappe.throw(_("Net Pay cannnot be negative"))
|
frappe.throw(_("Net Pay cannnot be negative"))
|
||||||
|
|
||||||
|
@ -5,21 +5,21 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from erpnext.hr.doctype.leave_application.leave_application \
|
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):
|
def execute(filters=None):
|
||||||
leave_types = frappe.db.sql_list("select name from `tabLeave Type` order by name asc")
|
leave_types = frappe.db.sql_list("select name from `tabLeave Type` order by name asc")
|
||||||
|
|
||||||
columns = get_columns(leave_types)
|
columns = get_columns(leave_types)
|
||||||
data = get_data(filters, leave_types)
|
data = get_data(filters, leave_types)
|
||||||
|
|
||||||
return columns, data
|
return columns, data
|
||||||
|
|
||||||
def get_columns(leave_types):
|
def get_columns(leave_types):
|
||||||
columns = [
|
columns = [
|
||||||
_("Employee") + ":Link/Employee:150",
|
_("Employee") + ":Link/Employee:150",
|
||||||
_("Employee Name") + "::200",
|
_("Employee Name") + "::200",
|
||||||
_("Department") +"::150"
|
_("Department") +"::150"
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -27,18 +27,18 @@ def get_columns(leave_types):
|
|||||||
columns.append(_(leave_type) + " " + _("Opening") + ":Float:160")
|
columns.append(_(leave_type) + " " + _("Opening") + ":Float:160")
|
||||||
columns.append(_(leave_type) + " " + _("Taken") + ":Float:160")
|
columns.append(_(leave_type) + " " + _("Taken") + ":Float:160")
|
||||||
columns.append(_(leave_type) + " " + _("Balance") + ":Float:160")
|
columns.append(_(leave_type) + " " + _("Balance") + ":Float:160")
|
||||||
|
|
||||||
return columns
|
return columns
|
||||||
|
|
||||||
def get_data(filters, leave_types):
|
def get_data(filters, leave_types):
|
||||||
user = frappe.session.user
|
user = frappe.session.user
|
||||||
allocation_records_based_on_to_date = get_leave_allocation_records(filters.to_date)
|
allocation_records_based_on_to_date = get_leave_allocation_records(filters.to_date)
|
||||||
allocation_records_based_on_from_date = get_leave_allocation_records(filters.from_date)
|
allocation_records_based_on_from_date = get_leave_allocation_records(filters.from_date)
|
||||||
|
|
||||||
active_employees = frappe.get_all("Employee",
|
active_employees = frappe.get_all("Employee",
|
||||||
filters = { "status": "Active", "company": filters.company},
|
filters = { "status": "Active", "company": filters.company},
|
||||||
fields = ["name", "employee_name", "department", "user_id"])
|
fields = ["name", "employee_name", "department", "user_id"])
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
for employee in active_employees:
|
for employee in active_employees:
|
||||||
leave_approvers = get_approvers(employee.department)
|
leave_approvers = get_approvers(employee.department)
|
||||||
@ -51,8 +51,7 @@ def get_data(filters, leave_types):
|
|||||||
filters.from_date, filters.to_date)
|
filters.from_date, filters.to_date)
|
||||||
|
|
||||||
# opening balance
|
# opening balance
|
||||||
opening = get_leave_balance_on(employee.name, leave_type, filters.from_date,
|
opening = get_total_allocated_leaves(employee.name, leave_type, filters.to_date)
|
||||||
allocation_records_based_on_from_date.get(employee.name, frappe._dict()))
|
|
||||||
|
|
||||||
# closing balance
|
# closing balance
|
||||||
closing = get_leave_balance_on(employee.name, leave_type, filters.to_date,
|
closing = get_leave_balance_on(employee.name, leave_type, filters.to_date,
|
||||||
@ -61,7 +60,7 @@ def get_data(filters, leave_types):
|
|||||||
row += [opening, leaves_taken, closing]
|
row += [opening, leaves_taken, closing]
|
||||||
|
|
||||||
data.append(row)
|
data.append(row)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def get_approvers(department):
|
def get_approvers(department):
|
||||||
|
@ -14,11 +14,11 @@ def execute(filters=None):
|
|||||||
columns, earning_types, ded_types = get_columns(salary_slips)
|
columns, earning_types, ded_types = get_columns(salary_slips)
|
||||||
ss_earning_map = get_ss_earning_map(salary_slips)
|
ss_earning_map = get_ss_earning_map(salary_slips)
|
||||||
ss_ded_map = get_ss_ded_map(salary_slips)
|
ss_ded_map = get_ss_ded_map(salary_slips)
|
||||||
|
doj_map = get_employee_doj_map()
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
for ss in salary_slips:
|
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]
|
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')
|
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):
|
def get_columns(salary_slips):
|
||||||
"""
|
"""
|
||||||
columns = [
|
columns = [
|
||||||
_("Salary Slip ID") + ":Link/Salary Slip:150",_("Employee") + ":Link/Employee:120", _("Employee Name") + "::140", _("Branch") + ":Link/Branch:120",
|
_("Salary Slip ID") + ":Link/Salary Slip:150",_("Employee") + ":Link/Employee:120", _("Employee Name") + "::140",
|
||||||
_("Department") + ":Link/Department:120", _("Designation") + ":Link/Designation:120",
|
_("Date of Joining") + "::80", _("Branch") + ":Link/Branch:120", _("Department") + ":Link/Department:120",
|
||||||
_("Company") + ":Link/Company:120", _("Start Date") + "::80", _("End Date") + "::80", _("Leave Without Pay") + ":Float:130",
|
_("Designation") + ":Link/Designation:120", _("Company") + ":Link/Company:120", _("Start Date") + "::80",
|
||||||
_("Payment Days") + ":Float:120"
|
_("End Date") + "::80", _("Leave Without Pay") + ":Float:130", _("Payment Days") + ":Float:120"
|
||||||
]
|
]
|
||||||
"""
|
"""
|
||||||
columns = [
|
columns = [
|
||||||
_("Salary Slip ID") + ":Link/Salary Slip:150",_("Employee") + ":Link/Employee:120", _("Employee Name") + "::140", _("Branch") + ":Link/Branch:-1",
|
_("Salary Slip ID") + ":Link/Salary Slip:150",_("Employee") + ":Link/Employee:120", _("Employee Name") + "::140",
|
||||||
_("Department") + ":Link/Department:-1", _("Designation") + ":Link/Designation:-1",
|
_("Date of Joining") + "::80", _("Branch") + ":Link/Branch:-1", _("Department") + ":Link/Department:-1",
|
||||||
_("Company") + ":Link/Company:120", _("Start Date") + "::80", _("End Date") + "::80", _("Leave Without Pay") + ":Float:-1",
|
_("Designation") + ":Link/Designation:-1", _("Company") + ":Link/Company:120", _("Start Date") + "::80",
|
||||||
_("Payment Days") + ":Float:120"
|
_("End Date") + "::80", _("Leave Without Pay") + ":Float:-1", _("Payment Days") + ":Float:120"
|
||||||
]
|
]
|
||||||
|
|
||||||
salary_components = {_("Earning"): [], _("Deduction"): []}
|
salary_components = {_("Earning"): [], _("Deduction"): []}
|
||||||
@ -93,6 +93,16 @@ def get_conditions(filters):
|
|||||||
|
|
||||||
return 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):
|
def get_ss_earning_map(salary_slips):
|
||||||
ss_earnings = frappe.db.sql("""select parent, salary_component, amount
|
ss_earnings = frappe.db.sql("""select parent, salary_component, amount
|
||||||
from `tabSalary Detail` where parent in (%s)""" %
|
from `tabSalary Detail` where parent in (%s)""" %
|
||||||
@ -115,4 +125,4 @@ def get_ss_ded_map(salary_slips):
|
|||||||
ss_ded_map.setdefault(d.parent, frappe._dict()).setdefault(d.salary_component, [])
|
ss_ded_map.setdefault(d.parent, frappe._dict()).setdefault(d.salary_component, [])
|
||||||
ss_ded_map[d.parent][d.salary_component] = flt(d.amount)
|
ss_ded_map[d.parent][d.salary_component] = flt(d.amount)
|
||||||
|
|
||||||
return ss_ded_map
|
return ss_ded_map
|
@ -568,6 +568,7 @@ def make_stock_entry(production_order_id, purpose, qty=None):
|
|||||||
stock_entry.bom_no = production_order.bom_no
|
stock_entry.bom_no = production_order.bom_no
|
||||||
stock_entry.use_multi_level_bom = production_order.use_multi_level_bom
|
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.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":
|
if purpose=="Material Transfer for Manufacture":
|
||||||
stock_entry.to_warehouse = wip_warehouse
|
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)
|
additional_costs = get_additional_costs(work_order, fg_qty=stock_entry.fg_completed_qty)
|
||||||
stock_entry.set("additional_costs", additional_costs)
|
stock_entry.set("additional_costs", additional_costs)
|
||||||
|
|
||||||
|
stock_entry.set_stock_entry_type()
|
||||||
stock_entry.get_items()
|
stock_entry.get_items()
|
||||||
return stock_entry.as_dict()
|
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.v12_0.set_gst_category
|
||||||
erpnext.patches.v11_0.remove_barcodes_field_from_copy_fields_to_variants
|
erpnext.patches.v11_0.remove_barcodes_field_from_copy_fields_to_variants
|
||||||
erpnext.patches.v12_0.set_task_status
|
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.add_item_name_in_work_orders
|
||||||
erpnext.patches.v12_0.update_pricing_rule_fields
|
erpnext.patches.v12_0.update_pricing_rule_fields
|
||||||
erpnext.patches.v11_1.make_job_card_time_logs
|
erpnext.patches.v11_1.make_job_card_time_logs
|
||||||
erpnext.patches.v12_0.rename_pricing_rule_child_doctypes
|
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
|
from erpnext.regional.italy import state_codes
|
||||||
import frappe
|
import frappe
|
||||||
|
|
||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
company = frappe.get_all('Company', filters = {'country': 'Italy'})
|
company = frappe.get_all('Company', filters = {'country': 'Italy'})
|
||||||
if not company:
|
if not company:
|
||||||
@ -27,4 +26,12 @@ def execute():
|
|||||||
frappe.db.sql("""
|
frappe.db.sql("""
|
||||||
UPDATE tabAddress set {condition} country_code = UPPER(ifnull((select code
|
UPDATE tabAddress set {condition} country_code = UPPER(ifnull((select code
|
||||||
from `tabCountry` where name = `tabAddress`.country), ''))
|
from `tabCountry` where name = `tabAddress`.country), ''))
|
||||||
|
where country_code is null and state_code is null
|
||||||
""".format(condition=condition))
|
""".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
|
||||||
|
""")
|
||||||
|
@ -7,13 +7,13 @@ import frappe
|
|||||||
def execute():
|
def execute():
|
||||||
frappe.reload_doc('buying', 'doctype', 'buying_settings')
|
frappe.reload_doc('buying', 'doctype', 'buying_settings')
|
||||||
frappe.db.set_value('Buying Settings', None, 'backflush_raw_materials_of_subcontract_based_on', 'BOM')
|
frappe.db.set_value('Buying Settings', None, 'backflush_raw_materials_of_subcontract_based_on', 'BOM')
|
||||||
|
|
||||||
frappe.reload_doc('stock', 'doctype', 'stock_entry_detail')
|
frappe.reload_doc('stock', 'doctype', 'stock_entry_detail')
|
||||||
frappe.db.sql(""" update `tabStock Entry Detail` as sed,
|
frappe.db.sql(""" update `tabStock Entry Detail` as sed,
|
||||||
`tabStock Entry` as se, `tabPurchase Order Item Supplied` as pois
|
`tabStock Entry` as se, `tabPurchase Order Item Supplied` as pois
|
||||||
set
|
set
|
||||||
sed.subcontracted_item = pois.main_item_code
|
sed.subcontracted_item = pois.main_item_code
|
||||||
where
|
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.rm_item_code = sed.item_code and se.docstatus = 1
|
||||||
and pois.parenttype = 'Purchase Order'""")
|
and pois.parenttype = 'Purchase Order'""")
|
@ -3,6 +3,8 @@ import json
|
|||||||
from six import iteritems
|
from six import iteritems
|
||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
|
if "tax_type" not in frappe.db.get_table_columns("Item Tax"):
|
||||||
|
return
|
||||||
old_item_taxes = {}
|
old_item_taxes = {}
|
||||||
item_tax_templates = {}
|
item_tax_templates = {}
|
||||||
rename_template_to_untitled = []
|
rename_template_to_untitled = []
|
||||||
@ -40,7 +42,7 @@ def execute():
|
|||||||
item.set("taxes", [])
|
item.set("taxes", [])
|
||||||
item.append("taxes", {"item_tax_template": item_tax_template_name, "tax_category": ""})
|
item.append("taxes", {"item_tax_template": item_tax_template_name, "tax_category": ""})
|
||||||
item.save()
|
item.save()
|
||||||
|
|
||||||
doctypes = [
|
doctypes = [
|
||||||
'Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice',
|
'Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice',
|
||||||
'Supplier Quotation', 'Purchase Order', 'Purchase Receipt', 'Purchase Invoice'
|
'Supplier Quotation', 'Purchase Order', 'Purchase Receipt', 'Purchase Invoice'
|
||||||
|
@ -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()
|
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()
|
@frappe.whitelist()
|
||||||
def check_if_child_exists(name):
|
def check_if_child_exists(name):
|
||||||
child_tasks = frappe.get_all("Task", filters={"parent_task": name})
|
child_tasks = frappe.get_all("Task", filters={"parent_task": name})
|
||||||
@ -196,10 +203,9 @@ def set_multiple_status(names, status):
|
|||||||
task.save()
|
task.save()
|
||||||
|
|
||||||
def set_tasks_as_overdue():
|
def set_tasks_as_overdue():
|
||||||
frappe.db.sql("""update tabTask set `status`='Overdue'
|
tasks = frappe.get_all("Task", filters={'status':['not in',['Cancelled', 'Completed']]})
|
||||||
where exp_end_date is not null
|
for task in tasks:
|
||||||
and exp_end_date < CURDATE()
|
frappe.get_doc("Task", task.name).update_status()
|
||||||
and `status` not in ('Completed', 'Cancelled')""")
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_children(doctype, parent, task=None, project=None, is_root=False):
|
def get_children(doctype, parent, task=None, project=None, is_root=False):
|
||||||
|
@ -10,8 +10,8 @@ frappe.ui.form.on("Timesheet", {
|
|||||||
filters:{
|
filters:{
|
||||||
'status': 'Active'
|
'status': 'Active'
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
frm.fields_dict['time_logs'].grid.get_field('task').get_query = function(frm, cdt, cdn) {
|
frm.fields_dict['time_logs'].grid.get_field('task').get_query = function(frm, cdt, cdn) {
|
||||||
var child = locals[cdt][cdn];
|
var child = locals[cdt][cdn];
|
||||||
@ -20,22 +20,26 @@ frappe.ui.form.on("Timesheet", {
|
|||||||
'project': child.project,
|
'project': child.project,
|
||||||
'status': ["!=", "Cancelled"]
|
'status': ["!=", "Cancelled"]
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
frm.fields_dict['time_logs'].grid.get_field('project').get_query = function() {
|
frm.fields_dict['time_logs'].grid.get_field('project').get_query = function() {
|
||||||
return{
|
return{
|
||||||
filters: {
|
filters: {
|
||||||
'company': frm.doc.company
|
'company': frm.doc.company
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
onload: function(frm){
|
onload: function(frm){
|
||||||
if (frm.doc.__islocal && frm.doc.time_logs) {
|
if (frm.doc.__islocal && frm.doc.time_logs) {
|
||||||
calculate_time_and_amount(frm);
|
calculate_time_and_amount(frm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (frm.is_new()) {
|
||||||
|
set_employee_and_company(frm);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
@ -58,7 +62,7 @@ frappe.ui.form.on("Timesheet", {
|
|||||||
if ((row.from_time <= frappe.datetime.now_datetime()) && !row.completed) {
|
if ((row.from_time <= frappe.datetime.now_datetime()) && !row.completed) {
|
||||||
button = 'Resume Timer';
|
button = 'Resume Timer';
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
frm.add_custom_button(__(button), function() {
|
frm.add_custom_button(__(button), function() {
|
||||||
var flag = true;
|
var flag = true;
|
||||||
@ -77,7 +81,7 @@ frappe.ui.form.on("Timesheet", {
|
|||||||
erpnext.timesheet.timer(frm, row, timestamp);
|
erpnext.timesheet.timer(frm, row, timestamp);
|
||||||
flag = false;
|
flag = false;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
// If no activities found to start a timer, create new
|
// If no activities found to start a timer, create new
|
||||||
if (flag) {
|
if (flag) {
|
||||||
erpnext.timesheet.timer(frm);
|
erpnext.timesheet.timer(frm);
|
||||||
@ -94,7 +98,7 @@ frappe.ui.form.on("Timesheet", {
|
|||||||
frappe.db.get_value('Company', { 'company_name' : frm.doc.company }, 'standard_working_hours')
|
frappe.db.get_value('Company', { 'company_name' : frm.doc.company }, 'standard_working_hours')
|
||||||
.then(({ message }) => {
|
.then(({ message }) => {
|
||||||
(frappe.working_hours = message.standard_working_hours || 0);
|
(frappe.working_hours = message.standard_working_hours || 0);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
make_invoice: function(frm) {
|
make_invoice: function(frm) {
|
||||||
@ -125,8 +129,8 @@ frappe.ui.form.on("Timesheet", {
|
|||||||
frappe.set_route("Form", r.message.doctype, r.message.name);
|
frappe.set_route("Form", r.message.doctype, r.message.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
dialog.show();
|
dialog.show();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -136,7 +140,7 @@ frappe.ui.form.on("Timesheet", {
|
|||||||
frm: frm
|
frm: frm
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
frappe.ui.form.on("Timesheet Detail", {
|
frappe.ui.form.on("Timesheet Detail", {
|
||||||
time_logs_remove: function(frm) {
|
time_logs_remove: function(frm) {
|
||||||
@ -171,22 +175,22 @@ frappe.ui.form.on("Timesheet Detail", {
|
|||||||
.find('[data-fieldname="timer"]')
|
.find('[data-fieldname="timer"]')
|
||||||
.append(frappe.render_template("timesheet"));
|
.append(frappe.render_template("timesheet"));
|
||||||
frm.trigger("control_timer");
|
frm.trigger("control_timer");
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
hours: function(frm, cdt, cdn) {
|
hours: function(frm, cdt, cdn) {
|
||||||
calculate_end_time(frm, cdt, cdn)
|
calculate_end_time(frm, cdt, cdn);
|
||||||
},
|
},
|
||||||
|
|
||||||
billing_hours: function(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) {
|
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) {
|
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) {
|
billable: function(frm, cdt, cdn) {
|
||||||
@ -212,7 +216,7 @@ frappe.ui.form.on("Timesheet Detail", {
|
|||||||
calculate_billing_costing_amount(frm, cdt, cdn);
|
calculate_billing_costing_amount(frm, cdt, cdn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -240,23 +244,23 @@ var calculate_end_time = function(frm, cdt, cdn) {
|
|||||||
frm._setting_hours = true;
|
frm._setting_hours = true;
|
||||||
frappe.model.set_value(cdt, cdn, "to_time",
|
frappe.model.set_value(cdt, cdn, "to_time",
|
||||||
d.format(frappe.defaultDatetimeFormat)).then(() => {
|
d.format(frappe.defaultDatetimeFormat)).then(() => {
|
||||||
frm._setting_hours = false;
|
frm._setting_hours = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
var update_billing_hours = function(frm, cdt, cdn){
|
var update_billing_hours = function(frm, cdt, cdn){
|
||||||
var child = locals[cdt][cdn];
|
var child = locals[cdt][cdn];
|
||||||
if(!child.billable) frappe.model.set_value(cdt, cdn, 'billing_hours', 0.0);
|
if(!child.billable) frappe.model.set_value(cdt, cdn, 'billing_hours', 0.0);
|
||||||
}
|
};
|
||||||
|
|
||||||
var update_time_rates = function(frm, cdt, cdn){
|
var update_time_rates = function(frm, cdt, cdn){
|
||||||
var child = locals[cdt][cdn];
|
var child = locals[cdt][cdn];
|
||||||
if(!child.billable){
|
if(!child.billable){
|
||||||
frappe.model.set_value(cdt, cdn, 'billing_rate', 0.0);
|
frappe.model.set_value(cdt, cdn, 'billing_rate', 0.0);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
var calculate_billing_costing_amount = function(frm, cdt, cdn){
|
var calculate_billing_costing_amount = function(frm, cdt, cdn){
|
||||||
var child = locals[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, 'billing_amount', billing_amount);
|
||||||
frappe.model.set_value(cdt, cdn, 'costing_amount', costing_amount);
|
frappe.model.set_value(cdt, cdn, 'costing_amount', costing_amount);
|
||||||
calculate_time_and_amount(frm);
|
calculate_time_and_amount(frm);
|
||||||
}
|
};
|
||||||
|
|
||||||
var calculate_time_and_amount = function(frm) {
|
var calculate_time_and_amount = function(frm) {
|
||||||
var tl = frm.doc.time_logs || [];
|
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_hours", total_working_hr);
|
||||||
frm.set_value("total_billable_amount", total_billable_amount);
|
frm.set_value("total_billable_amount", total_billable_amount);
|
||||||
frm.set_value("total_costing_amount", total_costing_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() {
|
onload: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
@ -422,6 +428,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
method: "erpnext.stock.get_item_details.get_item_details",
|
method: "erpnext.stock.get_item_details.get_item_details",
|
||||||
child: item,
|
child: item,
|
||||||
args: {
|
args: {
|
||||||
|
doc: me.frm.doc,
|
||||||
args: {
|
args: {
|
||||||
item_code: item.item_code,
|
item_code: item.item_code,
|
||||||
barcode: item.barcode,
|
barcode: item.barcode,
|
||||||
@ -456,7 +463,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
cost_center: item.cost_center,
|
cost_center: item.cost_center,
|
||||||
tax_category: me.frm.doc.tax_category,
|
tax_category: me.frm.doc.tax_category,
|
||||||
item_tax_template: item.item_tax_template,
|
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.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) {
|
callback: function(r) {
|
||||||
if (!r.exc && r.message) {
|
if (!r.exc && r.message) {
|
||||||
r.message.forEach(row_item => {
|
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._set_values_for_item_list(r.message);
|
||||||
me.calculate_taxes_and_totals();
|
me.calculate_taxes_and_totals();
|
||||||
@ -1139,14 +1146,12 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
|
|
||||||
return this.frm.call({
|
return this.frm.call({
|
||||||
method: "erpnext.accounts.doctype.pricing_rule.pricing_rule.apply_pricing_rule",
|
method: "erpnext.accounts.doctype.pricing_rule.pricing_rule.apply_pricing_rule",
|
||||||
args: { args: args },
|
args: { args: args, doc: me.frm.doc },
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if (!r.exc && r.message) {
|
if (!r.exc && r.message) {
|
||||||
me._set_values_for_item_list(r.message);
|
me._set_values_for_item_list(r.message);
|
||||||
if(item) me.set_gross_profit(item);
|
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")
|
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,
|
"warehouse": d.warehouse,
|
||||||
"serial_no": d.serial_no,
|
"serial_no": d.serial_no,
|
||||||
"price_list_rate": d.price_list_rate,
|
"price_list_rate": d.price_list_rate,
|
||||||
"discount_percentage": d.discount_percentage || 0.0,
|
|
||||||
"conversion_factor": d.conversion_factor || 1.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 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) {
|
if(!me.frm.doc.ignore_pricing_rule && existing_pricing_rule && !d.pricing_rules) {
|
||||||
me.apply_price_list(frappe.get_doc(d.doctype, d.name));
|
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) {
|
validate_pricing_rule: function(item) {
|
||||||
var me = this;
|
let me = this;
|
||||||
|
const fields = ["discount_percentage", "discount_amount", "pricing_rules"];
|
||||||
|
|
||||||
if (item.pricing_rules) {
|
if (item.pricing_rules) {
|
||||||
frappe.call({
|
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: {
|
args: {
|
||||||
pricing_rules: item.pricing_rules,
|
doc: me.frm.doc
|
||||||
item_row: item
|
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
let items = [];
|
if (r.message) {
|
||||||
let child = '';
|
r.message.items.forEach(d => {
|
||||||
|
me.frm.doc.items.forEach(row => {
|
||||||
me.frm.doc.items.map(d => {
|
if(d.name == row.name) {
|
||||||
items[d.item_code] = d;
|
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,9 +1331,29 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
|
|
||||||
me.frm.doc.items = items;
|
me.frm.doc.items = items;
|
||||||
refresh_field('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() {
|
validate_company_and_party: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
var valid = true;
|
var valid = true;
|
||||||
@ -1379,7 +1393,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if(!r.exc) {
|
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();
|
me.calculate_taxes_and_totals();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
<base-image :src="image" :alt="title" />
|
<base-image :src="image" :alt="title" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-8">
|
<div class="col-md-8" style='padding-left: 30px;'>
|
||||||
<h2>{{ title }}</h2>
|
<h2>{{ title }}</h2>
|
||||||
<div class="text-muted">
|
<div class="text-muted">
|
||||||
<slot name="detail-header-item"></slot>
|
<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 frappe
|
||||||
import unittest
|
import unittest
|
||||||
|
from frappe.utils import getdate
|
||||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
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.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
||||||
from erpnext.stock.doctype.item.test_item import make_item
|
from erpnext.stock.doctype.item.test_item import make_item
|
||||||
@ -12,10 +13,27 @@ import json
|
|||||||
|
|
||||||
class TestGSTR3BReport(unittest.TestCase):
|
class TestGSTR3BReport(unittest.TestCase):
|
||||||
def test_gstr_3b_report(self):
|
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.set_user("Administrator")
|
||||||
|
|
||||||
frappe.db.sql("delete from `tabSales Invoice` where company='_Test Company GST'")
|
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 `tabPurchase Invoice` where company='_Test Company GST'")
|
||||||
|
frappe.db.sql("delete from `tabGSTR 3B Report` where company='_Test Company GST'")
|
||||||
|
|
||||||
make_company()
|
make_company()
|
||||||
make_item("Milk", properties = {"is_nil_exempt": 1, "standard_rate": 0.000000})
|
make_item("Milk", properties = {"is_nil_exempt": 1, "standard_rate": 0.000000})
|
||||||
@ -33,8 +51,8 @@ class TestGSTR3BReport(unittest.TestCase):
|
|||||||
"doctype": "GSTR 3B Report",
|
"doctype": "GSTR 3B Report",
|
||||||
"company": "_Test Company GST",
|
"company": "_Test Company GST",
|
||||||
"company_address": "_Test Address-Billing",
|
"company_address": "_Test Address-Billing",
|
||||||
"year": "2019",
|
"year": getdate().year,
|
||||||
"month": "March"
|
"month": month_number_mapping.get(getdate().month)
|
||||||
}).insert()
|
}).insert()
|
||||||
|
|
||||||
output = json.loads(report.json_output)
|
output = json.loads(report.json_output)
|
||||||
@ -55,7 +73,6 @@ def make_sales_invoice():
|
|||||||
income_account = 'Sales - _GST',
|
income_account = 'Sales - _GST',
|
||||||
expense_account = 'Cost of Goods Sold - _GST',
|
expense_account = 'Cost of Goods Sold - _GST',
|
||||||
cost_center = 'Main - _GST',
|
cost_center = 'Main - _GST',
|
||||||
posting_date = '2019-03-10',
|
|
||||||
do_not_save=1
|
do_not_save=1
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -77,7 +94,6 @@ def make_sales_invoice():
|
|||||||
income_account = 'Sales - _GST',
|
income_account = 'Sales - _GST',
|
||||||
expense_account = 'Cost of Goods Sold - _GST',
|
expense_account = 'Cost of Goods Sold - _GST',
|
||||||
cost_center = 'Main - _GST',
|
cost_center = 'Main - _GST',
|
||||||
posting_date = '2019-03-10',
|
|
||||||
do_not_save=1
|
do_not_save=1
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -99,7 +115,6 @@ def make_sales_invoice():
|
|||||||
income_account = 'Sales - _GST',
|
income_account = 'Sales - _GST',
|
||||||
expense_account = 'Cost of Goods Sold - _GST',
|
expense_account = 'Cost of Goods Sold - _GST',
|
||||||
cost_center = 'Main - _GST',
|
cost_center = 'Main - _GST',
|
||||||
posting_date = '2019-03-10',
|
|
||||||
do_not_save=1
|
do_not_save=1
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -122,7 +137,6 @@ def make_sales_invoice():
|
|||||||
income_account = 'Sales - _GST',
|
income_account = 'Sales - _GST',
|
||||||
expense_account = 'Cost of Goods Sold - _GST',
|
expense_account = 'Cost of Goods Sold - _GST',
|
||||||
cost_center = 'Main - _GST',
|
cost_center = 'Main - _GST',
|
||||||
posting_date = '2019-03-10',
|
|
||||||
do_not_save=1
|
do_not_save=1
|
||||||
)
|
)
|
||||||
si3.submit()
|
si3.submit()
|
||||||
@ -135,7 +149,6 @@ def create_purchase_invoices():
|
|||||||
currency = 'INR',
|
currency = 'INR',
|
||||||
warehouse = 'Finished Goods - _GST',
|
warehouse = 'Finished Goods - _GST',
|
||||||
cost_center = 'Main - _GST',
|
cost_center = 'Main - _GST',
|
||||||
posting_date = '2019-03-10',
|
|
||||||
do_not_save=1,
|
do_not_save=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -157,7 +170,6 @@ def create_purchase_invoices():
|
|||||||
currency = 'INR',
|
currency = 'INR',
|
||||||
warehouse = 'Finished Goods - _GST',
|
warehouse = 'Finished Goods - _GST',
|
||||||
cost_center = 'Main - _GST',
|
cost_center = 'Main - _GST',
|
||||||
posting_date = '2019-03-10',
|
|
||||||
item = "Milk",
|
item = "Milk",
|
||||||
do_not_save=1
|
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 Order Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
||||||
'Purchase Receipt 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],
|
'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': [
|
'Employee': [
|
||||||
dict(fieldname='ifsc_code', label='IFSC Code',
|
dict(fieldname='ifsc_code', label='IFSC Code',
|
||||||
fieldtype='Data', insert_after='bank_ac_no', print_hide=1,
|
fieldtype='Data', insert_after='bank_ac_no', print_hide=1,
|
||||||
|
@ -95,13 +95,12 @@
|
|||||||
<Cognome>{{ doc.customer_data.last_name }}</Cognome>
|
<Cognome>{{ doc.customer_data.last_name }}</Cognome>
|
||||||
</Anagrafica>
|
</Anagrafica>
|
||||||
{%- else %}
|
{%- else %}
|
||||||
{%- if doc.customer_data.is_public_administration %}
|
|
||||||
<CodiceFiscale>{{ doc.customer_data.fiscal_code }}</CodiceFiscale>
|
|
||||||
{%- else %}
|
|
||||||
<IdFiscaleIVA>
|
<IdFiscaleIVA>
|
||||||
<IdPaese>{{ doc.customer_address_data.country_code }}</IdPaese>
|
<IdPaese>{{ doc.customer_address_data.country_code }}</IdPaese>
|
||||||
<IdCodice>{{ doc.tax_id | replace("IT","") }}</IdCodice>
|
<IdCodice>{{ doc.tax_id | replace("IT","") }}</IdCodice>
|
||||||
</IdFiscaleIVA>
|
</IdFiscaleIVA>
|
||||||
|
{%- if doc.customer_data.fiscal_code %}
|
||||||
|
<CodiceFiscale>{{ doc.customer_data.fiscal_code }}</CodiceFiscale>
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
<Anagrafica>
|
<Anagrafica>
|
||||||
<Denominazione>{{ doc.customer_name }}</Denominazione>
|
<Denominazione>{{ doc.customer_name }}</Denominazione>
|
||||||
@ -128,22 +127,42 @@
|
|||||||
<ImportoBollo>{{ format_float(doc.stamp_duty) }}</ImportoBollo>
|
<ImportoBollo>{{ format_float(doc.stamp_duty) }}</ImportoBollo>
|
||||||
</DatiBollo>
|
</DatiBollo>
|
||||||
{%- endif %}
|
{%- 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>
|
<Causale>VENDITA</Causale>
|
||||||
</DatiGeneraliDocumento>
|
</DatiGeneraliDocumento>
|
||||||
{%- if doc.po_no %}
|
{%- for po_no, po_date in doc.customer_po_data.items() %}
|
||||||
<DatiOrdineAcquisto>
|
<DatiOrdineAcquisto>
|
||||||
<IdDocumento>{{ doc.po_no }}</IdDocumento>
|
<IdDocumento>{{ po_no }}</IdDocumento>
|
||||||
{%- if doc.po_date %}
|
<Data>{{ po_date }}</Data>
|
||||||
<Data>{{ doc.po_date }}</Data>
|
</DatiOrdineAcquisto>
|
||||||
{%- endif %}
|
{%- endfor %}
|
||||||
</DatiOrdineAcquisto>
|
|
||||||
{%- endif %}
|
|
||||||
{%- if doc.is_return and doc.return_against_unamended %}
|
{%- if doc.is_return and doc.return_against_unamended %}
|
||||||
<DatiFattureCollegate>
|
<DatiFattureCollegate>
|
||||||
<IdDocumento>{{ doc.return_against_unamended }}</IdDocumento>
|
<IdDocumento>{{ doc.return_against_unamended }}</IdDocumento>
|
||||||
</DatiFattureCollegate>
|
</DatiFattureCollegate>
|
||||||
{%- endif %}
|
{%- 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 %}
|
{%- if doc.shipping_address_data %}
|
||||||
<DatiTrasporto>
|
<DatiTrasporto>
|
||||||
<IndirizzoResa>
|
<IndirizzoResa>
|
||||||
@ -165,7 +184,11 @@
|
|||||||
<UnitaMisura>{{ item.stock_uom }}</UnitaMisura>
|
<UnitaMisura>{{ item.stock_uom }}</UnitaMisura>
|
||||||
<PrezzoUnitario>{{ format_float(item.price_list_rate or item.rate) }}</PrezzoUnitario>
|
<PrezzoUnitario>{{ format_float(item.price_list_rate or item.rate) }}</PrezzoUnitario>
|
||||||
{{ render_discount_or_margin(item) }}
|
{{ render_discount_or_margin(item) }}
|
||||||
<PrezzoTotale>{{ format_float(item.amount) }}</PrezzoTotale>
|
{%- 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>
|
<AliquotaIVA>{{ format_float(item.tax_rate) }}</AliquotaIVA>
|
||||||
{%- if item.tax_exemption_reason %}
|
{%- if item.tax_exemption_reason %}
|
||||||
<Natura>{{ item.tax_exemption_reason.split("-")[0] }}</Natura>
|
<Natura>{{ item.tax_exemption_reason.split("-")[0] }}</Natura>
|
||||||
@ -199,7 +222,9 @@
|
|||||||
<ModalitaPagamento>{{ payment_term.mode_of_payment_code.split("-")[0] }}</ModalitaPagamento>
|
<ModalitaPagamento>{{ payment_term.mode_of_payment_code.split("-")[0] }}</ModalitaPagamento>
|
||||||
<DataScadenzaPagamento>{{ payment_term.due_date }}</DataScadenzaPagamento>
|
<DataScadenzaPagamento>{{ payment_term.due_date }}</DataScadenzaPagamento>
|
||||||
<ImportoPagamento>{{ format_float(payment_term.payment_amount) }}</ImportoPagamento>
|
<ImportoPagamento>{{ format_float(payment_term.payment_amount) }}</ImportoPagamento>
|
||||||
<IstitutoFinanziario>{{ payment_term.bank_account_name }}</IstitutoFinanziario>
|
{%- if payment_term.bank_account_name %}
|
||||||
|
<IstitutoFinanziario>{{ payment_term.bank_account_name }}</IstitutoFinanziario>
|
||||||
|
{%- endif %}
|
||||||
{%- if payment_term.bank_account_iban %}
|
{%- if payment_term.bank_account_iban %}
|
||||||
<IBAN>{{ payment_term.bank_account_iban }}</IBAN>
|
<IBAN>{{ payment_term.bank_account_iban }}</IBAN>
|
||||||
<ABI>{{ payment_term.bank_account_iban[5:10] }}</ABI>
|
<ABI>{{ payment_term.bank_account_iban[5:10] }}</ABI>
|
||||||
|
@ -3,15 +3,26 @@ erpnext.setup_e_invoice_button = (doctype) => {
|
|||||||
refresh: (frm) => {
|
refresh: (frm) => {
|
||||||
if(frm.doc.docstatus == 1) {
|
if(frm.doc.docstatus == 1) {
|
||||||
frm.add_custom_button('Generate E-Invoice', () => {
|
frm.add_custom_button('Generate E-Invoice', () => {
|
||||||
var w = window.open(
|
frm.call({
|
||||||
frappe.urllib.get_full_url(
|
method: "erpnext.regional.italy.utils.generate_single_invoice",
|
||||||
"/api/method/erpnext.regional.italy.utils.generate_single_invoice?"
|
args: {
|
||||||
+ "docname=" + frm.doc.name
|
docname: frm.doc.name
|
||||||
)
|
},
|
||||||
)
|
callback: function(r) {
|
||||||
if (!w) {
|
frm.reload_doc();
|
||||||
frappe.msgprint(__("Please enable pop-ups")); return;
|
if(r.message) {
|
||||||
}
|
var w = window.open(
|
||||||
|
frappe.urllib.get_full_url(
|
||||||
|
"/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")
|
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 = {
|
custom_fields = {
|
||||||
'Company': [
|
'Company': [
|
||||||
dict(fieldname='sb_e_invoicing', label='E-Invoicing',
|
dict(fieldname='sb_e_invoicing', label='E-Invoicing',
|
||||||
@ -128,7 +144,7 @@ def make_custom_fields(update=True):
|
|||||||
'Purchase Invoice Item': invoice_item_fields,
|
'Purchase Invoice Item': invoice_item_fields,
|
||||||
'Sales Order Item': invoice_item_fields,
|
'Sales Order Item': invoice_item_fields,
|
||||||
'Delivery Note 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,
|
'Quotation Item': invoice_item_fields,
|
||||||
'Purchase Order Item': invoice_item_fields,
|
'Purchase Order Item': invoice_item_fields,
|
||||||
'Purchase Receipt 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 erpnext.controllers.taxes_and_totals import get_itemised_tax
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.core.doctype.file.file import remove_file
|
from frappe.core.doctype.file.file import remove_file
|
||||||
|
from six import string_types
|
||||||
from frappe.desk.form.load import get_attachments
|
from frappe.desk.form.load import get_attachments
|
||||||
from erpnext.regional.italy import state_codes
|
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:
|
if item.tax_rate == 0.0 and item.tax_amount == 0.0:
|
||||||
item.tax_exemption_reason = tax_data["0.0"]["tax_exemption_reason"]
|
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
|
return invoice
|
||||||
|
|
||||||
def get_conditions(filters):
|
def get_conditions(filters):
|
||||||
@ -134,6 +143,7 @@ def get_invoice_summary(items, taxes):
|
|||||||
idx=len(items)+1,
|
idx=len(items)+1,
|
||||||
item_code=reference_row.description,
|
item_code=reference_row.description,
|
||||||
item_name=reference_row.description,
|
item_name=reference_row.description,
|
||||||
|
description=reference_row.description,
|
||||||
rate=reference_row.tax_amount,
|
rate=reference_row.tax_amount,
|
||||||
qty=1.0,
|
qty=1.0,
|
||||||
amount=reference_row.tax_amount,
|
amount=reference_row.tax_amount,
|
||||||
@ -142,7 +152,7 @@ def get_invoice_summary(items, taxes):
|
|||||||
tax_amount=(reference_row.tax_amount * tax.rate) / 100,
|
tax_amount=(reference_row.tax_amount * tax.rate) / 100,
|
||||||
net_amount=reference_row.tax_amount,
|
net_amount=reference_row.tax_amount,
|
||||||
taxable_amount=reference_row.tax_amount,
|
taxable_amount=reference_row.tax_amount,
|
||||||
item_tax_rate="{}",
|
item_tax_rate={tax.account_head: tax.rate},
|
||||||
charges=True
|
charges=True
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -150,10 +160,16 @@ def get_invoice_summary(items, taxes):
|
|||||||
#Check item tax rates if tax rate is zero.
|
#Check item tax rates if tax rate is zero.
|
||||||
if tax.rate == 0:
|
if tax.rate == 0:
|
||||||
for item in items:
|
for item in items:
|
||||||
item_tax_rate = json.loads(item.item_tax_rate)
|
item_tax_rate = item.item_tax_rate
|
||||||
if tax.account_head in item_tax_rate:
|
if isinstance(item.item_tax_rate, string_types):
|
||||||
|
item_tax_rate = json.loads(item.item_tax_rate)
|
||||||
|
|
||||||
|
if item_tax_rate and tax.account_head in item_tax_rate:
|
||||||
key = cstr(item_tax_rate[tax.account_head])
|
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]["tax_amount"] += item.tax_amount
|
||||||
summary_data[key]["taxable_amount"] += item.net_amount
|
summary_data[key]["taxable_amount"] += item.net_amount
|
||||||
if key == "0.0":
|
if key == "0.0":
|
||||||
@ -198,19 +214,25 @@ def sales_invoice_validate(doc):
|
|||||||
else:
|
else:
|
||||||
doc.company_fiscal_regime = company_fiscal_regime
|
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:
|
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"))
|
frappe.throw(_("Please set either the Tax ID or Fiscal Code on Company '%s'" % doc.company), title=_("E-Invoicing Information Missing"))
|
||||||
|
|
||||||
#Validate customer details
|
#Validate customer details
|
||||||
customer_type, is_public_administration = frappe.db.get_value("Customer", doc.customer, ["customer_type", "is_public_administration"])
|
customer = frappe.get_doc("Customer", doc.customer)
|
||||||
if customer_type == _("Individual"):
|
|
||||||
|
if customer.customer_type == _("Individual"):
|
||||||
|
doc.customer_fiscal_code = customer.fiscal_code
|
||||||
if not doc.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"))
|
frappe.throw(_("Please set Fiscal Code for the customer '%s'" % doc.customer), title=_("E-Invoicing Information Missing"))
|
||||||
else:
|
else:
|
||||||
if is_public_administration:
|
if customer.is_public_administration:
|
||||||
|
doc.customer_fiscal_code = customer.fiscal_code
|
||||||
if not doc.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"))
|
frappe.throw(_("Please set Fiscal Code for the public administration '%s'" % doc.customer), title=_("E-Invoicing Information Missing"))
|
||||||
else:
|
else:
|
||||||
|
doc.tax_id = customer.tax_id
|
||||||
if not doc.tax_id:
|
if not doc.tax_id:
|
||||||
frappe.throw(_("Please set Tax ID for the customer '%s'" % doc.customer), title=_("E-Invoicing Information Missing"))
|
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):
|
def generate_single_invoice(docname):
|
||||||
doc = frappe.get_doc("Sales Invoice", docname)
|
doc = frappe.get_doc("Sales Invoice", docname)
|
||||||
|
|
||||||
|
|
||||||
e_invoice = prepare_and_attach_invoice(doc, True)
|
e_invoice = prepare_and_attach_invoice(doc, True)
|
||||||
|
|
||||||
|
return e_invoice.file_name
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def download_e_invoice_file(file_name):
|
||||||
content = None
|
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()
|
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.filecontent = content
|
||||||
frappe.local.response.type = "download"
|
frappe.local.response.type = "download"
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
frappe.query_reports["GSTR-1"] = {
|
frappe.query_reports["GSTR-1"] = {
|
||||||
"filters": [
|
"filters": [
|
||||||
{
|
{
|
||||||
"fieldname":"company",
|
"fieldname": "company",
|
||||||
"label": __("Company"),
|
"label": __("Company"),
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"options": "Company",
|
"options": "Company",
|
||||||
@ -12,22 +12,22 @@ frappe.query_reports["GSTR-1"] = {
|
|||||||
"default": frappe.defaults.get_user_default("Company")
|
"default": frappe.defaults.get_user_default("Company")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname":"company_address",
|
"fieldname": "company_address",
|
||||||
"label": __("Address"),
|
"label": __("Address"),
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"options": "Address",
|
"options": "Address",
|
||||||
"get_query": function() {
|
"get_query": function () {
|
||||||
var company = frappe.query_report.get_filter_value('company');
|
var company = frappe.query_report.get_filter_value('company');
|
||||||
if (company) {
|
if (company) {
|
||||||
return {
|
return {
|
||||||
"query": 'frappe.contacts.doctype.address.address.address_query',
|
"query": 'frappe.contacts.doctype.address.address.address_query',
|
||||||
"filters": { link_doctype: 'Company', link_name: company}
|
"filters": { link_doctype: 'Company', link_name: company }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname":"from_date",
|
"fieldname": "from_date",
|
||||||
"label": __("From Date"),
|
"label": __("From Date"),
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
@ -35,19 +35,34 @@ frappe.query_reports["GSTR-1"] = {
|
|||||||
"width": "80"
|
"width": "80"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname":"to_date",
|
"fieldname": "to_date",
|
||||||
"label": __("To Date"),
|
"label": __("To Date"),
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"default": frappe.datetime.get_today()
|
"default": frappe.datetime.get_today()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname":"type_of_business",
|
"fieldname": "type_of_business",
|
||||||
"label": __("Type of Business"),
|
"label": __("Type of Business"),
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"options": ["B2B", "B2C Large", "B2C Small","CDNR", "EXPORT"],
|
"options": ["B2B", "B2C Large", "B2C Small", "CDNR", "EXPORT"],
|
||||||
"default": "B2B"
|
"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
|
from __future__ import unicode_literals
|
||||||
import frappe, json
|
import frappe, json
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import flt, formatdate
|
from frappe.utils import flt, formatdate, now_datetime, getdate
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
|
from erpnext.regional.doctype.gstr_3b_report.gstr_3b_report import get_period
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
return Gstr1Report(filters).run()
|
return Gstr1Report(filters).run()
|
||||||
@ -38,7 +39,7 @@ class Gstr1Report(object):
|
|||||||
shipping_bill_date,
|
shipping_bill_date,
|
||||||
reason_for_issuing_document
|
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):
|
def run(self):
|
||||||
self.get_columns()
|
self.get_columns()
|
||||||
@ -113,9 +114,14 @@ class Gstr1Report(object):
|
|||||||
if self.filters.get(opts[0]):
|
if self.filters.get(opts[0]):
|
||||||
conditions += opts[1]
|
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":
|
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
|
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]))
|
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:
|
if not b2c_limit:
|
||||||
frappe.throw(_("Please set B2C Limit in GST Settings."))
|
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":
|
if self.filters.get("type_of_business") == "B2C Large":
|
||||||
conditions += """ and SUBSTR(place_of_supply, 1, 2) != SUBSTR(company_gstin, 1, 2)
|
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})""".\
|
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
|
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()
|
self.update_lead()
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
|
super(Quotation, self).on_cancel()
|
||||||
|
|
||||||
#update enquiry status
|
#update enquiry status
|
||||||
self.set_status(update=True)
|
self.set_status(update=True)
|
||||||
self.update_opportunity()
|
self.update_opportunity()
|
||||||
|
@ -183,6 +183,8 @@ class SalesOrder(SellingController):
|
|||||||
self.update_blanket_order()
|
self.update_blanket_order()
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
|
super(SalesOrder, self).on_cancel()
|
||||||
|
|
||||||
# Cannot cancel closed SO
|
# Cannot cancel closed SO
|
||||||
if self.status == 'Closed':
|
if self.status == 'Closed':
|
||||||
frappe.throw(_("Closed order cannot be cancelled. Unclose to cancel."))
|
frappe.throw(_("Closed order cannot be cancelled. Unclose to cancel."))
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import flt, add_days
|
from frappe.utils import flt, add_days, nowdate
|
||||||
import frappe.permissions
|
import frappe.permissions
|
||||||
import unittest
|
import unittest
|
||||||
from erpnext.selling.doctype.sales_order.sales_order \
|
from erpnext.selling.doctype.sales_order.sales_order \
|
||||||
@ -13,7 +13,6 @@ from erpnext.controllers.accounts_controller import update_child_qty_rate
|
|||||||
import json
|
import json
|
||||||
from erpnext.selling.doctype.sales_order.sales_order import make_raw_material_request
|
from erpnext.selling.doctype.sales_order.sales_order import make_raw_material_request
|
||||||
|
|
||||||
|
|
||||||
class TestSalesOrder(unittest.TestCase):
|
class TestSalesOrder(unittest.TestCase):
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
frappe.set_user("Administrator")
|
frappe.set_user("Administrator")
|
||||||
@ -710,6 +709,28 @@ class TestSalesOrder(unittest.TestCase):
|
|||||||
se.cancel()
|
se.cancel()
|
||||||
self.assertFalse(frappe.db.exists("Serial No", {"sales_order": so.name}))
|
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):
|
def test_request_for_raw_materials(self):
|
||||||
from erpnext.stock.doctype.item.test_item import make_item
|
from erpnext.stock.doctype.item.test_item import make_item
|
||||||
item = make_item("_Test Finished Item", {"is_stock_item": 1,
|
item = make_item("_Test Finished Item", {"is_stock_item": 1,
|
||||||
|
@ -244,4 +244,4 @@
|
|||||||
"track_changes": 1,
|
"track_changes": 1,
|
||||||
"track_seen": 0,
|
"track_seen": 0,
|
||||||
"track_views": 0
|
"track_views": 0
|
||||||
}
|
}
|
||||||
|
@ -233,9 +233,21 @@ erpnext.pos.PointOfSale = class PointOfSale {
|
|||||||
} else {
|
} else {
|
||||||
this.update_item_in_frm(item, field, value)
|
this.update_item_in_frm(item, field, value)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// update cart
|
frappe.dom.unfreeze();
|
||||||
this.update_cart_data(item);
|
frappe.run_serially([
|
||||||
this.set_form_action();
|
() => {
|
||||||
|
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.on_qty_change(item_row);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.on_qty_change(item);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
() => this.post_qty_change(item)
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -251,7 +263,28 @@ erpnext.pos.PointOfSale = class PointOfSale {
|
|||||||
frappe.flags.hide_serial_batch_dialog = true;
|
frappe.flags.hide_serial_batch_dialog = true;
|
||||||
|
|
||||||
frappe.run_serially([
|
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;
|
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)) ) {
|
(item.has_serial_no) || (item.actual_batch_qty != item.actual_qty)) ) {
|
||||||
// check has serial no/batch no and update cart
|
// check has serial no/batch no and update cart
|
||||||
this.select_batch_and_serial_no(item);
|
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) {
|
select_batch_and_serial_no(row) {
|
||||||
frappe.dom.unfreeze();
|
frappe.dom.unfreeze();
|
||||||
|
|
||||||
@ -283,7 +327,8 @@ erpnext.pos.PointOfSale = class PointOfSale {
|
|||||||
frappe.model.clear_doc(item.doctype, item.name);
|
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) {
|
update_cart_data(item) {
|
||||||
this.cart.add_item(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();
|
frappe.dom.unfreeze();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,16 +488,15 @@ erpnext.pos.PointOfSale = class PointOfSale {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setup_company() {
|
setup_company() {
|
||||||
this.company = frappe.sys_defaults.company;
|
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
if(!this.company) {
|
if(!frappe.sys_defaults.company) {
|
||||||
frappe.prompt({fieldname:"company", options: "Company", fieldtype:"Link",
|
frappe.prompt({fieldname:"company", options: "Company", fieldtype:"Link",
|
||||||
label: __("Select Company"), reqd: 1}, (data) => {
|
label: __("Select Company"), reqd: 1}, (data) => {
|
||||||
this.company = data.company;
|
this.company = data.company;
|
||||||
resolve(this.company);
|
resolve(this.company);
|
||||||
}, __("Select Company"));
|
}, __("Select Company"));
|
||||||
} else {
|
} else {
|
||||||
resolve(this.company);
|
resolve();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -509,7 +550,9 @@ erpnext.pos.PointOfSale = class PointOfSale {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set_pos_profile_data() {
|
set_pos_profile_data() {
|
||||||
this.frm.doc.company = this.company;
|
if (this.company) {
|
||||||
|
this.frm.doc.company = this.company;
|
||||||
|
}
|
||||||
|
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
return this.frm.call({
|
return this.frm.call({
|
||||||
@ -953,7 +996,6 @@ class POSCart {
|
|||||||
$item.appendTo(this.$cart_items);
|
$item.appendTo(this.$cart_items);
|
||||||
}
|
}
|
||||||
this.highlight_item(item.item_code);
|
this.highlight_item(item.item_code);
|
||||||
this.scroll_to_item(item.item_code);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update_item(item) {
|
update_item(item) {
|
||||||
@ -1206,7 +1248,10 @@ class POSItems {
|
|||||||
clearTimeout(this.last_search);
|
clearTimeout(this.last_search);
|
||||||
this.last_search = setTimeout(() => {
|
this.last_search = setTimeout(() => {
|
||||||
const search_term = e.target.value;
|
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);
|
}, 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 ""
|
batch_no = data.get("batch_no") if data.get("batch_no") else ""
|
||||||
barcode = data.get("barcode") if data.get("barcode") 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:
|
if pos_profile:
|
||||||
condition += get_item_group_condition(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
|
and {condition} limit {start}, {page_length}""".format
|
||||||
(start=start,page_length=page_length,lft=lft, rgt=rgt, condition=condition),
|
(start=start,page_length=page_length,lft=lft, rgt=rgt, condition=condition),
|
||||||
{
|
{
|
||||||
'item_code': item_code,
|
|
||||||
'price_list': price_list,
|
'price_list': price_list,
|
||||||
'warehouse': warehouse
|
'warehouse': warehouse
|
||||||
} , as_dict=1)
|
} , 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):
|
def get_conditions(item_code, serial_no, batch_no, barcode):
|
||||||
if serial_no or batch_no or 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
|
return """(i.name like {item_code}
|
||||||
or i.item_name like %(item_code)s)"""
|
or i.item_name like {item_code})""".format(item_code = frappe.db.escape('%' + item_code + '%'))
|
||||||
|
|
||||||
return frappe.db.escape('%' + item_code + '%'), condition
|
|
||||||
|
|
||||||
def get_item_group_condition(pos_profile):
|
def get_item_group_condition(pos_profile):
|
||||||
cond = "and 1=1"
|
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
|
// For license information, please see license.txt
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
||||||
frappe.query_reports["Sales Partner-wise Transaction Summary"] = {
|
frappe.query_reports["Sales Partner Transaction Summary"] = {
|
||||||
"filters": [
|
"filters": [
|
||||||
{
|
{
|
||||||
fieldname: "sales_partner",
|
fieldname: "sales_partner",
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"add_total_row": 1,
|
"add_total_row": 1,
|
||||||
"creation": "2019-03-15 16:21:16.088831",
|
"creation": "2019-03-25 18:15:09.920739",
|
||||||
"disable_prepared_report": 0,
|
"disable_prepared_report": 0,
|
||||||
"disabled": 0,
|
"disabled": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
@ -8,14 +8,14 @@
|
|||||||
"idx": 0,
|
"idx": 0,
|
||||||
"is_standard": "Yes",
|
"is_standard": "Yes",
|
||||||
"letter_head": "Gadgets International",
|
"letter_head": "Gadgets International",
|
||||||
"modified": "2019-03-15 16:21:16.088831",
|
"modified": "2019-03-25 18:15:09.920739",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Selling",
|
"module": "Selling",
|
||||||
"name": "Sales Partner-wise Transaction Summary",
|
"name": "Sales Partner Transaction Summary",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"prepared_report": 0,
|
"prepared_report": 0,
|
||||||
"ref_doctype": "Sales Order",
|
"ref_doctype": "Sales Order",
|
||||||
"report_name": "Sales Partner-wise Transaction Summary",
|
"report_name": "Sales Partner Transaction Summary",
|
||||||
"report_type": "Script Report",
|
"report_type": "Script Report",
|
||||||
"roles": [
|
"roles": [
|
||||||
{
|
{
|
@ -1,8 +1,16 @@
|
|||||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
// License: GNU General Public License v3. See license.txt
|
// 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": [
|
"filters": [
|
||||||
|
{
|
||||||
|
fieldname:"company",
|
||||||
|
label: __("Company"),
|
||||||
|
fieldtype: "Link",
|
||||||
|
options: "Company",
|
||||||
|
default: frappe.defaults.get_user_default("Company")
|
||||||
|
},
|
||||||
{
|
{
|
||||||
fieldname: "fiscal_year",
|
fieldname: "fiscal_year",
|
||||||
label: __("Fiscal Year"),
|
label: __("Fiscal Year"),
|
||||||
@ -10,6 +18,13 @@ frappe.query_reports["Territory Target Variance Item Group-Wise"] = {
|
|||||||
options: "Fiscal Year",
|
options: "Fiscal Year",
|
||||||
default: frappe.sys_defaults.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",
|
fieldname: "period",
|
||||||
label: __("Period"),
|
label: __("Period"),
|
@ -1,19 +1,21 @@
|
|||||||
{
|
{
|
||||||
"add_total_row": 0,
|
"add_total_row": 0,
|
||||||
"apply_user_permissions": 1,
|
"creation": "2019-03-25 22:16:49.040998",
|
||||||
"creation": "2013-06-21 12:15:00",
|
"disable_prepared_report": 0,
|
||||||
"disabled": 0,
|
"disabled": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "Report",
|
"doctype": "Report",
|
||||||
"idx": 3,
|
"idx": 0,
|
||||||
"is_standard": "Yes",
|
"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",
|
"modified_by": "Administrator",
|
||||||
"module": "Selling",
|
"module": "Selling",
|
||||||
"name": "Territory Target Variance Item Group-Wise",
|
"name": "Sales Person Target Variance Based On Item Group",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
|
"prepared_report": 0,
|
||||||
"ref_doctype": "Sales Order",
|
"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",
|
"report_type": "Script Report",
|
||||||
"roles": [
|
"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
|
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
// License: GNU General Public License v3. See license.txt
|
// 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": [
|
"filters": [
|
||||||
|
{
|
||||||
|
fieldname:"company",
|
||||||
|
label: __("Company"),
|
||||||
|
fieldtype: "Link",
|
||||||
|
options: "Company",
|
||||||
|
default: frappe.defaults.get_user_default("Company")
|
||||||
|
},
|
||||||
{
|
{
|
||||||
fieldname: "fiscal_year",
|
fieldname: "fiscal_year",
|
||||||
label: __("Fiscal Year"),
|
label: __("Fiscal Year"),
|
||||||
@ -10,6 +18,13 @@ frappe.query_reports["Sales Person Target Variance Item Group-Wise"] = {
|
|||||||
options: "Fiscal Year",
|
options: "Fiscal Year",
|
||||||
default: frappe.sys_defaults.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",
|
fieldname: "period",
|
||||||
label: __("Period"),
|
label: __("Period"),
|
@ -1,19 +1,21 @@
|
|||||||
{
|
{
|
||||||
"add_total_row": 0,
|
"add_total_row": 0,
|
||||||
"apply_user_permissions": 1,
|
"creation": "2019-03-25 22:20:59.033199",
|
||||||
"creation": "2013-06-21 12:14:15",
|
"disable_prepared_report": 0,
|
||||||
"disabled": 0,
|
"disabled": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "Report",
|
"doctype": "Report",
|
||||||
"idx": 3,
|
"idx": 0,
|
||||||
"is_standard": "Yes",
|
"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",
|
"modified_by": "Administrator",
|
||||||
"module": "Selling",
|
"module": "Selling",
|
||||||
"name": "Sales Person Target Variance Item Group-Wise",
|
"name": "Territory Target Variance Based On Item Group",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
|
"prepared_report": 0,
|
||||||
"ref_doctype": "Sales Order",
|
"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",
|
"report_type": "Script Report",
|
||||||
"roles": [
|
"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))
|
|
@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"brand": "_Test Brand",
|
"brand": "_Test Brand",
|
||||||
"doctype": "Brand"
|
"doctype": "Brand"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "details",
|
"fieldname": "details",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -54,6 +55,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "company_name",
|
"fieldname": "company_name",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -88,6 +90,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"description": "",
|
"description": "",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "abbr",
|
"fieldname": "abbr",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -122,6 +125,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:!doc.__islocal && in_list(frappe.user_roles, \"System Manager\")",
|
"depends_on": "eval:!doc.__islocal && in_list(frappe.user_roles, \"System Manager\")",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "change_abbr",
|
"fieldname": "change_abbr",
|
||||||
"fieldtype": "Button",
|
"fieldtype": "Button",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -153,6 +157,7 @@
|
|||||||
"bold": 1,
|
"bold": 1,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "is_group",
|
"fieldname": "is_group",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -185,6 +190,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "default_finance_book",
|
"fieldname": "default_finance_book",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -218,6 +224,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "cb0",
|
"fieldname": "cb0",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -248,6 +255,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "domain",
|
"fieldname": "domain",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -280,6 +288,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "parent_company",
|
"fieldname": "parent_company",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -313,6 +322,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "sb_about",
|
"fieldname": "sb_about",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -345,6 +355,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "company_logo",
|
"fieldname": "company_logo",
|
||||||
"fieldtype": "Attach Image",
|
"fieldtype": "Attach Image",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -377,6 +388,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "company_description",
|
"fieldname": "company_description",
|
||||||
"fieldtype": "Text Editor",
|
"fieldtype": "Text Editor",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -409,6 +421,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "sales_settings",
|
"fieldname": "sales_settings",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -441,6 +454,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "sales_monthly_history",
|
"fieldname": "sales_monthly_history",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
@ -473,6 +487,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "transactions_annual_history",
|
"fieldname": "transactions_annual_history",
|
||||||
"fieldtype": "Code",
|
"fieldtype": "Code",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
@ -505,6 +520,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "monthly_sales_target",
|
"fieldname": "monthly_sales_target",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -538,6 +554,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "column_break_goals",
|
"fieldname": "column_break_goals",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -569,6 +586,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "total_monthly_sales",
|
"fieldname": "total_monthly_sales",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -602,6 +620,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "charts_section",
|
"fieldname": "charts_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -633,6 +652,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "default_currency",
|
"fieldname": "default_currency",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -665,6 +685,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "default_letter_head",
|
"fieldname": "default_letter_head",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -698,6 +719,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "default_holiday_list",
|
"fieldname": "default_holiday_list",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -731,6 +753,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "standard_working_hours",
|
"fieldname": "standard_working_hours",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -763,6 +786,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "default_terms",
|
"fieldname": "default_terms",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -795,6 +819,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "column_break_10",
|
"fieldname": "column_break_10",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -826,6 +851,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "country",
|
"fieldname": "country",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -858,6 +884,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "create_chart_of_accounts_based_on",
|
"fieldname": "create_chart_of_accounts_based_on",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -892,6 +919,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:doc.create_chart_of_accounts_based_on===\"Standard Template\"",
|
"depends_on": "eval:doc.create_chart_of_accounts_based_on===\"Standard Template\"",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "chart_of_accounts",
|
"fieldname": "chart_of_accounts",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -926,6 +954,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:doc.create_chart_of_accounts_based_on===\"Existing Company\"",
|
"depends_on": "eval:doc.create_chart_of_accounts_based_on===\"Existing Company\"",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "existing_company",
|
"fieldname": "existing_company",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -959,6 +988,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "tax_id",
|
"fieldname": "tax_id",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -991,6 +1021,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "date_of_establishment",
|
"fieldname": "date_of_establishment",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1023,6 +1054,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "default_settings",
|
"fieldname": "default_settings",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1056,6 +1088,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:!doc.__islocal",
|
"depends_on": "eval:!doc.__islocal",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "default_bank_account",
|
"fieldname": "default_bank_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1091,6 +1124,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:!doc.__islocal",
|
"depends_on": "eval:!doc.__islocal",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "default_cash_account",
|
"fieldname": "default_cash_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1124,6 +1158,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:!doc.__islocal",
|
"depends_on": "eval:!doc.__islocal",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "default_receivable_account",
|
"fieldname": "default_receivable_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1158,6 +1193,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "round_off_account",
|
"fieldname": "round_off_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1191,6 +1227,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "round_off_cost_center",
|
"fieldname": "round_off_cost_center",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1224,6 +1261,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "write_off_account",
|
"fieldname": "write_off_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1257,6 +1295,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "discount_allowed_account",
|
"fieldname": "discount_allowed_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1290,6 +1329,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "discount_received_account",
|
"fieldname": "discount_received_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1323,6 +1363,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "exchange_gain_loss_account",
|
"fieldname": "exchange_gain_loss_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1356,6 +1397,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "unrealized_exchange_gain_loss_account",
|
"fieldname": "unrealized_exchange_gain_loss_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1389,6 +1431,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "column_break0",
|
"fieldname": "column_break0",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1414,6 +1457,40 @@
|
|||||||
"unique": 0,
|
"unique": 0,
|
||||||
"width": "50%"
|
"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_bulk_edit": 0,
|
||||||
"allow_in_quick_entry": 0,
|
"allow_in_quick_entry": 0,
|
||||||
@ -1422,6 +1499,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:!doc.__islocal",
|
"depends_on": "eval:!doc.__islocal",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "default_payable_account",
|
"fieldname": "default_payable_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1456,6 +1534,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "default_employee_advance_account",
|
"fieldname": "default_employee_advance_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1490,6 +1569,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:!doc.__islocal",
|
"depends_on": "eval:!doc.__islocal",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "default_expense_account",
|
"fieldname": "default_expense_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1523,6 +1603,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:!doc.__islocal",
|
"depends_on": "eval:!doc.__islocal",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "default_income_account",
|
"fieldname": "default_income_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1556,6 +1637,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:!doc.__islocal",
|
"depends_on": "eval:!doc.__islocal",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "default_deferred_revenue_account",
|
"fieldname": "default_deferred_revenue_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1590,6 +1672,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:!doc.__islocal",
|
"depends_on": "eval:!doc.__islocal",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "default_deferred_expense_account",
|
"fieldname": "default_deferred_expense_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1624,6 +1707,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:!doc.__islocal",
|
"depends_on": "eval:!doc.__islocal",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "default_payroll_payable_account",
|
"fieldname": "default_payroll_payable_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1658,6 +1742,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:!doc.__islocal",
|
"depends_on": "eval:!doc.__islocal",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "default_expense_claim_payable_account",
|
"fieldname": "default_expense_claim_payable_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1691,6 +1776,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "section_break_22",
|
"fieldname": "section_break_22",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1723,6 +1809,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:!doc.__islocal",
|
"depends_on": "eval:!doc.__islocal",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "cost_center",
|
"fieldname": "cost_center",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1755,6 +1842,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "column_break_26",
|
"fieldname": "column_break_26",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1787,6 +1875,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:!doc.__islocal",
|
"depends_on": "eval:!doc.__islocal",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "credit_limit",
|
"fieldname": "credit_limit",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1822,6 +1911,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "",
|
"depends_on": "",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "payment_terms",
|
"fieldname": "payment_terms",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1856,6 +1946,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:!doc.__islocal",
|
"depends_on": "eval:!doc.__islocal",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "auto_accounting_for_stock_settings",
|
"fieldname": "auto_accounting_for_stock_settings",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1888,6 +1979,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"default": "1",
|
"default": "1",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "enable_perpetual_inventory",
|
"fieldname": "enable_perpetual_inventory",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1920,6 +2012,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "default_inventory_account",
|
"fieldname": "default_inventory_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1953,6 +2046,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "stock_adjustment_account",
|
"fieldname": "stock_adjustment_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -1985,6 +2079,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "column_break_32",
|
"fieldname": "column_break_32",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2016,6 +2111,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "stock_received_but_not_billed",
|
"fieldname": "stock_received_but_not_billed",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2048,6 +2144,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "expenses_included_in_valuation",
|
"fieldname": "expenses_included_in_valuation",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2080,6 +2177,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "fixed_asset_depreciation_settings",
|
"fieldname": "fixed_asset_depreciation_settings",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2112,6 +2210,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "accumulated_depreciation_account",
|
"fieldname": "accumulated_depreciation_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2145,6 +2244,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "depreciation_expense_account",
|
"fieldname": "depreciation_expense_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2178,6 +2278,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "series_for_depreciation_entry",
|
"fieldname": "series_for_depreciation_entry",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2210,6 +2311,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "expenses_included_in_asset_valuation",
|
"fieldname": "expenses_included_in_asset_valuation",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2243,6 +2345,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "column_break_40",
|
"fieldname": "column_break_40",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2274,6 +2377,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "disposal_account",
|
"fieldname": "disposal_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2307,6 +2411,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "depreciation_cost_center",
|
"fieldname": "depreciation_cost_center",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2340,6 +2445,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "capital_work_in_progress_account",
|
"fieldname": "capital_work_in_progress_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2373,6 +2479,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "asset_received_but_not_billed",
|
"fieldname": "asset_received_but_not_billed",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2406,6 +2513,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "budget_detail",
|
"fieldname": "budget_detail",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2438,6 +2546,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "exception_budget_approver_role",
|
"fieldname": "exception_budget_approver_role",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2472,6 +2581,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"description": "For reference only.",
|
"description": "For reference only.",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "company_info",
|
"fieldname": "company_info",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2503,6 +2613,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "date_of_incorporation",
|
"fieldname": "date_of_incorporation",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2535,6 +2646,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "address_html",
|
"fieldname": "address_html",
|
||||||
"fieldtype": "HTML",
|
"fieldtype": "HTML",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2566,6 +2678,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "column_break1",
|
"fieldname": "column_break1",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2599,6 +2712,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:doc.date_of_incorporation",
|
"depends_on": "eval:doc.date_of_incorporation",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "date_of_commencement",
|
"fieldname": "date_of_commencement",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2631,6 +2745,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "phone_no",
|
"fieldname": "phone_no",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2665,6 +2780,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "fax",
|
"fieldname": "fax",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2699,6 +2815,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "email",
|
"fieldname": "email",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2733,6 +2850,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "website",
|
"fieldname": "website",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2767,6 +2885,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"description": "",
|
"description": "",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "registration_info",
|
"fieldname": "registration_info",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2801,6 +2920,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"description": "Company registration numbers for your reference. Tax numbers etc.",
|
"description": "Company registration numbers for your reference. Tax numbers etc.",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "registration_details",
|
"fieldname": "registration_details",
|
||||||
"fieldtype": "Code",
|
"fieldtype": "Code",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2834,6 +2954,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "delete_company_transactions",
|
"fieldname": "delete_company_transactions",
|
||||||
"fieldtype": "Button",
|
"fieldtype": "Button",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -2866,6 +2987,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "lft",
|
"fieldname": "lft",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
@ -2898,6 +3020,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "rgt",
|
"fieldname": "rgt",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
@ -2930,6 +3053,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "old_parent",
|
"fieldname": "old_parent",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
@ -2969,7 +3093,7 @@
|
|||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"menu_index": 0,
|
"menu_index": 0,
|
||||||
"modified": "2019-01-15 13:29:54.510379",
|
"modified": "2019-03-26 17:15:50.390548",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Setup",
|
"module": "Setup",
|
||||||
"name": "Company",
|
"name": "Company",
|
||||||
|
@ -13,5 +13,16 @@ frappe.ui.form.on('Sales Partner', {
|
|||||||
unhide_field(['address_html', 'contact_html', 'address_contacts']);
|
unhide_field(['address_html', 'contact_html', 'address_contacts']);
|
||||||
frappe.contacts.render_address_and_contact(frm);
|
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_copy": 0,
|
||||||
|
"allow_events_in_timeline": 0,
|
||||||
"allow_guest_to_view": 0,
|
"allow_guest_to_view": 0,
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 1,
|
"allow_rename": 1,
|
||||||
@ -21,6 +22,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "partner_name",
|
"fieldname": "partner_name",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -45,7 +47,7 @@
|
|||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
"unique": 0
|
"unique": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
@ -54,6 +56,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "partner_type",
|
"fieldname": "partner_type",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -89,6 +92,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"description": "",
|
"description": "",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "territory",
|
"fieldname": "territory",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -121,6 +125,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "column_break0",
|
"fieldname": "column_break0",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -153,6 +158,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "commission_rate",
|
"fieldname": "commission_rate",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -186,6 +192,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "address_contacts",
|
"fieldname": "address_contacts",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -218,6 +225,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:doc.__islocal",
|
"depends_on": "eval:doc.__islocal",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "address_desc",
|
"fieldname": "address_desc",
|
||||||
"fieldtype": "HTML",
|
"fieldtype": "HTML",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -249,6 +257,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "address_html",
|
"fieldname": "address_html",
|
||||||
"fieldtype": "HTML",
|
"fieldtype": "HTML",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -280,6 +289,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "column_break1",
|
"fieldname": "column_break1",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -311,6 +321,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:doc.__islocal",
|
"depends_on": "eval:doc.__islocal",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "contact_desc",
|
"fieldname": "contact_desc",
|
||||||
"fieldtype": "HTML",
|
"fieldtype": "HTML",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -342,6 +353,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "contact_html",
|
"fieldname": "contact_html",
|
||||||
"fieldtype": "HTML",
|
"fieldtype": "HTML",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -373,6 +385,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "partner_target_details_section_break",
|
"fieldname": "partner_target_details_section_break",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -405,6 +418,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "targets",
|
"fieldname": "targets",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -439,41 +453,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"description": "Select Monthly Distribution to unevenly distribute targets across months.",
|
"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": 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,
|
|
||||||
"fieldname": "website",
|
"fieldname": "website",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -505,6 +485,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "show_in_website",
|
"fieldname": "show_in_website",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -537,6 +518,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "show_in_website",
|
"depends_on": "show_in_website",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "section_break_17",
|
"fieldname": "section_break_17",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -567,6 +549,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "route",
|
"fieldname": "route",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -599,6 +582,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "column_break_20",
|
"fieldname": "column_break_20",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -629,6 +613,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "logo",
|
"fieldname": "logo",
|
||||||
"fieldtype": "Attach",
|
"fieldtype": "Attach",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -661,6 +646,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "partner_website",
|
"fieldname": "partner_website",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -693,6 +679,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "show_in_website",
|
"depends_on": "show_in_website",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "section_break_22",
|
"fieldname": "section_break_22",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -723,6 +710,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "introduction",
|
"fieldname": "introduction",
|
||||||
"fieldtype": "Text",
|
"fieldtype": "Text",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -754,6 +742,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "description",
|
"fieldname": "description",
|
||||||
"fieldtype": "Text Editor",
|
"fieldtype": "Text Editor",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -790,7 +779,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2018-06-11 13:47:04.182339",
|
"modified": "2019-03-21 16:26:45.447265",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Setup",
|
"module": "Setup",
|
||||||
"name": "Sales Partner",
|
"name": "Sales Partner",
|
||||||
@ -860,5 +849,6 @@
|
|||||||
"show_name_in_global_search": 1,
|
"show_name_in_global_search": 1,
|
||||||
"sort_order": "ASC",
|
"sort_order": "ASC",
|
||||||
"track_changes": 0,
|
"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}',
|
frm.dashboard.add_indicator(__('Total Contribution Amount: {0}',
|
||||||
[format_currency(info.allocated_amount, info.currency)]), 'blue');
|
[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,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "name_and_employee_id",
|
"fieldname": "name_and_employee_id",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -54,6 +55,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "sales_person_name",
|
"fieldname": "sales_person_name",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -88,6 +90,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"description": "Select company name first.",
|
"description": "Select company name first.",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "parent_sales_person",
|
"fieldname": "parent_sales_person",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -122,6 +125,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "commission_rate",
|
"fieldname": "commission_rate",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -154,6 +158,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "is_group",
|
"fieldname": "is_group",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -189,6 +194,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"default": "1",
|
"default": "1",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "enabled",
|
"fieldname": "enabled",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -221,6 +227,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "cb0",
|
"fieldname": "cb0",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -251,6 +258,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "employee",
|
"fieldname": "employee",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -284,6 +292,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fetch_from": "employee.department",
|
"fetch_from": "employee.department",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "department",
|
"fieldname": "department",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -317,6 +326,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "lft",
|
"fieldname": "lft",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
@ -350,6 +360,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "rgt",
|
"fieldname": "rgt",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
@ -383,6 +394,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "old_parent",
|
"fieldname": "old_parent",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
@ -417,6 +429,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"description": "Set targets Item Group-wise for this Sales Person.",
|
"description": "Set targets Item Group-wise for this Sales Person.",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "target_details_section_break",
|
"fieldname": "target_details_section_break",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -450,6 +463,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "targets",
|
"fieldname": "targets",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -476,41 +490,6 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
"unique": 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,
|
"has_web_view": 0,
|
||||||
@ -524,7 +503,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2019-01-30 11:28:16.966735",
|
"modified": "2019-03-21 16:26:01.706129",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Setup",
|
"module": "Setup",
|
||||||
"name": "Sales Person",
|
"name": "Sales Person",
|
||||||
|
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