Compare commits

...

23 Commits

Author SHA1 Message Date
Ameya Shenoy
a7ae06eadb Merge branch 'staging-fixes' into staging 2018-09-26 08:52:54 +00:00
Ameya Shenoy
90197dd341 bumped to version 11.0.3-beta.2 2018-09-26 08:52:54 +00:00
Ameya Shenoy
41d1982b90 Merge pull request #15501 from codingCoffee/qwe
fix(multiple): syntax and patch
2018-09-26 14:12:01 +05:30
Ameya Shenoy
12ec142a69 fix(multiple): syntax and patch
- syntax fix for using super class
- check "All Departments" in department name with translations
2018-09-26 14:05:48 +05:30
Ameya Shenoy
47b82789ae Merge branch 'staging-fixes' into staging 2018-09-26 07:32:44 +00:00
Ameya Shenoy
b8a5fb7392 bumped to version 11.0.3 2018-09-26 07:32:44 +00:00
Ameya Shenoy
9d3a97fd15 Merge branch 'master' into staging-fixes 2018-09-26 07:28:53 +00:00
Ameya Shenoy
0ff35a852a Merge branch 'hotfix' 2018-09-26 07:26:49 +00:00
Ameya Shenoy
e04431ea5c bumped to version 10.1.54 2018-09-26 07:26:49 +00:00
deepeshgarg007
86152eb5c8 Sales person Commission Report and more (#15431)
* Commission For Sales Person

* Changes Made

* Changes made in sales person dashboard and commission report

* Update sales_person_commission_summary.py
2018-09-25 19:08:16 +05:30
rohitwaghchaure
fafc277666 [Fix] BOM update tool, too many writes in one request. Please send smaller requests (#15432) 2018-09-25 18:59:20 +05:30
Aditya Hase
865cb88bdd fix(vscode-intellisense): Make VS Code Intellisense work with ERPNext (#15453)
__init__.py in apps/erpnext directory confuses vs code.

Causing all erpnext dotted paths to need an extra `erpnext.` for 
suggestion and completion to work properly.

This commit fixes this issue.
2018-09-25 18:51:17 +05:30
rohitwaghchaure
fe1e4a41e6 Validate negative stock serial number (#15492) 2018-09-25 18:36:32 +05:30
Faris Ansari
7a8c5b0c2c fix(setup wizard): Validate FY dates (#15473) 2018-09-25 18:34:33 +05:30
Aditya Hase
a38b77cbfd feature(chart-of-accounts): Rebuild HSM Tree after bulk insertion (#15457)
* feature(chart-of-accounts): Rebuild HSM Tree after bulk insertion

* Update chart_of_accounts.py
2018-09-25 18:10:50 +05:30
Zarrar
b113349f31 minor fix for auto-opt-in for customer (#15483) 2018-09-24 14:30:07 +05:30
Shreya Shah
0a95b31aea Merge pull request #15454 from frappe/coverage-badge
Add coverage badge to README.md
2018-09-24 12:25:06 +05:30
Ameya Shenoy
2b5bce0c53 Merge branch 'staging-fixes' into staging 2018-09-21 11:04:20 +00:00
Ameya Shenoy
cdedb27cf0 bumped to version 11.0.2 2018-09-21 11:04:20 +00:00
Zarrar
e83ff38c10 [Enhance] Deferred Expense (#15437)
* added section for deferred expense in item master

* added default expense account field in Company master

* added deferred expense section in purchase invoice item

* validation and getter code added

* scheduler event to book expense every month

* codacy, import fix and other minor fixes

* rectify debit credit logic for expense

* commonify js code for deferred expense and revenue

* remove deferred calculation and validation

* common file to calculate deferred revenue and expense

* codacy fixes

* expense account root_type - Asset, specific method naming
2018-09-21 15:45:40 +05:30
Aditya Hase
40880da280 fix(readme): Add coverage badge 2018-09-20 17:48:35 +05:30
Aditya Hase
6886c47251 fix(style): Center align badges as well 2018-09-20 17:46:53 +05:30
Aditya Hase
99c8fb19f7 fix(style): Put markdown for badges on separate lines 2018-09-20 17:43:04 +05:30
30 changed files with 1266 additions and 291 deletions

View File

@@ -4,12 +4,16 @@
<p align="center">
<p>ERP made simple</p>
</p>
</div>
[![Build Status](https://travis-ci.com/frappe/erpnext.png)](https://travis-ci.com/frappe/erpnext) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/frappe/erpnext?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Open Source Helpers](https://www.codetriage.com/frappe/erpnext/badges/users.svg)](https://www.codetriage.com/frappe/erpnext)
[![Build Status](https://travis-ci.com/frappe/erpnext.png)](https://travis-ci.com/frappe/erpnext)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/frappe/erpnext?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Open Source Helpers](https://www.codetriage.com/frappe/erpnext/badges/users.svg)](https://www.codetriage.com/frappe/erpnext)
[![Coverage Status](https://coveralls.io/repos/github/frappe/erpnext/badge.svg?branch=develop)](https://coveralls.io/github/frappe/erpnext?branch=develop)
[https://erpnext.com](https://erpnext.com)
</div>
Includes: Accounting, Inventory, Manufacturing, CRM, Sales, Purchase, Project Management, HRMS. Requires MariaDB.
ERPNext is built on the [Frappe](https://github.com/frappe/frappe) Framework, a full-stack web app framework in Python & JavaScript.

View File

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

View File

@@ -0,0 +1,179 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import date_diff, add_months, today, getdate, add_days, flt
from erpnext.accounts.utils import get_account_currency
from erpnext.accounts.general_ledger import make_gl_entries
def validate_service_stop_date(doc):
''' Validates service_stop_date for Purchase Invoice and Sales Invoice '''
enable_check = "enable_deferred_revenue" \
if doc.doctype=="Sales Invoice" else "enable_deferred_expense"
old_stop_dates = {}
old_doc = frappe.db.get_all("{0} Item".format(doc.doctype),
{"parent": doc.name}, ["name", "service_stop_date"])
for d in old_doc:
old_stop_dates[d.name] = d.service_stop_date or ""
for item in doc.items:
if not item.get(enable_check): continue
if item.service_stop_date:
if date_diff(item.service_stop_date, item.service_start_date) < 0:
frappe.throw(_("Service Stop Date cannot be before Service Start Date"))
if date_diff(item.service_stop_date, item.service_end_date) > 0:
frappe.throw(_("Service Stop Date cannot be after Service End Date"))
if old_stop_dates and old_stop_dates[item.name] and item.service_stop_date!=old_stop_dates[item.name]:
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):
# check for the purchase invoice for which GL entries has to be done
invoices = frappe.db.sql_list('''
select parent from `tabPurchase Invoice Item` where service_start_date<=%s and service_end_date>=%s
and enable_deferred_expense = 1 and docstatus = 1
''', (end_date or today(), start_date or add_months(today(), -1)))
# For each invoice, book deferred expense
for invoice in invoices:
doc = frappe.get_doc("Purchase Invoice", invoice)
book_deferred_income_or_expense(doc, start_date, end_date)
def convert_deferred_revenue_to_income(start_date=None, end_date=None):
# check for the sales invoice for which GL entries has to be done
invoices = frappe.db.sql_list('''
select parent from `tabSales Invoice Item` where service_start_date<=%s and service_end_date>=%s
and enable_deferred_revenue = 1 and docstatus = 1
''', (end_date or today(), start_date or add_months(today(), -1)))
# For each invoice, book deferred revenue
for invoice in invoices:
doc = frappe.get_doc("Sales Invoice", invoice)
book_deferred_income_or_expense(doc, start_date, end_date)
def get_booking_dates(doc, item, start_date=None, end_date=None):
deferred_account = "deferred_revenue_account" if doc.doctype=="Sales Invoice" else "deferred_expense_account"
last_gl_entry, skip = False, False
booking_end_date = getdate(add_days(today(), -1)) if not end_date else end_date
if booking_end_date < item.service_start_date or \
(item.service_stop_date and booking_end_date.month > item.service_stop_date.month):
return None, None, None, True
elif booking_end_date >= item.service_end_date:
last_gl_entry = True
booking_end_date = item.service_end_date
elif item.service_stop_date and item.service_stop_date <= booking_end_date:
last_gl_entry = True
booking_end_date = item.service_stop_date
booking_start_date = getdate(add_months(today(), -1)) if not start_date else start_date
booking_start_date = booking_start_date \
if booking_start_date > item.service_start_date else item.service_start_date
prev_gl_entry = frappe.db.sql('''
select name, posting_date from `tabGL Entry` where company=%s and account=%s and
voucher_type=%s and voucher_no=%s and voucher_detail_no=%s
order by posting_date desc limit 1
''', (doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True)
if not prev_gl_entry and item.service_start_date < booking_start_date:
booking_start_date = item.service_start_date
elif prev_gl_entry:
booking_start_date = getdate(add_days(prev_gl_entry[0].posting_date, 1))
skip = True if booking_start_date > booking_end_date else False
return last_gl_entry, booking_start_date, booking_end_date, skip
def calculate_amount_and_base_amount(doc, item, last_gl_entry, total_days, total_booking_days):
account_currency = get_account_currency(item.expense_account)
if doc.doctype == "Sales Invoice":
total_credit_debit, total_credit_debit_currency = "debit", "debit_in_account_currency"
deferred_account = "deferred_revenue_account"
else:
total_credit_debit, total_credit_debit_currency = "credit", "credit_in_account_currency"
deferred_account = "deferred_expense_account"
amount, base_amount = 0, 0
if not last_gl_entry:
base_amount = flt(item.base_net_amount*total_booking_days/flt(total_days), item.precision("base_net_amount"))
if account_currency==doc.company_currency:
amount = base_amount
else:
amount = flt(item.net_amount*total_booking_days/flt(total_days), item.precision("net_amount"))
else:
gl_entries_details = frappe.db.sql('''
select sum({0}) as total_credit, sum({1}) as total_credit_in_account_currency, voucher_detail_no
from `tabGL Entry` where company=%s and account=%s and voucher_type=%s and voucher_no=%s and voucher_detail_no=%s
group by voucher_detail_no
'''.format(total_credit_debit, total_credit_debit_currency),
(doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True)
already_booked_amount = gl_entries_details[0].total_credit if gl_entries_details else 0
base_amount = flt(item.base_net_amount - already_booked_amount, item.precision("base_net_amount"))
if account_currency==doc.company_currency:
amount = base_amount
else:
already_booked_amount_in_account_currency = gl_entries_details[0].total_credit_in_account_currency if gl_entries_details else 0
amount = flt(item.net_amount - already_booked_amount_in_account_currency, item.precision("net_amount"))
return amount, base_amount
def book_deferred_income_or_expense(doc, start_date=None, end_date=None):
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
# start_date: 1st of the last month or the start date
# end_date: end_date or today-1
gl_entries = []
for item in doc.get('items'):
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)
total_booking_days = date_diff(booking_end_date, booking_start_date) + 1
account_currency = get_account_currency(item.expense_account)
amount, base_amount = calculate_amount_and_base_amount(doc, item, last_gl_entry, total_days, total_booking_days)
if doc.doctype == "Sales Invoice":
against, project = doc.customer, doc.project
credit_account, debit_account = item.income_account, item.deferred_revenue_account
else:
against, project = doc.supplier, item.project
credit_account, debit_account = item.deferred_expense_account, item.expense_account
# GL Entry for crediting the amount in the deferred expense
gl_entries.append(
doc.get_gl_dict({
"account": credit_account,
"against": against,
"credit": base_amount,
"credit_in_account_currency": amount,
"cost_center": item.cost_center,
'posting_date': booking_end_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": item.cost_center,
"voucher_detail_no": item.name,
'posting_date': booking_end_date,
'project': project
}, account_currency)
)
if gl_entries:
make_gl_entries(gl_entries, cancel=(doc.docstatus == 2), merge_entries=True)

View File

@@ -12,6 +12,11 @@ class BalanceMismatchError(frappe.ValidationError): pass
class Account(NestedSet):
nsm_parent_field = 'parent_account'
def on_update(self):
if frappe.local.flags.ignore_on_update:
return
else:
super(Account, self).on_update()
def onload(self):
frozen_accounts_modifier = frappe.db.get_value("Accounts Settings", "Accounts Settings",

View File

@@ -6,6 +6,7 @@ import frappe, os, json
from frappe.utils import cstr
from unidecode import unidecode
from six import iteritems
from frappe.utils.nestedset import rebuild_tree
def create_charts(company, chart_template=None, existing_company=None):
chart = get_chart(chart_template, existing_company)
@@ -53,7 +54,12 @@ def create_charts(company, chart_template=None, existing_company=None):
_import_accounts(child, account.name, root_type)
# Rebuild NestedSet HSM tree for Account Doctype
# after all accounts are already inserted.
frappe.local.flags.ignore_on_update = True
_import_accounts(chart, None, None, root_account=True)
rebuild_tree("Account", "parent_account")
frappe.local.flags.ignore_on_update = False
def add_suffix_if_duplicate(account_name, account_number, accounts):
if account_number:

View File

@@ -496,6 +496,16 @@ frappe.ui.form.on("Purchase Invoice", {
'Purchase Invoice': 'Debit Note',
'Payment Entry': 'Payment'
}
frm.fields_dict['items'].grid.get_field('deferred_expense_account').get_query = function(doc) {
return {
filters: {
'root_type': 'Asset',
'company': doc.company,
"is_group": 0
}
}
}
},
onload: function(frm) {

View File

@@ -22,6 +22,7 @@ from six import iteritems
from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_invoice,\
unlink_inter_company_invoice
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details
from erpnext.accounts.deferred_revenue import validate_service_stop_date
form_grid_templates = {
"items": "templates/form_grid/item_grid.html"
@@ -74,6 +75,9 @@ class PurchaseInvoice(BuyingController):
if (self.is_paid == 1):
self.validate_cash()
# validate service stop date to lie in between start and end date
validate_service_stop_date(self)
if self._action=="submit" and self.update_stock:
self.make_batches('warehouse')
@@ -448,7 +452,7 @@ class PurchaseInvoice(BuyingController):
elif not item.is_fixed_asset:
gl_entries.append(
self.get_gl_dict({
"account": item.expense_account,
"account": item.expense_account if not item.enable_deferred_expense else item.deferred_expense_account,
"against": self.supplier,
"debit": flt(item.base_net_amount, item.precision("base_net_amount")),
"debit_in_account_currency": (flt(item.base_net_amount,

View File

@@ -1680,8 +1680,229 @@
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"collapsible": 1,
"columns": 0,
"fieldname": "deferred_expense_section",
"fieldtype": "Section Break",
"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": "Deferred Expense",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "enable_deferred_expense",
"fieldname": "deferred_expense_account",
"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": "Deferred Expense Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "enable_deferred_expense",
"fieldname": "service_stop_date",
"fieldtype": "Date",
"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": "Service Stop Date",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "enable_deferred_expense",
"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": "Enable Deferred Expense",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_58",
"fieldtype": "Column Break",
"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,
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "enable_deferred_expense",
"fieldname": "service_start_date",
"fieldtype": "Date",
"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": "Service Start Date",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "enable_deferred_expense",
"fieldname": "service_end_date",
"fieldtype": "Date",
"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": "Service End Date",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "reference",
"fieldtype": "Section Break",
"hidden": 0,
@@ -2323,7 +2544,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-08-06 05:18:38.205356",
"modified": "2018-09-04 10:11:28.246395",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",
@@ -2336,5 +2557,6 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
}
"track_seen": 0,
"track_views": 0
}

View File

@@ -572,7 +572,7 @@ def save_invoice(doc, name, name_list):
frappe.db.commit()
name_list.append(name)
except Exception:
frappe.log_error(frappe.get_traceback())
frappe.db.rollback()
frappe.log_error(frappe.get_traceback())
return name_list

View File

@@ -786,39 +786,6 @@ frappe.ui.form.on('Sales Invoice Timesheet', {
}
})
frappe.ui.form.on('Sales Invoice Item', {
service_stop_date: function(frm, cdt, cdn) {
var child = locals[cdt][cdn];
if(child.service_stop_date) {
let start_date = Date.parse(child.service_start_date);
let end_date = Date.parse(child.service_end_date);
let stop_date = Date.parse(child.service_stop_date);
if(stop_date < start_date) {
frappe.model.set_value(cdt, cdn, "service_stop_date", "");
frappe.throw(__("Service Stop Date cannot be before Service Start Date"));
} else if (stop_date > end_date) {
frappe.model.set_value(cdt, cdn, "service_stop_date", "");
frappe.throw(__("Service Stop Date cannot be after Service End Date"));
}
}
},
service_start_date: function(frm, cdt, cdn) {
var child = locals[cdt][cdn];
if(child.service_start_date) {
frappe.call({
"method": "erpnext.stock.get_item_details.calculate_service_end_date",
args: {"args": child},
callback: function(r) {
frappe.model.set_value(cdt, cdn, "service_end_date", r.message.service_end_date);
}
})
}
}
})
var calculate_total_billing_amount = function(frm) {
var doc = frm.doc;

View File

@@ -23,6 +23,7 @@ from erpnext.setup.doctype.company.company import update_company_current_month_s
from erpnext.accounts.general_ledger import get_round_off_account_and_cost_center
from erpnext.accounts.doctype.loyalty_program.loyalty_program import \
get_loyalty_program_details_with_points, get_loyalty_details, validate_loyalty_points
from erpnext.accounts.deferred_revenue import validate_service_stop_date
from erpnext.healthcare.utils import manage_invoice_submit_cancel
@@ -92,7 +93,7 @@ class SalesInvoice(SellingController):
self.validate_delivery_note()
# validate service stop date to lie in between start and end date
self.validate_service_stop_date()
validate_service_stop_date(self)
if not self.is_opening:
self.is_opening = 'No'
@@ -558,24 +559,6 @@ class SalesInvoice(SellingController):
if frappe.db.get_value("Sales Order Item", item.so_detail, "delivered_by_supplier"):
frappe.throw(_("Could not update stock, invoice contains drop shipping item."))
def validate_service_stop_date(self):
old_doc = frappe.db.get_all("Sales Invoice Item", {"parent": self.name}, ["name", "service_stop_date"])
old_stop_dates = {}
for d in old_doc:
old_stop_dates[d.name] = d.service_stop_date or ""
for item in self.items:
if item.enable_deferred_revenue:
if item.service_stop_date:
if date_diff(item.service_stop_date, item.service_start_date) < 0:
frappe.throw(_("Service Stop Date cannot be before Service Start Date"))
if date_diff(item.service_stop_date, item.service_end_date) > 0:
frappe.throw(_("Service Stop Date cannot be after Service End Date"))
if old_stop_dates and old_stop_dates[item.name] and item.service_stop_date!=old_stop_dates[item.name]:
frappe.throw(_("Cannot change Service Stop Date for item in row {0}".format(item.idx)))
def update_current_stock(self):
for d in self.get('items'):
if d.item_code and d.warehouse:
@@ -1059,9 +1042,11 @@ class SalesInvoice(SellingController):
# valdite the redemption and then delete the loyalty points earned on cancel of the invoice
def delete_loyalty_point_entry(self):
lp_entry = frappe.db.sql("select name from `tabLoyalty Point Entry` where sales_invoice=%s",
(self.name), as_dict=1)[0]
(self.name), as_dict=1)
if not lp_entry: return
against_lp_entry = frappe.db.sql('''select name, sales_invoice from `tabLoyalty Point Entry`
where redeem_against=%s''', (lp_entry.name), as_dict=1)
where redeem_against=%s''', (lp_entry[0].name), as_dict=1)
if against_lp_entry:
invoice_list = ", ".join([d.sales_invoice for d in against_lp_entry])
frappe.throw(_('''Sales Invoice can't be cancelled since the Loyalty Points earned has been redeemed.
@@ -1119,92 +1104,6 @@ class SalesInvoice(SellingController):
if points_to_redeem < 1: # since points_to_redeem is integer
break
def book_income_for_deferred_revenue(self, start_date=None, end_date=None):
# book the 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
gl_entries = []
for item in self.get('items'):
last_gl_entry = 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):
continue
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
if item.service_start_date < booking_start_date:
prev_gl_entry = frappe.db.sql('''
select name, posting_date from `tabGL Entry` where company=%s and account=%s and
voucher_type=%s and voucher_no=%s and voucher_detail_no=%s
order by posting_date desc limit 1
''', (self.company, item.deferred_revenue_account, "Sales Invoice", self.name, item.name), as_dict=True)
if not prev_gl_entry:
booking_start_date = item.service_start_date
else:
booking_start_date = getdate(add_days(prev_gl_entry[0].posting_date, 1))
total_days = date_diff(item.service_end_date, item.service_start_date)
total_booking_days = date_diff(booking_end_date, booking_start_date) + 1
account_currency = get_account_currency(item.income_account)
if not last_gl_entry:
base_amount = flt(item.base_net_amount*total_booking_days/flt(total_days), item.precision("base_net_amount"))
if account_currency==self.company_currency:
amount = base_amount
else:
amount = flt(item.net_amount*total_booking_days/flt(total_days), item.precision("net_amount"))
else:
gl_entries_details = frappe.db.sql('''
select sum(debit) as total_debit, sum(debit_in_account_currency) as total_debit_in_account_currency, voucher_detail_no
from `tabGL Entry` where company=%s and account=%s and voucher_type=%s and voucher_no=%s and voucher_detail_no=%s
group by voucher_detail_no
''', (self.company, item.deferred_revenue_account, "Sales Invoice", self.name, item.name), as_dict=True)
already_booked_amount = gl_entries_details[0].total_debit if gl_entries_details else 0
base_amount = flt(item.base_net_amount - already_booked_amount, item.precision("base_net_amount"))
if account_currency==self.company_currency:
amount = base_amount
else:
already_booked_amount_in_account_currency = gl_entries_details[0].total_debit_in_account_currency if gl_entries_details else 0
amount = flt(item.net_amount - already_booked_amount_in_account_currency, item.precision("net_amount"))
# GL Entry for crediting the amount in the income
gl_entries.append(
self.get_gl_dict({
"account": item.income_account,
"against": self.customer,
"credit": base_amount,
"credit_in_account_currency": amount,
"cost_center": item.cost_center,
'posting_date': booking_end_date
}, account_currency)
)
# GL Entry to debit the amount from the deferred account
gl_entries.append(
self.get_gl_dict({
"account": item.deferred_revenue_account,
"against": self.customer,
"debit": base_amount,
"debit_in_account_currency": amount,
"cost_center": item.cost_center,
"voucher_detail_no": item.name,
'posting_date': booking_end_date
}, account_currency)
)
if gl_entries:
from erpnext.accounts.general_ledger import make_gl_entries
make_gl_entries(gl_entries, cancel=(self.docstatus == 2), merge_entries=True)
# Healthcare
def set_healthcare_services(self, checked_values):
self.set("items", [])
@@ -1243,19 +1142,6 @@ class SalesInvoice(SellingController):
self.set_missing_values(for_validate = True)
def booked_deferred_revenue(start_date=None, end_date=None):
# check for the sales invoice for which GL entries has to be done
invoices = frappe.db.sql_list('''
select parent from `tabSales Invoice Item` where service_start_date<=%s and service_end_date>=%s
and enable_deferred_revenue = 1 and docstatus = 1
''', (end_date or today(), start_date or add_months(today(), -1)))
# ToDo also find the list on the basic of the GL entry, and make another list
for invoice in invoices:
doc = frappe.get_doc("Sales Invoice", invoice)
doc.book_income_for_deferred_revenue(start_date, end_date)
def validate_inter_company_party(doctype, party, company, inter_company_invoice_reference):
if doctype == "Sales Invoice":
partytype, ref_partytype, internal = "Customer", "Supplier", "is_internal_customer"

View File

@@ -12,7 +12,7 @@ app_license = "GNU General Public License (v3)"
source_link = "https://github.com/frappe/erpnext"
develop_version = '11.x.x-develop'
staging_version = '11.0.1'
staging_version = '11.0.3-beta.2'
error_report_email = "support@erpnext.com"
@@ -250,7 +250,8 @@ scheduler_events = {
"erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms"
],
"monthly": [
"erpnext.accounts.doctype.sales_invoice.sales_invoice.booked_deferred_revenue",
"erpnext.accounts.deferred_revenue.convert_deferred_revenue_to_income",
"erpnext.accounts.deferred_revenue.convert_deferred_expense_to_expense",
"erpnext.hr.utils.allocate_earned_leaves"
]
}

View File

@@ -16,16 +16,23 @@ class BOMUpdateTool(Document):
self.update_new_bom()
bom_list = self.get_parent_boms(self.new_bom)
updated_bom = []
for bom in bom_list:
bom_obj = frappe.get_doc("BOM", bom)
bom_obj.get_doc_before_save()
updated_bom = bom_obj.update_cost_and_exploded_items(updated_bom)
bom_obj.calculate_cost()
bom_obj.update_parent_cost()
bom_obj.db_update()
if (getattr(bom_obj.meta, 'track_changes', False)
and bom_obj._doc_before_save and not bom_obj.flags.ignore_version):
bom_obj.save_version()
try:
bom_obj = frappe.get_doc("BOM", bom)
bom_obj.get_doc_before_save()
updated_bom = bom_obj.update_cost_and_exploded_items(updated_bom)
bom_obj.calculate_cost()
bom_obj.update_parent_cost()
bom_obj.db_update()
if (getattr(bom_obj.meta, 'track_changes', False)
and bom_obj._doc_before_save and not bom_obj.flags.ignore_version):
bom_obj.save_version()
frappe.db.commit()
except Exception:
frappe.db.rollback()
frappe.log_error(frappe.get_traceback())
def validate_bom(self):
if cstr(self.current_bom) == cstr(self.new_bom):

View File

@@ -18,7 +18,7 @@ def execute():
for department in departments:
# skip root node
if department.name == _("All Departments"):
if _(department.name) == _("All Departments"):
continue
# for each company, create a copy of the doc

View File

@@ -796,6 +796,38 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
this.apply_pricing_rule(frappe.get_doc(cdt, cdn), true);
},
service_stop_date: function(frm, cdt, cdn) {
var child = locals[cdt][cdn];
if(child.service_stop_date) {
let start_date = Date.parse(child.service_start_date);
let end_date = Date.parse(child.service_end_date);
let stop_date = Date.parse(child.service_stop_date);
if(stop_date < start_date) {
frappe.model.set_value(cdt, cdn, "service_stop_date", "");
frappe.throw(__("Service Stop Date cannot be before Service Start Date"));
} else if (stop_date > end_date) {
frappe.model.set_value(cdt, cdn, "service_stop_date", "");
frappe.throw(__("Service Stop Date cannot be after Service End Date"));
}
}
},
service_start_date: function(frm, cdt, cdn) {
var child = locals[cdt][cdn];
if(child.service_start_date) {
frappe.call({
"method": "erpnext.stock.get_item_details.calculate_service_end_date",
args: {"args": child},
callback: function(r) {
frappe.model.set_value(cdt, cdn, "service_end_date", r.message.service_end_date);
}
})
}
},
calculate_net_weight: function(){
/* Calculate Total Net Weight then further applied shipping rule to calculate shipping charges.*/
var me = this;

View File

@@ -214,8 +214,9 @@ def get_loyalty_programs(doc):
"ifnull(to_date, '2500-01-01')": [">=", today()]})
for loyalty_program in loyalty_programs:
customer_groups = [d.value for d in get_children("Customer Group", loyalty_program.customer_group)]
customer_territories = [d.value for d in get_children("Territory", loyalty_program.customer_territory)]
customer_groups = [d.value for d in get_children("Customer Group", loyalty_program.customer_group)] + [loyalty_program.customer_group]
customer_territories = [d.value for d in get_children("Territory", loyalty_program.customer_territory)] + [loyalty_program.customer_territory]
if (not loyalty_program.customer_group or doc.customer_group in customer_groups)\
and (not loyalty_program.customer_territory or doc.territory in customer_territories):
lp_details.append(loyalty_program.name)

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
@@ -9,18 +10,24 @@
"doctype": "DocType",
"document_type": "Setup",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "sales_person",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Sales Person",
"length": 0,
"no_copy": 0,
@@ -32,24 +39,31 @@
"print_hide_if_no_value": 0,
"print_width": "200px",
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0,
"width": "200px"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "contact_no",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Contact No.",
"length": 0,
"no_copy": 0,
@@ -60,24 +74,31 @@
"print_hide_if_no_value": 0,
"print_width": "100px",
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0,
"width": "100px"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "allocated_percentage",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Contribution (%)",
"length": 0,
"no_copy": 0,
@@ -88,24 +109,31 @@
"print_hide_if_no_value": 0,
"print_width": "100px",
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0,
"width": "100px"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "allocated_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Contribution to Net Total",
"length": 0,
"no_copy": 0,
@@ -117,24 +145,63 @@
"print_hide_if_no_value": 0,
"print_width": "120px",
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0,
"width": "120px"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "commission_rate",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Commission Rate",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"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": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "incentives",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Incentives",
"length": 0,
"no_copy": 0,
@@ -145,24 +212,26 @@
"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,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 1,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2016-07-11 03:28:08.421297",
"modified": "2018-09-17 13:03:14.755974",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Team",
@@ -171,5 +240,8 @@
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"track_seen": 0
"show_name_in_global_search": 0,
"track_changes": 1,
"track_seen": 0,
"track_views": 0
}

View File

@@ -0,0 +1,54 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
frappe.query_reports["Sales Person Commission Summary"] = {
"filters": [
{
fieldname: "sales_person",
label: __("Sales Person"),
fieldtype: "Link",
options: "Sales Person"
},
{
fieldname: "doc_type",
label: __("Document Type"),
fieldtype: "Select",
options: "Sales Order\nDelivery Note\nSales Invoice",
default: "Sales Order"
},
{
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
},
{
fieldname:"to_date",
label: __("To Date"),
fieldtype: "Date",
default: frappe.datetime.get_today()
},
{
fieldname:"company",
label: __("Company"),
fieldtype: "Link",
options: "Company",
default: frappe.defaults.get_user_default("Company")
},
{
fieldname:"customer",
label: __("Customer"),
fieldtype: "Link",
options: "Customer",
},
{
fieldname:"territory",
label: __("Territory"),
fieldtype: "Link",
options: "Territory",
},
]
}

View File

@@ -0,0 +1,26 @@
{
"add_total_row": 1,
"creation": "2018-09-11 17:49:27.256304",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"modified": "2018-09-11 17:49:27.256304",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Person Commission Summary",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Sales Order",
"report_name": "Sales Person Commission Summary",
"report_type": "Script Report",
"roles": [
{
"role": "Sales Manager"
},
{
"role": "Maintenance User"
}
]
}

View File

@@ -0,0 +1,142 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import msgprint, _
from frappe.utils import flt
def execute(filters=None):
if not filters: filters = {}
columns = get_columns(filters)
entries = get_entries(filters)
data = []
for d in entries:
data.append([
d.name, d.customer, d.territory, d.posting_date,
d.base_net_amount, d.sales_person, d.allocated_percentage, d.commission_rate, d.allocated_amount,d.incentives
])
if data:
total_row = [""]*len(data[0])
data.append(total_row)
return columns, data
def get_columns(filters):
if not filters.get("doc_type"):
msgprint(_("Please select the document type first"), raise_exception=1)
columns =[
{
"label": _(filters["doc_type"]),
"options": filters["doc_type"],
"fieldname": filters['doc_type'],
"fieldtype": "Link",
"width": 140
},
{
"label": _("Customer"),
"options": "Customer",
"fieldname": "customer",
"fieldtype": "Link",
"width": 140
},
{
"label": _("Territory"),
"options": "Territory",
"fieldname": "territory",
"fieldtype": "Link",
"width": 100
},
{
"label": _("Posting Date"),
"fieldname": "posting_date",
"fieldtype": "Date",
"width": 100
},
{
"label": _("Amount"),
"fieldname": "amount",
"fieldtype": "Currency",
"width": 120
},
{
"label": _("Sales Person"),
"options": "Sales Person",
"fieldname": "sales_person",
"fieldtype": "Link",
"width": 140
},
{
"label": _("Contribution %"),
"fieldname": "contribution_percentage",
"fieldtype": "Data",
"width": 110
},
{
"label": _("Commission Rate %"),
"fieldname": "commission_rate",
"fieldtype": "Data",
"width": 100
},
{
"label": _("Contribution Amount"),
"fieldname": "contribution_amount",
"fieldtype": "Currency",
"width": 120
},
{
"label": _("Incentives"),
"fieldname": "incentives",
"fieldtype": "Currency",
"width": 120
}
]
return columns
def get_entries(filters):
date_field = filters["doc_type"] == "Sales Order" and "transaction_date" or "posting_date"
conditions, values = get_conditions(filters, date_field)
entries = frappe.db.sql("""
select
dt.name, dt.customer, dt.territory, dt.%s as posting_date,dt.base_net_total as base_net_amount,
st.commission_rate,st.sales_person, st.allocated_percentage, st.allocated_amount, st.incentives
from
`tab%s` dt, `tabSales Team` st
where
st.parent = dt.name and st.parenttype = %s
and dt.docstatus = 1 %s order by dt.name desc,st.sales_person
""" %(date_field, filters["doc_type"], '%s', conditions),
tuple([filters["doc_type"]] + values), as_dict=1)
return entries
def get_conditions(filters, date_field):
conditions = [""]
values = []
for field in ["company", "customer", "territory"]:
if filters.get(field):
conditions.append("dt.{0}=%s".format(field))
values.append(filters[field])
if filters.get("sales_person"):
conditions.append("st.sales_person = '{0}'".format(filters.get("sales_person")))
if filters.get("from_date"):
conditions.append("dt.{0}>=%s".format(date_field))
values.append(filters["from_date"])
if filters.get("to_date"):
conditions.append("dt.{0}<=%s".format(date_field))
values.append(filters["to_date"])
return " and ".join(conditions), values

View File

@@ -12,6 +12,8 @@ frappe.provide("erpnext.selling");
erpnext.selling.SellingController = erpnext.TransactionController.extend({
setup: function() {
this._super();
this.frm.add_fetch("sales_partner", "commission_rate", "commission_rate");
this.frm.add_fetch("sales_person", "commission_rate", "commission_rate");
},
onload: function() {
@@ -29,8 +31,6 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
setup_queries: function() {
var me = this;
this.frm.add_fetch("sales_partner", "commission_rate", "commission_rate");
$.each([["customer", "customer"],
["lead", "lead"]],
function(i, opts) {
@@ -171,17 +171,26 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
allocated_percentage: function(doc, cdt, cdn) {
var sales_person = frappe.get_doc(cdt, cdn);
if(sales_person.allocated_percentage) {
sales_person.allocated_percentage = flt(sales_person.allocated_percentage,
precision("allocated_percentage", sales_person));
sales_person.allocated_amount = flt(this.frm.doc.base_net_total *
sales_person.allocated_percentage / 100.0,
precision("allocated_amount", sales_person));
refresh_field(["allocated_amount"], sales_person);
refresh_field(["allocated_percentage", "allocated_amount"], sales_person.name,
this.calculate_incentive(sales_person);
refresh_field(["allocated_percentage", "allocated_amount", "commission_rate","incentives"], sales_person.name,
sales_person.parentfield);
}
}
},
sales_person: function(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
this.calculate_incentive(row);
refresh_field("incentives",row.name,row.parentfield);
},
warehouse: function(doc, cdt, cdn) {
@@ -250,6 +259,15 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
});
},
calculate_incentive: function(row) {
if(row.allocated_amount)
{
row.incentives = flt(
row.allocated_amount * row.commission_rate / 100.0,
precision("incentives", sales_person));
}
},
batch_no: function(doc, cdt, cdn) {
var me = this;
var item = frappe.get_doc(cdt, cdn);

View File

@@ -837,7 +837,7 @@
"label": "Create Chart Of Accounts Based On",
"length": 0,
"no_copy": 0,
"options": "\nStandard Template\nExisting Company",
"options": "\nStandard Template\nExisting Company",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -871,7 +871,7 @@
"label": "Chart Of Accounts Template",
"length": 0,
"no_copy": 1,
"options": "",
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -1158,6 +1158,39 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "round_off_cost_center",
"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": "Round Off Cost Center",
"length": 0,
"no_copy": 0,
"options": "Cost Center",
"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,
"fieldname": "write_off_account",
"fieldtype": "Link",
"hidden": 0,
@@ -1458,7 +1491,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:!doc.__islocal",
"fieldname": "default_payroll_payable_account",
"fieldname": "default_deferred_expense_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1,
@@ -1467,7 +1500,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Default Payroll Payable Account",
"label": "Default Deferred Expense Account",
"length": 0,
"no_copy": 1,
"options": "Account",
@@ -1492,7 +1525,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:!doc.__islocal",
"fieldname": "default_expense_claim_payable_account",
"fieldname": "default_payroll_payable_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1,
@@ -1501,7 +1534,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Default Expense Claim Payable Account",
"label": "Default Payroll Payable Account",
"length": 0,
"no_copy": 1,
"options": "Account",
@@ -1525,19 +1558,20 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "round_off_cost_center",
"depends_on": "eval:!doc.__islocal",
"fieldname": "default_expense_claim_payable_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Round Off Cost Center",
"label": "Default Expense Claim Payable Account",
"length": 0,
"no_copy": 0,
"options": "Cost Center",
"no_copy": 1,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -2836,8 +2870,8 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2018-09-07 16:03:30.716918",
"modified_by": "cave@aperture.com",
"modified": "2018-09-13 10:00:47.915706",
"modified_by": "Administrator",
"module": "Setup",
"name": "Company",
"owner": "Administrator",

View File

@@ -1,6 +1,15 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.ui.form.on('Sales Person', {
refresh: function(frm) {
if(frm.doc.__onload && frm.doc.__onload.dashboard_info) {
var info = frm.doc.__onload.dashboard_info;
frm.dashboard.add_indicator(__('Total Contribution Amount: {0}',
[format_currency(info.allocated_amount, info.currency)]), 'blue');
}
}
});
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
cur_frm.cscript.set_root_readonly(doc);

View File

@@ -1,6 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:sales_person_name",
@@ -15,7 +15,8 @@
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -42,11 +43,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -74,11 +76,12 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"translatable": 0,
"unique": 1
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -108,11 +111,44 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "commission_rate",
"fieldtype": "Data",
"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": "Commission Rate",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"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,
@@ -141,47 +177,49 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "1",
"fieldname": "enabled",
"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": "Enabled",
"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,
"default": "1",
"fieldname": "enabled",
"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": "Enabled",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "cb0",
"fieldtype": "Column Break",
"hidden": 0,
@@ -202,11 +240,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -233,18 +272,19 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "employee.department",
"fieldname": "department",
"fieldtype": "Link",
"fetch_from": "employee.department",
"fieldname": "department",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -252,25 +292,26 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Department",
"label": "Department",
"length": 0,
"no_copy": 0,
"options": "Department",
"options": "Department",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -298,11 +339,12 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -330,11 +372,12 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -362,11 +405,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -395,11 +439,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -428,11 +473,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -462,11 +508,11 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "icon-user",
@@ -477,7 +523,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-05-17 09:44:18.203325",
"modified": "2018-09-12 16:41:06.378899",
"modified_by": "Administrator",
"module": "Setup",
"name": "Sales Person",
@@ -541,12 +587,13 @@
"write": 1
}
],
"quick_entry": 0,
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"search_fields": "parent_sales_person",
"show_name_in_global_search": 1,
"sort_order": "ASC",
"track_changes": 0,
"track_seen": 0
"track_changes": 1,
"track_seen": 0,
"track_views": 0
}

View File

@@ -6,9 +6,10 @@ import frappe
from frappe import _
from frappe.utils import flt
from frappe.utils.nestedset import NestedSet
from erpnext import get_default_currency
class SalesPerson(NestedSet):
nsm_parent_field = 'parent_sales_person';
nsm_parent_field = 'parent_sales_person'
def validate(self):
for d in self.get('targets') or []:
@@ -16,6 +17,24 @@ class SalesPerson(NestedSet):
frappe.throw(_("Either target qty or target amount is mandatory."))
self.validate_employee_id()
def onload(self):
self.load_dashboard_info()
def load_dashboard_info(self):
company_default_currency = get_default_currency()
allocated_amount = frappe.db.sql("""
select sum(allocated_amount)
from `tabSales Team`
where sales_person = %s and docstatus=1 and parenttype = 'Sales Order'
""",(self.sales_person_name))
info = {}
info["allocated_amount"] = flt(allocated_amount[0][0]) if allocated_amount else 0
info["currency"] = company_default_currency
self.set_onload('dashboard_info', info)
def on_update(self):
super(SalesPerson, self).on_update()
self.validate_one_root()
@@ -35,4 +54,48 @@ class SalesPerson(NestedSet):
frappe.throw(_("Another Sales Person {0} exists with the same Employee id").format(sales_person))
def on_doctype_update():
frappe.db.add_index("Sales Person", ["lft", "rgt"])
frappe.db.add_index("Sales Person", ["lft", "rgt"])
def get_timeline_data(doctype, name):
out = {}
out.update(dict(frappe.db.sql('''select
unix_timestamp(dt.transaction_date), count(st.parenttype)
from
`tabSales Order` dt, `tabSales Team` st
where
st.sales_person = %s and st.parent = dt.name and dt.transaction_date > date_sub(curdate(), interval 1 year)
group by dt.transaction_date ''', name)))
sales_invoice = dict(frappe.db.sql('''select
unix_timestamp(dt.posting_date), count(st.parenttype)
from
`tabSales Invoice` dt, `tabSales Team` st
where
st.sales_person = %s and st.parent = dt.name and dt.posting_date > date_sub(curdate(), interval 1 year)
group by dt.posting_date ''', name))
for key in sales_invoice:
if out.get(key):
out[key] += sales_invoice[key]
else:
out[key] = sales_invoice[key]
delivery_note = dict(frappe.db.sql('''select
unix_timestamp(dt.posting_date), count(st.parenttype)
from
`tabDelivery Note` dt, `tabSales Team` st
where
st.sales_person = %s and st.parent = dt.name and dt.posting_date > date_sub(curdate(), interval 1 year)
group by dt.posting_date ''', name))
for key in delivery_note:
if out.get(key):
out[key] += delivery_note[key]
else:
out[key] = delivery_note[key]
return out

View File

@@ -0,0 +1,14 @@
from frappe import _
def get_data():
return {
'heatmap': True,
'heatmap_message': _('This is based on transactions against this Sales Person. See timeline below for details'),
'fieldname': 'sales_person',
'transactions': [
{
'label': _('Sales'),
'items': ['Sales Order', 'Delivery Note', 'Sales Invoice']
},
]
}

View File

@@ -2690,18 +2690,20 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "enable_deferred_revenue",
"fieldtype": "Check",
"depends_on": "enable_deferred_revenue",
"fieldname": "deferred_revenue_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Enable Deferred Revenue",
"label": "Deferred Revenue Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -2722,20 +2724,18 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "enable_deferred_revenue",
"fieldname": "deferred_revenue_account",
"fieldtype": "Link",
"fieldname": "enable_deferred_revenue",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Deferred Revenue Account",
"label": "Enable Deferred Revenue",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -2813,6 +2813,168 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
"fieldname": "deferred_expense_section",
"fieldtype": "Section Break",
"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": "Deferred Expense",
"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,
"depends_on": "enable_deferred_expense",
"fieldname": "deferred_expense_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Deferred Expense Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"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,
"fieldname": "enable_deferred_expense",
"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": "Enable Deferred Expense",
"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,
"fieldname": "column_break_88",
"fieldtype": "Column Break",
"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,
"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,
"depends_on": "enable_deferred_expense",
"fieldname": "no_of_months_exp",
"fieldtype": "Int",
"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": "No of Months",
"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,
@@ -3951,7 +4113,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 1,
"modified": "2018-09-19 16:17:41.039657",
"modified": "2018-09-20 11:14:21.031369",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",

View File

@@ -191,14 +191,14 @@ def process_serial_no(sle):
update_serial_nos(sle, item_det)
def validate_serial_no(sle, item_det):
serial_nos = get_serial_nos(sle.serial_no) if sle.serial_no else []
if item_det.has_serial_no==0:
if sle.serial_no:
if serial_nos:
frappe.throw(_("Item {0} is not setup for Serial Nos. Column must be blank").format(sle.item_code),
SerialNoNotRequiredError)
elif sle.is_cancelled == "No":
if sle.serial_no:
serial_nos = get_serial_nos(sle.serial_no)
if serial_nos:
if cint(sle.actual_qty) != flt(sle.actual_qty):
frappe.throw(_("Serial No {0} quantity {1} cannot be a fraction").format(sle.item_code, sle.actual_qty))
@@ -285,6 +285,12 @@ def validate_serial_no(sle, item_det):
elif sle.actual_qty < 0 or not item_det.serial_no_series:
frappe.throw(_("Serial Nos Required for Serialized Item {0}").format(sle.item_code),
SerialNoRequiredError)
elif serial_nos:
for serial_no in serial_nos:
sr = frappe.db.get_value("Serial No", serial_no, ["name", "warehouse"], as_dict=1)
if sr and sle.actual_qty < 0 and sr.warehouse != sle.warehouse:
frappe.throw(_("Cannot cancel {0} {1} because Serial No {2} does not belong to the warehouse {3}")
.format(sle.voucher_type, sle.voucher_no, serial_no, sle.warehouse))
def validate_so_serial_no(sr, sales_order,):
if not sr.sales_order or sr.sales_order!= sales_order:

View File

@@ -310,14 +310,18 @@ def calculate_service_end_date(args, item=None):
if not item:
item = frappe.get_cached_doc("Item", args.item_code)
enable_deferred = "enable_deferred_revenue" if args.doctype=="Sales Invoice" else "enable_deferred_expense"
no_of_months = "no_of_months" if args.doctype=="Sales Invoice" else "no_of_months_exp"
account = "deferred_revenue_account" if args.doctype=="Sales Invoice" else "deferred_expense_account"
service_start_date = args.service_start_date if args.service_start_date else args.transaction_date
service_end_date = add_months(service_start_date, item.no_of_months)
service_end_date = add_months(service_start_date, item.get(no_of_months))
deferred_detail = {
"enable_deferred_revenue": item.enable_deferred_revenue,
"deferred_revenue_account": get_default_deferred_revenue_account(args, item),
"service_start_date": service_start_date,
"service_end_date": service_end_date
}
deferred_detail[enable_deferred] = item.get(enable_deferred)
deferred_detail[account] = get_default_deferred_account(args, item, fieldname=account)
return deferred_detail
@@ -331,11 +335,11 @@ def get_default_expense_account(args, item, item_group):
or item_group.get("expense_account")
or args.expense_account)
def get_default_deferred_revenue_account(args, item):
def get_default_deferred_account(args, item, fieldname=None):
if item.enable_deferred_revenue:
return (item.deferred_revenue_account
or args.deferred_revenue_account
or frappe.get_cached_value('Company', args.company, "default_deferred_revenue_account"))
return (item.get(fieldname)
or args.get(fieldname)
or frappe.get_cached_value('Company', args.company, "default_"+fieldname))
else:
return None