mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-01 04:28:27 +00:00
Merge branch 'hotfix' into hotfix-shipping-override
This commit is contained in:
@@ -6,7 +6,6 @@
|
||||
</p>
|
||||
|
||||
[](https://travis-ci.com/frappe/erpnext)
|
||||
[](https://gitter.im/frappe/erpnext?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://www.codetriage.com/frappe/erpnext)
|
||||
[](https://coveralls.io/github/frappe/erpnext?branch=develop)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import frappe
|
||||
from erpnext.hooks import regional_overrides
|
||||
from frappe.utils import getdate
|
||||
|
||||
__version__ = '11.1.14'
|
||||
__version__ = '11.1.20'
|
||||
|
||||
def get_default_company(user=None):
|
||||
'''Get default company for user'''
|
||||
|
||||
@@ -2,9 +2,9 @@ from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import date_diff, add_months, today, getdate, add_days, flt
|
||||
from frappe.utils import date_diff, add_months, today, getdate, add_days, flt, get_last_day
|
||||
from erpnext.accounts.utils import get_account_currency
|
||||
from erpnext.accounts.general_ledger import make_gl_entries
|
||||
from frappe.email import sendmail_to_system_managers
|
||||
|
||||
def validate_service_stop_date(doc):
|
||||
''' Validates service_stop_date for Purchase Invoice and Sales Invoice '''
|
||||
@@ -33,47 +33,49 @@ def validate_service_stop_date(doc):
|
||||
frappe.throw(_("Cannot change Service Stop Date for item in row {0}".format(item.idx)))
|
||||
|
||||
def convert_deferred_expense_to_expense(start_date=None, end_date=None):
|
||||
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
|
||||
if not start_date:
|
||||
start_date = add_months(today(), -1)
|
||||
if not end_date:
|
||||
end_date = add_days(today(), -1)
|
||||
|
||||
# check for the purchase invoice for which GL entries has to be done
|
||||
invoices = frappe.db.sql_list('''
|
||||
select distinct parent from `tabPurchase Invoice Item` where service_start_date<=%s and service_end_date>=%s
|
||||
select distinct parent from `tabPurchase Invoice Item`
|
||||
where service_start_date<=%s and service_end_date>=%s
|
||||
and enable_deferred_expense = 1 and docstatus = 1 and ifnull(amount, 0) > 0
|
||||
''', (end_date or today(), start_date or add_months(today(), -1)))
|
||||
''', (end_date, start_date))
|
||||
|
||||
# For each invoice, book deferred expense
|
||||
for invoice in invoices:
|
||||
doc = frappe.get_doc("Purchase Invoice", invoice)
|
||||
book_deferred_income_or_expense(doc, start_date, end_date)
|
||||
book_deferred_income_or_expense(doc, end_date)
|
||||
|
||||
def convert_deferred_revenue_to_income(start_date=None, end_date=None):
|
||||
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
|
||||
if not start_date:
|
||||
start_date = add_months(today(), -1)
|
||||
if not end_date:
|
||||
end_date = add_days(today(), -1)
|
||||
|
||||
# check for the sales invoice for which GL entries has to be done
|
||||
invoices = frappe.db.sql_list('''
|
||||
select distinct parent from `tabSales Invoice Item` where service_start_date<=%s and service_end_date>=%s
|
||||
select distinct parent from `tabSales Invoice Item`
|
||||
where service_start_date<=%s and service_end_date>=%s
|
||||
and enable_deferred_revenue = 1 and docstatus = 1 and ifnull(amount, 0) > 0
|
||||
''', (end_date or today(), start_date or add_months(today(), -1)))
|
||||
''', (end_date, start_date))
|
||||
|
||||
# For each invoice, book deferred revenue
|
||||
for invoice in invoices:
|
||||
doc = frappe.get_doc("Sales Invoice", invoice)
|
||||
book_deferred_income_or_expense(doc, start_date, end_date)
|
||||
book_deferred_income_or_expense(doc, end_date)
|
||||
|
||||
def get_booking_dates(doc, item, posting_date=None):
|
||||
if not posting_date:
|
||||
posting_date = add_days(today(), -1)
|
||||
|
||||
last_gl_entry = False
|
||||
|
||||
def get_booking_dates(doc, item, start_date=None, end_date=None):
|
||||
deferred_account = "deferred_revenue_account" if doc.doctype=="Sales Invoice" else "deferred_expense_account"
|
||||
last_gl_entry, skip = False, False
|
||||
|
||||
booking_end_date = getdate(add_days(today(), -1) if not end_date else end_date)
|
||||
if booking_end_date < item.service_start_date or \
|
||||
(item.service_stop_date and booking_end_date.month > item.service_stop_date.month):
|
||||
return None, None, None, True
|
||||
elif booking_end_date >= item.service_end_date:
|
||||
last_gl_entry = True
|
||||
booking_end_date = item.service_end_date
|
||||
elif item.service_stop_date and item.service_stop_date <= booking_end_date:
|
||||
last_gl_entry = True
|
||||
booking_end_date = item.service_stop_date
|
||||
|
||||
booking_start_date = getdate(add_months(today(), -1) if not start_date else start_date)
|
||||
booking_start_date = booking_start_date \
|
||||
if booking_start_date > item.service_start_date else item.service_start_date
|
||||
|
||||
prev_gl_entry = frappe.db.sql('''
|
||||
select name, posting_date from `tabGL Entry` where company=%s and account=%s and
|
||||
@@ -81,17 +83,28 @@ def get_booking_dates(doc, item, start_date=None, end_date=None):
|
||||
order by posting_date desc limit 1
|
||||
''', (doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True)
|
||||
|
||||
if not prev_gl_entry and item.service_start_date < booking_start_date:
|
||||
booking_start_date = item.service_start_date
|
||||
elif prev_gl_entry:
|
||||
booking_start_date = getdate(add_days(prev_gl_entry[0].posting_date, 1))
|
||||
skip = True if booking_start_date > booking_end_date else False
|
||||
if prev_gl_entry:
|
||||
start_date = getdate(add_days(prev_gl_entry[0].posting_date, 1))
|
||||
else:
|
||||
start_date = item.service_start_date
|
||||
|
||||
return last_gl_entry, booking_start_date, booking_end_date, skip
|
||||
end_date = get_last_day(start_date)
|
||||
if end_date >= item.service_end_date:
|
||||
end_date = item.service_end_date
|
||||
last_gl_entry = True
|
||||
elif item.service_stop_date and end_date >= item.service_stop_date:
|
||||
end_date = item.service_stop_date
|
||||
last_gl_entry = True
|
||||
|
||||
def calculate_amount_and_base_amount(doc, item, last_gl_entry, total_days, total_booking_days):
|
||||
account_currency = get_account_currency(item.expense_account)
|
||||
if end_date > getdate(posting_date):
|
||||
end_date = posting_date
|
||||
|
||||
if getdate(start_date) <= getdate(end_date):
|
||||
return start_date, end_date, last_gl_entry
|
||||
else:
|
||||
return None, None, None
|
||||
|
||||
def calculate_amount(doc, item, last_gl_entry, total_days, total_booking_days, account_currency):
|
||||
if doc.doctype == "Sales Invoice":
|
||||
total_credit_debit, total_credit_debit_currency = "debit", "debit_in_account_currency"
|
||||
deferred_account = "deferred_revenue_account"
|
||||
@@ -123,28 +136,15 @@ def calculate_amount_and_base_amount(doc, item, last_gl_entry, total_days, total
|
||||
|
||||
return amount, base_amount
|
||||
|
||||
def book_deferred_income_or_expense(doc, start_date=None, end_date=None):
|
||||
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
|
||||
# start_date: 1st of the last month or the start date
|
||||
# end_date: end_date or today-1
|
||||
def book_deferred_income_or_expense(doc, posting_date=None):
|
||||
enable_check = "enable_deferred_revenue" \
|
||||
if doc.doctype=="Sales Invoice" else "enable_deferred_expense"
|
||||
|
||||
gl_entries = []
|
||||
for item in doc.get('items'):
|
||||
if not item.get(enable_check): continue
|
||||
|
||||
skip = False
|
||||
last_gl_entry, booking_start_date, booking_end_date, skip = \
|
||||
get_booking_dates(doc, item, start_date, end_date)
|
||||
|
||||
if skip: continue
|
||||
total_days = date_diff(item.service_end_date, item.service_start_date) + 1
|
||||
total_booking_days = date_diff(booking_end_date, booking_start_date) + 1
|
||||
def _book_deferred_revenue_or_expense(item):
|
||||
start_date, end_date, last_gl_entry = get_booking_dates(doc, item, posting_date=posting_date)
|
||||
if not (start_date and end_date): return
|
||||
|
||||
account_currency = get_account_currency(item.expense_account)
|
||||
amount, base_amount = calculate_amount_and_base_amount(doc, item, last_gl_entry, total_days, total_booking_days)
|
||||
|
||||
if doc.doctype == "Sales Invoice":
|
||||
against, project = doc.customer, doc.project
|
||||
credit_account, debit_account = item.income_account, item.deferred_revenue_account
|
||||
@@ -152,36 +152,62 @@ def book_deferred_income_or_expense(doc, start_date=None, end_date=None):
|
||||
against, project = doc.supplier, item.project
|
||||
credit_account, debit_account = item.deferred_expense_account, item.expense_account
|
||||
|
||||
# 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,
|
||||
"voucher_detail_no": item.name,
|
||||
'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)
|
||||
)
|
||||
total_days = date_diff(item.service_end_date, item.service_start_date) + 1
|
||||
total_booking_days = date_diff(end_date, start_date) + 1
|
||||
|
||||
amount, base_amount = calculate_amount(doc, item, last_gl_entry,
|
||||
total_days, total_booking_days, account_currency)
|
||||
|
||||
make_gl_entries(doc, credit_account, debit_account, against,
|
||||
amount, base_amount, end_date, project, account_currency, item.cost_center, item.name)
|
||||
|
||||
if getdate(end_date) < getdate(posting_date) and not last_gl_entry:
|
||||
_book_deferred_revenue_or_expense(item)
|
||||
|
||||
|
||||
for item in doc.get('items'):
|
||||
if item.get(enable_check):
|
||||
_book_deferred_revenue_or_expense(item)
|
||||
|
||||
def make_gl_entries(doc, credit_account, debit_account, against,
|
||||
amount, base_amount, posting_date, project, account_currency, cost_center, voucher_detail_no):
|
||||
# GL Entry for crediting the amount in the deferred expense
|
||||
from erpnext.accounts.general_ledger import make_gl_entries
|
||||
|
||||
gl_entries = []
|
||||
gl_entries.append(
|
||||
doc.get_gl_dict({
|
||||
"account": credit_account,
|
||||
"against": against,
|
||||
"credit": base_amount,
|
||||
"credit_in_account_currency": amount,
|
||||
"cost_center": 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:
|
||||
try:
|
||||
make_gl_entries(gl_entries, cancel=(doc.docstatus == 2), merge_entries=True)
|
||||
frappe.db.commit()
|
||||
except:
|
||||
frappe.db.rollback()
|
||||
frappe.log_error(message = frappe.get_traceback(), title = _("Error while processing deferred accounting for {0}").format(doc.name))
|
||||
title = _("Error while processing deferred accounting for {0}").format(doc.name)
|
||||
traceback = frappe.get_traceback()
|
||||
frappe.log_error(message=traceback , title=title)
|
||||
sendmail_to_system_managers(title, traceback)
|
||||
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.utils import cint, cstr
|
||||
from frappe import throw, _
|
||||
from frappe.utils.nestedset import NestedSet
|
||||
from frappe.utils.nestedset import NestedSet, get_ancestors_of, get_descendants_of
|
||||
|
||||
class RootNotEditable(frappe.ValidationError): pass
|
||||
class BalanceMismatchError(frappe.ValidationError): pass
|
||||
@@ -41,6 +41,7 @@ class Account(NestedSet):
|
||||
self.validate_frozen_accounts_modifier()
|
||||
self.validate_balance_must_be_debit_or_credit()
|
||||
self.validate_account_currency()
|
||||
self.validate_root_company_and_sync_account_to_children()
|
||||
|
||||
def validate_parent(self):
|
||||
"""Fetch Parent Details and validate parent account"""
|
||||
@@ -90,6 +91,38 @@ class Account(NestedSet):
|
||||
if not self.parent_account and not self.is_group:
|
||||
frappe.throw(_("Root Account must be a group"))
|
||||
|
||||
def validate_root_company_and_sync_account_to_children(self):
|
||||
# ignore validation while creating new compnay or while syncing to child companies
|
||||
if frappe.local.flags.ignore_root_company_validation or self.flags.ignore_root_company_validation:
|
||||
return
|
||||
|
||||
ancestors = get_root_company(self.company)
|
||||
if ancestors:
|
||||
if frappe.get_value("Company", self.company, "allow_account_creation_against_child_company"):
|
||||
return
|
||||
frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0]))
|
||||
else:
|
||||
descendants = get_descendants_of('Company', self.company)
|
||||
if not descendants: return
|
||||
|
||||
acc_name_map = {}
|
||||
acc_name = frappe.db.get_value('Account', self.parent_account, "account_name")
|
||||
for d in frappe.db.get_values('Account',
|
||||
{"company": ["in", descendants], "account_name": acc_name},
|
||||
["company", "name"], as_dict=True):
|
||||
acc_name_map[d["company"]] = d["name"]
|
||||
|
||||
if not acc_name_map: return
|
||||
|
||||
for company in descendants:
|
||||
doc = frappe.copy_doc(self)
|
||||
doc.flags.ignore_root_company_validation = True
|
||||
doc.update({"company": company, "account_currency": None,
|
||||
"parent": acc_name_map[company], "parent_account": acc_name_map[company]})
|
||||
doc.save()
|
||||
frappe.msgprint(_("Account {0} is added in the child company {1}")
|
||||
.format(doc.name, company))
|
||||
|
||||
def validate_group_or_ledger(self):
|
||||
if self.get("__islocal"):
|
||||
return
|
||||
@@ -250,3 +283,9 @@ def merge_account(old, new, is_group, root_type, company):
|
||||
frappe.rename_doc("Account", old, new, merge=1, ignore_permissions=1)
|
||||
|
||||
return new
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_root_company(company):
|
||||
# return the topmost company in the hierarchy
|
||||
ancestors = get_ancestors_of('Company', company, "lft asc")
|
||||
return [ancestors[0]] if ancestors else []
|
||||
|
||||
@@ -4,13 +4,42 @@ frappe.treeview_settings["Account"] = {
|
||||
breadcrumbs: "Accounts",
|
||||
title: __("Chart Of Accounts"),
|
||||
get_tree_root: false,
|
||||
filters: [{
|
||||
fieldname: "company",
|
||||
fieldtype:"Select",
|
||||
options: erpnext.utils.get_tree_options("company"),
|
||||
label: __("Company"),
|
||||
default: erpnext.utils.get_tree_default("company")
|
||||
}],
|
||||
filters: [
|
||||
{
|
||||
fieldname: "company",
|
||||
fieldtype:"Select",
|
||||
options: erpnext.utils.get_tree_options("company"),
|
||||
label: __("Company"),
|
||||
default: erpnext.utils.get_tree_default("company"),
|
||||
on_change: function() {
|
||||
var me = frappe.treeview_settings['Account'].treeview;
|
||||
var company = me.page.fields_dict.company.get_value();
|
||||
frappe.call({
|
||||
method: "erpnext.accounts.doctype.account.account.get_root_company",
|
||||
args: {
|
||||
company: company,
|
||||
},
|
||||
callback: function(r) {
|
||||
if(r.message) {
|
||||
let root_company = r.message.length ? r.message[0] : "";
|
||||
me.page.fields_dict.root_company.set_value(root_company);
|
||||
|
||||
frappe.db.get_value("Company", {"name": company}, "allow_account_creation_against_child_company", (r) => {
|
||||
frappe.flags.ignore_root_company_validation = r.allow_account_creation_against_child_company;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
fieldname: "root_company",
|
||||
fieldtype:"Data",
|
||||
label: __("Root Company"),
|
||||
hidden: true,
|
||||
disable_onchange: true
|
||||
}
|
||||
],
|
||||
root_label: "Accounts",
|
||||
get_tree_nodes: 'erpnext.accounts.utils.get_children',
|
||||
add_tree_node: 'erpnext.accounts.utils.add_ac',
|
||||
@@ -42,8 +71,8 @@ frappe.treeview_settings["Account"] = {
|
||||
],
|
||||
ignore_fields:["parent_account"],
|
||||
onload: function(treeview) {
|
||||
frappe.treeview_settings['Account'].page = {};
|
||||
$.extend(frappe.treeview_settings['Account'].page, treeview.page);
|
||||
frappe.treeview_settings['Account'].treeview = {};
|
||||
$.extend(frappe.treeview_settings['Account'].treeview, treeview);
|
||||
function get_company() {
|
||||
return treeview.page.fields_dict.company.get_value();
|
||||
}
|
||||
@@ -78,6 +107,18 @@ frappe.treeview_settings["Account"] = {
|
||||
}
|
||||
|
||||
},
|
||||
post_render: function(treeview) {
|
||||
frappe.treeview_settings['Account'].treeview["tree"] = treeview.tree;
|
||||
treeview.page.set_primary_action(__("New"), function() {
|
||||
let root_company = treeview.page.fields_dict.root_company.get_value();
|
||||
|
||||
if(root_company) {
|
||||
frappe.throw(__("Please add the account to root level Company - ") + root_company);
|
||||
} else {
|
||||
treeview.new_node();
|
||||
}
|
||||
}, "octicon octicon-plus");
|
||||
},
|
||||
onrender: function(node) {
|
||||
if(frappe.boot.user.can_read.indexOf("GL Entry") !== -1){
|
||||
var dr_or_cr = node.data.balance < 0 ? "Cr" : "Dr";
|
||||
@@ -93,6 +134,20 @@ frappe.treeview_settings["Account"] = {
|
||||
}
|
||||
},
|
||||
toolbar: [
|
||||
{
|
||||
label:__("Add Child"),
|
||||
condition: function(node) {
|
||||
return frappe.boot.user.can_create.indexOf("Account") !== -1
|
||||
&& (!frappe.treeview_settings['Account'].treeview.page.fields_dict.root_company.get_value()
|
||||
|| frappe.flags.ignore_root_company_validation)
|
||||
&& node.expandable && !node.hide_add;
|
||||
},
|
||||
click: function() {
|
||||
var me = frappe.treeview_settings['Account'].treeview;
|
||||
me.new_node();
|
||||
},
|
||||
btnClass: "hidden-xs"
|
||||
},
|
||||
{
|
||||
condition: function(node) {
|
||||
return !node.root && frappe.boot.user.can_read.indexOf("GL Entry") !== -1
|
||||
@@ -103,7 +158,7 @@ frappe.treeview_settings["Account"] = {
|
||||
"account": node.label,
|
||||
"from_date": frappe.sys_defaults.year_start_date,
|
||||
"to_date": frappe.sys_defaults.year_end_date,
|
||||
"company": frappe.treeview_settings['Account'].page.fields_dict.company.get_value()
|
||||
"company": frappe.treeview_settings['Account'].treeview.page.fields_dict.company.get_value()
|
||||
};
|
||||
frappe.set_route("query-report", "General Ledger");
|
||||
},
|
||||
|
||||
@@ -97,6 +97,19 @@ class TestAccount(unittest.TestCase):
|
||||
self.assertRaises(frappe.ValidationError, merge_account, "Capital Stock - _TC",\
|
||||
"Softwares - _TC", doc.is_group, doc.root_type, doc.company)
|
||||
|
||||
def test_account_sync(self):
|
||||
del frappe.local.flags["ignore_root_company_validation"]
|
||||
acc = frappe.new_doc("Account")
|
||||
acc.account_name = "Test Sync Account"
|
||||
acc.parent_account = "Temporary Accounts - _TC3"
|
||||
acc.company = "_Test Company 3"
|
||||
acc.insert()
|
||||
|
||||
acc_tc_4 = frappe.db.get_value('Account', {'account_name': "Test Sync Account", "company": "_Test Company 4"})
|
||||
acc_tc_5 = frappe.db.get_value('Account', {'account_name': "Test Sync Account", "company": "_Test Company 5"})
|
||||
self.assertEqual(acc_tc_4, "Test Sync Account - _TC4")
|
||||
self.assertEqual(acc_tc_5, "Test Sync Account - _TC5")
|
||||
|
||||
def _make_test_records(verbose):
|
||||
from frappe.test_runner import make_test_objects
|
||||
|
||||
@@ -131,7 +144,7 @@ def _make_test_records(verbose):
|
||||
|
||||
# related to Account Inventory Integration
|
||||
["_Test Account Stock In Hand", "Current Assets", 0, None, None],
|
||||
|
||||
|
||||
# fixed asset depreciation
|
||||
["_Test Fixed Asset", "Current Assets", 0, "Fixed Asset", None],
|
||||
["_Test Accumulated Depreciations", "Current Assets", 0, None, None],
|
||||
@@ -168,13 +181,17 @@ def get_inventory_account(company, warehouse=None):
|
||||
return account
|
||||
|
||||
def create_account(**kwargs):
|
||||
account = frappe.get_doc(dict(
|
||||
doctype = "Account",
|
||||
account_name = kwargs.get('account_name'),
|
||||
account_type = kwargs.get('account_type'),
|
||||
parent_account = kwargs.get('parent_account'),
|
||||
company = kwargs.get('company')
|
||||
))
|
||||
|
||||
account.save()
|
||||
return account.name
|
||||
account = frappe.db.get_value("Account", filters={"account_name": kwargs.get("account_name"), "company": kwargs.get("company")})
|
||||
if account:
|
||||
return account
|
||||
else:
|
||||
account = frappe.get_doc(dict(
|
||||
doctype = "Account",
|
||||
account_name = kwargs.get('account_name'),
|
||||
account_type = kwargs.get('account_type'),
|
||||
parent_account = kwargs.get('parent_account'),
|
||||
company = kwargs.get('company')
|
||||
))
|
||||
|
||||
account.save()
|
||||
return account.name
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 1,
|
||||
@@ -290,7 +291,7 @@
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "IBAN",
|
||||
"length": 25,
|
||||
"length": 30,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
@@ -669,7 +670,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-07-20 13:55:36.996465",
|
||||
"modified": "2019-03-05 17:56:05.103238",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Bank Account",
|
||||
|
||||
@@ -23,36 +23,36 @@ class BankReconciliation(Document):
|
||||
|
||||
|
||||
journal_entries = frappe.db.sql("""
|
||||
select
|
||||
"Journal Entry" as payment_document, t1.name as payment_entry,
|
||||
t1.cheque_no as cheque_number, t1.cheque_date,
|
||||
select
|
||||
"Journal Entry" as payment_document, t1.name as payment_entry,
|
||||
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,
|
||||
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
|
||||
`tabJournal Entry` t1, `tabJournal Entry Account` t2
|
||||
where
|
||||
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}
|
||||
group by t2.account, t1.name
|
||||
order by t1.posting_date ASC, t1.name DESC
|
||||
""".format(condition), (self.bank_account, self.from_date, self.to_date), as_dict=1)
|
||||
|
||||
payment_entries = frappe.db.sql("""
|
||||
select
|
||||
"Payment Entry" as payment_document, name as payment_entry,
|
||||
reference_no as cheque_number, reference_date as cheque_date,
|
||||
if(paid_from=%(account)s, paid_amount, "") as credit,
|
||||
if(paid_from=%(account)s, "", received_amount) as debit,
|
||||
select
|
||||
"Payment Entry" as payment_document, name as payment_entry,
|
||||
reference_no as cheque_number, reference_date as cheque_date,
|
||||
if(paid_from=%(account)s, paid_amount, 0) as credit,
|
||||
if(paid_from=%(account)s, 0, received_amount) as debit,
|
||||
posting_date, ifnull(party,if(paid_from=%(account)s,paid_to,paid_from)) as against_account, clearance_date,
|
||||
if(paid_to=%(account)s, paid_to_account_currency, paid_from_account_currency) as account_currency
|
||||
from `tabPayment Entry`
|
||||
where
|
||||
(paid_from=%(account)s or paid_to=%(account)s) and docstatus=1
|
||||
and posting_date >= %(from)s and posting_date <= %(to)s {0}
|
||||
order by
|
||||
order by
|
||||
posting_date ASC, name DESC
|
||||
""".format(condition),
|
||||
""".format(condition),
|
||||
{"account":self.bank_account, "from":self.from_date, "to":self.to_date}, as_dict=1)
|
||||
|
||||
pos_entries = []
|
||||
@@ -79,8 +79,12 @@ class BankReconciliation(Document):
|
||||
|
||||
for d in entries:
|
||||
row = self.append('payment_entries', {})
|
||||
amount = d.debit if d.debit else d.credit
|
||||
d.amount = fmt_money(amount, 2, d.account_currency) + " " + (_("Dr") if d.debit else _("Cr"))
|
||||
|
||||
amount = flt(d.get('debit', 0)) - flt(d.get('credit', 0))
|
||||
|
||||
formatted_amount = fmt_money(abs(amount), 2, d.account_currency)
|
||||
d.amount = formatted_amount + " " + (_("Dr") if amount > 0 else _("Cr"))
|
||||
|
||||
d.pop("credit")
|
||||
d.pop("debit")
|
||||
d.pop("account_currency")
|
||||
@@ -103,10 +107,10 @@ class BankReconciliation(Document):
|
||||
d.clearance_date = None
|
||||
|
||||
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
|
||||
where name=%s""".format(d.payment_document),
|
||||
frappe.db.sql("""update `tab{0}` set clearance_date = %s, modified = %s
|
||||
where name=%s""".format(d.payment_document),
|
||||
(d.clearance_date, nowdate(), d.payment_entry))
|
||||
|
||||
|
||||
clearance_date_updated = True
|
||||
|
||||
if clearance_date_updated:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 0,
|
||||
@@ -19,6 +20,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Cost Center",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "budget_against",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
@@ -52,6 +54,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -86,6 +89,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.budget_against == 'Cost Center'",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "cost_center",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -120,6 +124,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.budget_against == 'Project'",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "project",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -153,6 +158,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "fiscal_year",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -186,6 +192,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@@ -218,6 +225,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:in_list([\"Stop\", \"Warn\"], doc.action_if_accumulated_monthly_budget_exceeded_on_po || doc.action_if_accumulated_monthly_budget_exceeded_on_mr || doc.action_if_accumulated_monthly_budget_exceeded_on_actual)",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "monthly_distribution",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -251,6 +259,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -283,6 +292,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_6",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@@ -315,6 +325,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "applicable_on_material_request",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@@ -343,12 +354,13 @@
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Stop",
|
||||
"depends_on": "eval:doc.applicable_on_material_request == 1",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "action_if_annual_budget_exceeded_on_mr",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
@@ -378,12 +390,13 @@
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Warn",
|
||||
"depends_on": "eval:doc.applicable_on_material_request == 1",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "action_if_accumulated_monthly_budget_exceeded_on_mr",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
@@ -417,6 +430,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_13",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@@ -448,6 +462,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "applicable_on_purchase_order",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@@ -476,12 +491,13 @@
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Stop",
|
||||
"depends_on": "eval:doc.applicable_on_purchase_order == 1",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "action_if_annual_budget_exceeded_on_po",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
@@ -511,12 +527,13 @@
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Warn",
|
||||
"depends_on": "eval:doc.applicable_on_purchase_order == 1",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "action_if_accumulated_monthly_budget_exceeded_on_po",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
@@ -550,6 +567,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_16",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@@ -581,6 +599,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "applicable_on_booking_actual_expenses",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@@ -609,12 +628,13 @@
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Stop",
|
||||
"depends_on": "eval:doc.applicable_on_booking_actual_expenses == 1",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "action_if_annual_budget_exceeded",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
@@ -644,12 +664,13 @@
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Warn",
|
||||
"depends_on": "eval:doc.applicable_on_booking_actual_expenses == 1",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "action_if_accumulated_monthly_budget_exceeded",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
@@ -683,6 +704,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_21",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@@ -715,6 +737,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "accounts",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
@@ -735,7 +758,7 @@
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
@@ -752,7 +775,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-09-12 11:02:41.825923",
|
||||
"modified": "2019-03-22 12:06:02.323099",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Budget",
|
||||
@@ -785,7 +808,7 @@
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
@@ -1,426 +1,434 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "naming_series:",
|
||||
"beta": 0,
|
||||
"creation": "2018-06-18 16:51:49.994750",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Cashier-closing-",
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Series",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Cashier-closing-",
|
||||
"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": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "user",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "User",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "User",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"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": "Today",
|
||||
"fieldname": "date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Date",
|
||||
"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": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "from_time",
|
||||
"fieldtype": "Time",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "From Time",
|
||||
"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": 1,
|
||||
"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": "",
|
||||
"fieldname": "time",
|
||||
"fieldtype": "Time",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "To Time",
|
||||
"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": 1,
|
||||
"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": "0.00",
|
||||
"fieldname": "expense",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "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,
|
||||
"default": "0.00",
|
||||
"fieldname": "custody",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Custody",
|
||||
"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": "0.00",
|
||||
"fieldname": "outstanding_amount",
|
||||
"fieldtype": "Float",
|
||||
"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": "Outstanding Amount",
|
||||
"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": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0.0",
|
||||
"fieldname": "payments",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Payments",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Cashier Closing Payments",
|
||||
"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": "net_amount",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Net Amount",
|
||||
"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": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "amended_from",
|
||||
"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": "Amended From",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Cashier Closing",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"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
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 1,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-02-19 08:35:23.157327",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Cashier Closing",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "naming_series:",
|
||||
"beta": 0,
|
||||
"creation": "2018-06-18 16:51:49.994750",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "POS-CLO-",
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Series",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "POS-CLO-",
|
||||
"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,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "user",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "User",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "User",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Today",
|
||||
"fieldname": "date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Date",
|
||||
"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,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "from_time",
|
||||
"fieldtype": "Time",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "From Time",
|
||||
"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": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "",
|
||||
"fieldname": "time",
|
||||
"fieldtype": "Time",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "To Time",
|
||||
"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": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0.00",
|
||||
"fieldname": "expense",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Expense",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "2",
|
||||
"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,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0.00",
|
||||
"fieldname": "custody",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Custody",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "2",
|
||||
"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,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0.00",
|
||||
"fieldname": "returns",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Returns",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "2",
|
||||
"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,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0.00",
|
||||
"fieldname": "outstanding_amount",
|
||||
"fieldtype": "Float",
|
||||
"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": "Outstanding Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "2",
|
||||
"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,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0.0",
|
||||
"fieldname": "payments",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Payments",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Cashier Closing Payments",
|
||||
"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,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "net_amount",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Net Amount",
|
||||
"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,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "amended_from",
|
||||
"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": "Amended From",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Cashier Closing",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"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,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 1,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-03-14 09:14:26.727129",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Cashier Closing",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
||||
@@ -29,8 +29,8 @@ class CashierClosing(Document):
|
||||
for i in self.payments:
|
||||
total += flt(i.amount)
|
||||
|
||||
self.net_amount = total + self.outstanding_amount + self.expense - self.custody
|
||||
self.net_amount = total + self.outstanding_amount + self.expense - self.custody + self.returns
|
||||
|
||||
def validate_time(self):
|
||||
if self.from_time >= self.time:
|
||||
frappe.throw(_("From Time Should Be Less Than To Time"))
|
||||
frappe.throw(_("From Time Should Be Less Than To Time"))
|
||||
@@ -6,6 +6,7 @@ import frappe, erpnext
|
||||
from frappe import _
|
||||
from frappe.utils import flt, fmt_money, getdate, formatdate
|
||||
from frappe.model.document import Document
|
||||
from frappe.model.meta import get_field_precision
|
||||
from erpnext.accounts.party import validate_party_gle_currency, validate_party_frozen_disabled
|
||||
from erpnext.accounts.utils import get_account_currency
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
@@ -56,7 +57,7 @@ class GLEntry(Document):
|
||||
.format(self.voucher_type, self.voucher_no, self.account))
|
||||
|
||||
# Zero value transaction is not allowed
|
||||
if not (flt(self.debit) or flt(self.credit)):
|
||||
if not (flt(self.debit, self.precision("debit")) or flt(self.credit, self.precision("credit"))):
|
||||
frappe.throw(_("{0} {1}: Either debit or credit amount is required for {2}")
|
||||
.format(self.voucher_type, self.voucher_no, self.account))
|
||||
|
||||
@@ -74,7 +75,8 @@ class GLEntry(Document):
|
||||
|
||||
def check_pl_account(self):
|
||||
if self.is_opening=='Yes' and \
|
||||
frappe.db.get_value("Account", self.account, "report_type")=="Profit and Loss":
|
||||
frappe.db.get_value("Account", self.account, "report_type")=="Profit and Loss" and \
|
||||
self.voucher_type not in ['Purchase Invoice', 'Sales Invoice']:
|
||||
frappe.throw(_("{0} {1}: 'Profit and Loss' type account {2} not allowed in Opening Entry")
|
||||
.format(self.voucher_type, self.voucher_no, self.account))
|
||||
|
||||
@@ -215,17 +217,23 @@ def validate_frozen_account(account, adv_adj=None):
|
||||
def update_against_account(voucher_type, voucher_no):
|
||||
entries = frappe.db.get_all("GL Entry",
|
||||
filters={"voucher_type": voucher_type, "voucher_no": voucher_no},
|
||||
fields=["name", "party", "against", "debit", "credit", "account"])
|
||||
fields=["name", "party", "against", "debit", "credit", "account", "company"])
|
||||
|
||||
if not entries:
|
||||
return
|
||||
company_currency = erpnext.get_company_currency(entries[0].company)
|
||||
precision = get_field_precision(frappe.get_meta("GL Entry")
|
||||
.get_field("debit"), company_currency)
|
||||
|
||||
accounts_debited, accounts_credited = [], []
|
||||
for d in entries:
|
||||
if flt(d.debit > 0): accounts_debited.append(d.party or d.account)
|
||||
if flt(d.credit) > 0: accounts_credited.append(d.party or d.account)
|
||||
if flt(d.debit, precision) > 0: accounts_debited.append(d.party or d.account)
|
||||
if flt(d.credit, precision) > 0: accounts_credited.append(d.party or d.account)
|
||||
|
||||
for d in entries:
|
||||
if flt(d.debit > 0):
|
||||
if flt(d.debit, precision) > 0:
|
||||
new_against = ", ".join(list(set(accounts_credited)))
|
||||
if flt(d.credit > 0):
|
||||
if flt(d.credit, precision) > 0:
|
||||
new_against = ", ".join(list(set(accounts_debited)))
|
||||
|
||||
if d.against != new_against:
|
||||
|
||||
@@ -52,11 +52,6 @@ class JournalEntry(AccountsController):
|
||||
self.update_loan()
|
||||
self.update_inter_company_jv()
|
||||
|
||||
def before_print(self):
|
||||
self.gl_entries = frappe.get_list("GL Entry",filters={"voucher_type": "Journal Entry",
|
||||
"voucher_no": self.name} ,
|
||||
fields=["account", "party_type", "party", "debit", "credit", "remarks"]
|
||||
)
|
||||
|
||||
def get_title(self):
|
||||
return self.pay_to_recd_from or self.accounts[0].account
|
||||
|
||||
@@ -232,6 +232,13 @@ frappe.ui.form.on('Payment Entry', {
|
||||
},
|
||||
|
||||
party_type: function(frm) {
|
||||
|
||||
let party_types = Object.keys(frappe.boot.party_account_types);
|
||||
if(frm.doc.party_type && !party_types.includes(frm.doc.party_type)){
|
||||
frm.set_value("party_type", "");
|
||||
frappe.throw(__("Party can only be one of "+ party_types.join(", ")));
|
||||
}
|
||||
|
||||
if(frm.doc.party) {
|
||||
$.each(["party", "party_balance", "paid_from", "paid_to",
|
||||
"paid_from_account_currency", "paid_from_account_balance",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -70,11 +70,6 @@ class PaymentEntry(AccountsController):
|
||||
self.update_advance_paid()
|
||||
self.update_expense_claim()
|
||||
|
||||
def before_print(self):
|
||||
self.gl_entries = frappe.get_list("GL Entry",filters={"voucher_type": "Payment Entry",
|
||||
"voucher_no": self.name} ,
|
||||
fields=["account", "party_type", "party", "debit", "credit", "remarks"]
|
||||
)
|
||||
|
||||
def on_cancel(self):
|
||||
self.setup_party_account_field()
|
||||
@@ -754,7 +749,7 @@ def get_outstanding_on_journal_entry(name):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_reference_details(reference_doctype, reference_name, party_account_currency):
|
||||
total_amount = outstanding_amount = exchange_rate = None
|
||||
total_amount = outstanding_amount = exchange_rate = bill_no = None
|
||||
ref_doc = frappe.get_doc(reference_doctype, reference_name)
|
||||
company_currency = ref_doc.get("company_currency") or erpnext.get_company_currency(ref_doc.company)
|
||||
|
||||
@@ -788,6 +783,7 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
|
||||
|
||||
if reference_doctype in ("Sales Invoice", "Purchase Invoice"):
|
||||
outstanding_amount = ref_doc.get("outstanding_amount")
|
||||
bill_no = ref_doc.get("bill_no")
|
||||
elif reference_doctype == "Expense Claim":
|
||||
outstanding_amount = flt(ref_doc.get("total_sanctioned_amount")) \
|
||||
- flt(ref_doc.get("total_amount+reimbursed")) - flt(ref_doc.get("total_advance_amount"))
|
||||
@@ -804,7 +800,8 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
|
||||
"due_date": ref_doc.get("due_date"),
|
||||
"total_amount": total_amount,
|
||||
"outstanding_amount": outstanding_amount,
|
||||
"exchange_rate": exchange_rate
|
||||
"exchange_rate": exchange_rate,
|
||||
"bill_no": bill_no
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -214,9 +214,10 @@ class PaymentRequest(Document):
|
||||
|
||||
def check_if_payment_entry_exists(self):
|
||||
if self.status == "Paid":
|
||||
payment_entry = frappe.db.sql_list("""select parent from `tabPayment Entry Reference`
|
||||
where reference_name=%s""", self.reference_name)
|
||||
if payment_entry:
|
||||
if frappe.get_all("Payment Entry Reference",
|
||||
filters={"reference_name": self.reference_name, "docstatus": ["<", 2]},
|
||||
fields=["parent"],
|
||||
limit=1):
|
||||
frappe.throw(_("Payment Entry already exists"), title=_('Error'))
|
||||
|
||||
def make_communication_entry(self):
|
||||
|
||||
@@ -468,7 +468,7 @@ cur_frm.fields_dict["items"].grid.get_field("cost_center").get_query = function(
|
||||
|
||||
cur_frm.cscript.cost_center = function(doc, cdt, cdn){
|
||||
var d = locals[cdt][cdn];
|
||||
if(d.idx == 1 && d.cost_center){
|
||||
if(d.cost_center){
|
||||
var cl = doc.items || [];
|
||||
for(var i = 0; i < cl.length; i++){
|
||||
if(!cl[i].cost_center) cl[i].cost_center = d.cost_center;
|
||||
@@ -510,6 +510,15 @@ frappe.ui.form.on("Purchase Invoice", {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frm.set_query("cost_center", function() {
|
||||
return {
|
||||
filters: {
|
||||
company: frm.doc.company,
|
||||
is_group: 0
|
||||
}
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
onload: function(frm) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@ from frappe.utils import cint, cstr, formatdate, flt, getdate, nowdate
|
||||
from frappe import _, throw
|
||||
import frappe.defaults
|
||||
|
||||
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
|
||||
from erpnext.controllers.buying_controller import BuyingController
|
||||
from erpnext.accounts.party import get_party_account, get_due_date
|
||||
from erpnext.accounts.utils import get_account_currency, get_fiscal_year
|
||||
@@ -17,7 +18,7 @@ from erpnext.accounts.general_ledger import make_gl_entries, merge_similar_entri
|
||||
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
|
||||
from erpnext.buying.utils import check_for_closed_status
|
||||
from erpnext.accounts.general_ledger import get_round_off_account_and_cost_center
|
||||
from erpnext.assets.doctype.asset.asset import get_asset_account
|
||||
from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_disabled
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
from six import iteritems
|
||||
from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_invoice,\
|
||||
@@ -54,11 +55,6 @@ class PurchaseInvoice(BuyingController):
|
||||
if not self.on_hold:
|
||||
self.release_date = ''
|
||||
|
||||
def before_print(self):
|
||||
self.gl_entries = frappe.get_list("GL Entry",filters={"voucher_type": "Purchase Invoice",
|
||||
"voucher_no": self.name} ,
|
||||
fields=["account", "party_type", "party", "debit", "credit"]
|
||||
)
|
||||
|
||||
def invoice_is_blocked(self):
|
||||
return self.on_hold and (not self.release_date or self.release_date > getdate(nowdate()))
|
||||
@@ -222,7 +218,7 @@ class PurchaseInvoice(BuyingController):
|
||||
self.validate_item_code()
|
||||
self.validate_warehouse()
|
||||
if auto_accounting_for_stock:
|
||||
warehouse_account = get_warehouse_account_map()
|
||||
warehouse_account = get_warehouse_account_map(self.company)
|
||||
|
||||
for item in self.get("items"):
|
||||
# in case of auto inventory accounting,
|
||||
@@ -238,6 +234,13 @@ class PurchaseInvoice(BuyingController):
|
||||
item.expense_account = warehouse_account[item.warehouse]["account"]
|
||||
else:
|
||||
item.expense_account = stock_not_billed_account
|
||||
elif item.is_fixed_asset and is_cwip_accounting_disabled():
|
||||
if not item.asset:
|
||||
frappe.throw(_("Row {0}: asset is required for item {1}")
|
||||
.format(item.idx, item.item_code))
|
||||
|
||||
item.expense_account = get_asset_category_account(item.asset, 'fixed_asset_account',
|
||||
company = self.company)
|
||||
elif item.is_fixed_asset and item.pr_detail:
|
||||
item.expense_account = asset_received_but_not_billed
|
||||
elif not item.expense_account and for_validate:
|
||||
@@ -366,7 +369,8 @@ class PurchaseInvoice(BuyingController):
|
||||
if repost_future_gle and cint(self.update_stock) and self.auto_accounting_for_stock:
|
||||
from erpnext.controllers.stock_controller import update_gl_entries_after
|
||||
items, warehouses = self.get_items_and_warehouses()
|
||||
update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items)
|
||||
update_gl_entries_after(self.posting_date, self.posting_time,
|
||||
warehouses, items, company = self.company)
|
||||
|
||||
elif self.docstatus == 2 and cint(self.update_stock) and self.auto_accounting_for_stock:
|
||||
delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
||||
@@ -383,7 +387,9 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
self.make_supplier_gl_entry(gl_entries)
|
||||
self.make_item_gl_entries(gl_entries)
|
||||
self.get_asset_gl_entry(gl_entries)
|
||||
if not is_cwip_accounting_disabled():
|
||||
self.get_asset_gl_entry(gl_entries)
|
||||
|
||||
self.make_tax_gl_entries(gl_entries)
|
||||
|
||||
gl_entries = merge_similar_entries(gl_entries)
|
||||
@@ -423,7 +429,7 @@ class PurchaseInvoice(BuyingController):
|
||||
stock_items = self.get_stock_items()
|
||||
expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
|
||||
if self.update_stock and self.auto_accounting_for_stock:
|
||||
warehouse_account = get_warehouse_account_map()
|
||||
warehouse_account = get_warehouse_account_map(self.company)
|
||||
|
||||
voucher_wise_stock_value = {}
|
||||
if self.update_stock:
|
||||
@@ -475,7 +481,7 @@ class PurchaseInvoice(BuyingController):
|
||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||
"credit": flt(item.rm_supp_cost)
|
||||
}, warehouse_account[self.supplier_warehouse]["account_currency"]))
|
||||
elif not item.is_fixed_asset:
|
||||
elif not item.is_fixed_asset or (item.is_fixed_asset and is_cwip_accounting_disabled()):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": item.expense_account if not item.enable_deferred_expense else item.deferred_expense_account,
|
||||
@@ -520,7 +526,7 @@ class PurchaseInvoice(BuyingController):
|
||||
base_asset_amount = flt(item.base_net_amount + item.item_tax_amount)
|
||||
|
||||
if (not item.expense_account or frappe.db.get_value('Account',
|
||||
item.expense_account, 'account_type') != 'Asset Received But Not Billed'):
|
||||
item.expense_account, 'account_type') not in ['Asset Received But Not Billed', 'Fixed Asset']):
|
||||
arbnb_account = self.get_company_default("asset_received_but_not_billed")
|
||||
item.expense_account = arbnb_account
|
||||
|
||||
|
||||
@@ -344,6 +344,7 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
|
||||
pi = frappe.copy_doc(test_records[0])
|
||||
pi.disable_rounded_total = 1
|
||||
pi.allocate_advances_automatically = 0
|
||||
pi.append("advances", {
|
||||
"reference_type": "Journal Entry",
|
||||
"reference_name": jv.name,
|
||||
@@ -383,6 +384,7 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
|
||||
pi = frappe.copy_doc(test_records[0])
|
||||
pi.disable_rounded_total = 1
|
||||
pi.allocate_advances_automatically = 0
|
||||
pi.append("advances", {
|
||||
"reference_type": "Journal Entry",
|
||||
"reference_name": jv.name,
|
||||
@@ -551,7 +553,7 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
sum(credit) as credit, debit_in_account_currency, credit_in_account_currency
|
||||
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
|
||||
group by account, voucher_no order by account asc;""", pi.name, as_dict=1)
|
||||
|
||||
|
||||
stock_in_hand_account = get_inventory_account(pi.company, pi.get("items")[0].warehouse)
|
||||
self.assertTrue(gl_entries)
|
||||
|
||||
@@ -634,7 +636,7 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
|
||||
self.assertEqual(frappe.db.get_value("Serial No", pi.get("items")[0].rejected_serial_no,
|
||||
"warehouse"), pi.get("items")[0].rejected_warehouse)
|
||||
|
||||
|
||||
def test_outstanding_amount_after_advance_jv_cancelation(self):
|
||||
from erpnext.accounts.doctype.journal_entry.test_journal_entry \
|
||||
import test_records as jv_test_records
|
||||
@@ -656,14 +658,14 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
pi.insert()
|
||||
pi.submit()
|
||||
pi.load_from_db()
|
||||
|
||||
|
||||
#check outstanding after advance allocation
|
||||
self.assertEqual(flt(pi.outstanding_amount), flt(pi.rounded_total - pi.total_advance))
|
||||
|
||||
|
||||
#added to avoid Document has been modified exception
|
||||
jv = frappe.get_doc("Journal Entry", jv.name)
|
||||
jv.cancel()
|
||||
|
||||
|
||||
pi.load_from_db()
|
||||
#check outstanding after advance cancellation
|
||||
self.assertEqual(flt(pi.outstanding_amount), flt(pi.rounded_total + pi.total_advance))
|
||||
@@ -722,7 +724,7 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
shipping_rule = create_shipping_rule(shipping_rule_type = "Buying", shipping_rule_name = "Shipping Rule - Purchase Invoice Test")
|
||||
|
||||
pi = frappe.copy_doc(test_records[0])
|
||||
|
||||
|
||||
pi.shipping_rule = shipping_rule.name
|
||||
pi.insert()
|
||||
|
||||
@@ -740,14 +742,14 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
"tax_amount": shipping_amount,
|
||||
"description": shipping_rule.name,
|
||||
"add_deduct_tax": "Add"
|
||||
}
|
||||
}
|
||||
pi.append("taxes", shipping_charge)
|
||||
pi.save()
|
||||
|
||||
self.assertEqual(pi.net_total, 1250)
|
||||
|
||||
self.assertEqual(pi.total_taxes_and_charges, 462.3)
|
||||
self.assertEqual(pi.grand_total, 1712.3)
|
||||
self.assertEqual(pi.grand_total, 1712.3)
|
||||
|
||||
def test_make_pi_without_terms(self):
|
||||
pi = make_purchase_invoice(do_not_save=1)
|
||||
|
||||
@@ -564,6 +564,15 @@ frappe.ui.form.on('Sales Invoice', {
|
||||
};
|
||||
});
|
||||
|
||||
frm.set_query("cost_center", function() {
|
||||
return {
|
||||
filters: {
|
||||
company: frm.doc.company,
|
||||
is_group: 0
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
frm.custom_make_buttons = {
|
||||
'Delivery Note': 'Delivery',
|
||||
'Sales Invoice': 'Sales Return',
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -205,11 +205,6 @@ class SalesInvoice(SellingController):
|
||||
def before_cancel(self):
|
||||
self.update_time_sheet(None)
|
||||
|
||||
def before_print(self):
|
||||
self.gl_entries = frappe.get_list("GL Entry",filters={"voucher_type": "Sales Invoice",
|
||||
"voucher_no": self.name} ,
|
||||
fields=["account", "party_type", "party", "debit", "credit"]
|
||||
)
|
||||
|
||||
def on_cancel(self):
|
||||
self.check_close_sales_order("sales_order")
|
||||
@@ -405,7 +400,7 @@ class SalesInvoice(SellingController):
|
||||
|
||||
for fieldname in ('territory', 'naming_series', 'currency', 'taxes_and_charges', 'letter_head', 'tc_name',
|
||||
'company', 'select_print_heading', 'cash_bank_account', 'company_address',
|
||||
'write_off_account', 'write_off_cost_center', 'apply_discount_on'):
|
||||
'write_off_account', 'write_off_cost_center', 'apply_discount_on', 'cost_center'):
|
||||
if (not for_validate) or (for_validate and not self.get(fieldname)):
|
||||
self.set(fieldname, pos.get(fieldname))
|
||||
|
||||
@@ -695,7 +690,8 @@ class SalesInvoice(SellingController):
|
||||
if repost_future_gle and cint(self.update_stock) \
|
||||
and cint(auto_accounting_for_stock):
|
||||
items, warehouses = self.get_items_and_warehouses()
|
||||
update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items)
|
||||
update_gl_entries_after(self.posting_date, self.posting_time,
|
||||
warehouses, items, company = self.company)
|
||||
elif self.docstatus == 2 and cint(self.update_stock) \
|
||||
and cint(auto_accounting_for_stock):
|
||||
from erpnext.accounts.general_ledger import delete_gl_entries
|
||||
|
||||
@@ -14,8 +14,9 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_per
|
||||
from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency
|
||||
from erpnext.stock.doctype.serial_no.serial_no import SerialNoWarehouseError
|
||||
from frappe.model.naming import make_autoname
|
||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account
|
||||
from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data
|
||||
from erpnext.stock.doctype.item.test_item import create_item
|
||||
from six import iteritems
|
||||
class TestSalesInvoice(unittest.TestCase):
|
||||
def make(self):
|
||||
@@ -762,7 +763,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
set_perpetual_inventory(0)
|
||||
|
||||
frappe.db.sql("delete from `tabPOS Profile`")
|
||||
|
||||
|
||||
def test_pos_si_without_payment(self):
|
||||
set_perpetual_inventory()
|
||||
make_pos_profile()
|
||||
@@ -854,6 +855,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
jv.submit()
|
||||
|
||||
si = frappe.copy_doc(test_records[0])
|
||||
si.allocate_advances_automatically = 0
|
||||
si.append("advances", {
|
||||
"doctype": "Sales Invoice Advance",
|
||||
"reference_type": "Journal Entry",
|
||||
@@ -1514,6 +1516,56 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
|
||||
accounts_settings.save()
|
||||
|
||||
def test_deferred_revenue(self):
|
||||
deferred_account = create_account(account_name="Deferred Revenue",
|
||||
parent_account="Current Liabilities - _TC", company="_Test Company")
|
||||
|
||||
item = create_item("_Test Item for Deferred Accounting")
|
||||
item.enable_deferred_revenue = 1
|
||||
item.deferred_revenue_account = deferred_account
|
||||
item.no_of_months = 12
|
||||
item.save()
|
||||
|
||||
si = create_sales_invoice(item=item.name, posting_date="2019-01-10", do_not_submit=True)
|
||||
si.items[0].enable_deferred_revenue = 1
|
||||
si.items[0].service_start_date = "2019-01-10"
|
||||
si.items[0].service_end_date = "2019-03-15"
|
||||
si.items[0].deferred_revenue_account = deferred_account
|
||||
si.save()
|
||||
si.submit()
|
||||
|
||||
from erpnext.accounts.deferred_revenue import convert_deferred_revenue_to_income
|
||||
convert_deferred_revenue_to_income(start_date="2019-01-01", end_date="2019-01-31")
|
||||
|
||||
expected_gle = [
|
||||
[deferred_account, 33.85, 0.0, "2019-01-31"],
|
||||
["Sales - _TC", 0.0, 33.85, "2019-01-31"]
|
||||
]
|
||||
|
||||
self.check_gl_entries(si.name, expected_gle, "2019-01-10")
|
||||
|
||||
convert_deferred_revenue_to_income(start_date="2019-01-01", end_date="2019-03-31")
|
||||
|
||||
expected_gle = [
|
||||
[deferred_account, 43.08, 0.0, "2019-02-28"],
|
||||
["Sales - _TC", 0.0, 43.08, "2019-02-28"],
|
||||
[deferred_account, 23.07, 0.0, "2019-03-15"],
|
||||
["Sales - _TC", 0.0, 23.07, "2019-03-15"]
|
||||
]
|
||||
|
||||
self.check_gl_entries(si.name, expected_gle, "2019-01-31")
|
||||
|
||||
def check_gl_entries(self, voucher_no, expected_gle, posting_date):
|
||||
gl_entries = frappe.db.sql("""select account, debit, credit, posting_date
|
||||
from `tabGL Entry`
|
||||
where voucher_type='Sales Invoice' and voucher_no=%s and posting_date > %s
|
||||
order by posting_date asc, account asc""", (voucher_no, posting_date), as_dict=1)
|
||||
|
||||
for i, gle in enumerate(gl_entries):
|
||||
self.assertEqual(expected_gle[i][0], gle.account)
|
||||
self.assertEqual(expected_gle[i][1], gle.debit)
|
||||
self.assertEqual(expected_gle[i][2], gle.credit)
|
||||
self.assertEqual(getdate(expected_gle[i][3]), gle.posting_date)
|
||||
|
||||
def create_sales_invoice(**args):
|
||||
si = frappe.new_doc("Sales Invoice")
|
||||
@@ -1611,4 +1663,4 @@ def get_outstanding_amount(against_voucher_type, against_voucher, account, party
|
||||
if against_voucher_type == 'Purchase Invoice':
|
||||
bal = bal * -1
|
||||
|
||||
return bal
|
||||
return bal
|
||||
@@ -333,6 +333,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
var me = this;
|
||||
this.frm = {}
|
||||
this.load_data(true);
|
||||
this.frm.doc.offline_pos_name = '';
|
||||
this.setup();
|
||||
this.set_default_customer()
|
||||
},
|
||||
@@ -345,7 +346,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
|
||||
if (load_doc) {
|
||||
this.frm.doc = JSON.parse(localStorage.getItem('doc'));
|
||||
this.frm.doc.offline_pos_name = null;
|
||||
}
|
||||
|
||||
$.each(this.meta, function (i, data) {
|
||||
@@ -641,7 +641,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
me.list_customers_btn.toggleClass("view_customer");
|
||||
me.pos_bill.show();
|
||||
me.list_customers_btn.show();
|
||||
me.frm.doc.offline_pos_name = $(this).parents().attr('invoice-name')
|
||||
me.frm.doc.offline_pos_name = $(this).parents().attr('invoice-name');
|
||||
me.edit_record();
|
||||
})
|
||||
|
||||
@@ -984,7 +984,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
}
|
||||
|
||||
if(!this.customer_doc.fields_dict.customer_pos_id.value) {
|
||||
this.customer_doc.set_value("customer_pos_id", $.now())
|
||||
this.customer_doc.set_value("customer_pos_id", frappe.datetime.now_datetime())
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1686,10 +1686,18 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
|
||||
create_invoice: function () {
|
||||
var me = this;
|
||||
var existing_pos_list = [];
|
||||
var invoice_data = {};
|
||||
this.si_docs = this.get_doc_from_localstorage();
|
||||
|
||||
if (this.frm.doc.offline_pos_name) {
|
||||
if(this.si_docs) {
|
||||
this.si_docs.forEach((row) => {
|
||||
existing_pos_list.push(Object.keys(row));
|
||||
});
|
||||
}
|
||||
|
||||
if (this.frm.doc.offline_pos_name
|
||||
&& in_list(existing_pos_list, this.frm.doc.offline_pos_name)) {
|
||||
this.update_invoice()
|
||||
//to retrieve and set the default payment
|
||||
invoice_data[this.frm.doc.offline_pos_name] = this.frm.doc;
|
||||
@@ -1698,8 +1706,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
|
||||
this.frm.doc.paid_amount = this.frm.doc.net_total
|
||||
this.frm.doc.outstanding_amount = 0
|
||||
} else {
|
||||
this.frm.doc.offline_pos_name = $.now();
|
||||
} else if(!this.frm.doc.offline_pos_name) {
|
||||
this.frm.doc.offline_pos_name = frappe.datetime.now_datetime();
|
||||
this.frm.doc.posting_date = frappe.datetime.get_today();
|
||||
this.frm.doc.posting_time = frappe.datetime.now_time();
|
||||
this.frm.doc.pos_total_qty = this.frm.doc.qty_total;
|
||||
|
||||
@@ -573,11 +573,17 @@ def get_party_shipping_address(doctype, name):
|
||||
else:
|
||||
return ''
|
||||
|
||||
def get_partywise_advanced_payment_amount(party_type="Customer"):
|
||||
def get_partywise_advanced_payment_amount(party_type, posting_date = None):
|
||||
cond = "1=1"
|
||||
if posting_date:
|
||||
cond = "posting_date <= '{0}'".format(posting_date)
|
||||
|
||||
data = frappe.db.sql(""" SELECT party, sum({0}) as amount
|
||||
FROM `tabGL Entry`
|
||||
WHERE party_type = %s and against_voucher is null GROUP BY party"""
|
||||
.format(("credit - debit") if party_type == "Customer" else "debit") , party_type)
|
||||
WHERE
|
||||
party_type = %s and against_voucher is null
|
||||
and {1} GROUP BY party"""
|
||||
.format(("credit") if party_type == "Customer" else "debit", cond) , party_type)
|
||||
|
||||
if data:
|
||||
return frappe._dict(data)
|
||||
@@ -107,26 +107,28 @@
|
||||
<thead>
|
||||
<tr>
|
||||
{% if(report.report_name === "Accounts Receivable" || report.report_name === "Accounts Payable") { %}
|
||||
<th style="width: 7%">{%= __("Date") %}</th>
|
||||
<th style="width: 7%">{%= __("Age (Days)") %}</th>
|
||||
<th style="width: 13%">{%= __("Reference") %}</th>
|
||||
{% if(report.report_name === "Accounts Receivable") { %}
|
||||
<th style="width: 10%">{%= __("Sales Person") %}</th>
|
||||
<th style="width: 9%">{%= __("Date") %}</th>
|
||||
<th style="width: 5%">{%= __("Age (Days)") %}</th>
|
||||
|
||||
{% if(report.report_name === "Accounts Receivable" && filters.show_sales_person_in_print) { %}
|
||||
<th style="width: 16%">{%= __("Reference") %}</th>
|
||||
<th style="width: 10%">{%= __("Sales Person") %}</th>
|
||||
{% } else { %}
|
||||
<th style="width: 26%">{%= __("Reference") %}</th>
|
||||
{% } %}
|
||||
{% if(!filters.show_pdc_in_print) { %}
|
||||
<th style="width: 20%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
|
||||
<th style="width: 20%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
|
||||
{% } %}
|
||||
<th style="width: 10%; text-align: right">{%= __("Invoiced Amount") %}</th>
|
||||
{% if(!filters.show_pdc_in_print) { %}
|
||||
<th style="width: 10%; text-align: right">{%= __("Paid Amount") %}</th>
|
||||
<th style="width: 10%; text-align: right">{%= report.report_name === "Accounts Receivable" ? __('Credit Note') : __('Debit Note') %}</th>
|
||||
{% } %}
|
||||
<th style="width: 15%; text-align: right">{%= __("Outstanding Amount") %}</th>
|
||||
<th style="width: 10%; text-align: right">{%= __("Outstanding Amount") %}</th>
|
||||
{% if(filters.show_pdc_in_print) { %}
|
||||
{% if(report.report_name === "Accounts Receivable") { %}
|
||||
<th style="width: 10%">{%= __("Customer LPO No.") %}</th>
|
||||
{% } %}
|
||||
<th style="width: 10%">{%= __("PDC/LC Date") %}</th>
|
||||
<th style="width: 10%">{%= __("PDC/LC Ref") %}</th>
|
||||
<th style="width: 10%">{%= __("PDC/LC Amount") %}</th>
|
||||
<th style="width: 10%">{%= __("Remaining Balance") %}</th>
|
||||
@@ -155,7 +157,7 @@
|
||||
{%= data[i]["voucher_no"] %}
|
||||
</td>
|
||||
|
||||
{% if(report.report_name === "Accounts Receivable") { %}
|
||||
{% if(report.report_name === "Accounts Receivable" && filters.show_sales_person_in_print) { %}
|
||||
<td>{%= data[i]["sales_person"] %}</td>
|
||||
{% } %}
|
||||
|
||||
@@ -195,7 +197,6 @@
|
||||
<td style="text-align: right">
|
||||
{%= data[i]["po_no"] %}</td>
|
||||
{% } %}
|
||||
<td style="text-align: right">{%= frappe.datetime.str_to_user(data[i][("pdc/lc_date")]) %}</td>
|
||||
<td style="text-align: right">{%= data[i][("pdc/lc_ref")] %}</td>
|
||||
<td style="text-align: right">{%= format_currency(data[i][("pdc/lc_amount")], data[i]["currency"]) %}</td>
|
||||
<td style="text-align: right">{%= format_currency(data[i][("remaining_balance")], data[i]["currency"]) %}</td>
|
||||
@@ -226,7 +227,6 @@
|
||||
<td style="text-align: right">
|
||||
{%= data[i][__("Customer LPO")] %}</td>
|
||||
{% } %}
|
||||
<td style="text-align: right">{%= frappe.datetime.str_to_user(data[i][__("PDC/LC Date")]) %}</td>
|
||||
<td style="text-align: right">{%= data[i][("pdc/lc_ref")] %}</td>
|
||||
<td style="text-align: right">{%= format_currency(data[i][("pdc/lc_amount")], data[i]["currency"]) %}</td>
|
||||
<td style="text-align: right">{%= format_currency(data[i][("remaining_balance")], data[i]["currency"]) %}</td>
|
||||
|
||||
@@ -102,14 +102,19 @@ frappe.query_reports["Accounts Receivable"] = {
|
||||
"fieldtype": "Link",
|
||||
"options": "Sales Person"
|
||||
},
|
||||
{
|
||||
"fieldname":"based_on_payment_terms",
|
||||
"label": __("Based On Payment Terms"),
|
||||
"fieldtype": "Check",
|
||||
},
|
||||
{
|
||||
"fieldname":"show_pdc_in_print",
|
||||
"label": __("Show PDC in Print"),
|
||||
"fieldtype": "Check",
|
||||
},
|
||||
{
|
||||
"fieldname":"based_on_payment_terms",
|
||||
"label": __("Based On Payment Terms"),
|
||||
"fieldname":"show_sales_person_in_print",
|
||||
"label": __("Show Sales Person in Print"),
|
||||
"fieldtype": "Check",
|
||||
},
|
||||
{
|
||||
|
||||
@@ -136,7 +136,8 @@ class AccountsReceivableSummary(ReceivablePayableReport):
|
||||
|
||||
partywise_total = self.get_partywise_total(party_naming_by, args)
|
||||
|
||||
partywise_advance_amount = get_partywise_advanced_payment_amount(args.get("party_type")) or {}
|
||||
partywise_advance_amount = get_partywise_advanced_payment_amount(args.get("party_type"),
|
||||
self.filters.get("report_date")) or {}
|
||||
for party, party_dict in iteritems(partywise_total):
|
||||
row = [party]
|
||||
|
||||
@@ -145,8 +146,12 @@ class AccountsReceivableSummary(ReceivablePayableReport):
|
||||
|
||||
row += [partywise_advance_amount.get(party, 0)]
|
||||
|
||||
paid_amt = 0
|
||||
if party_dict.paid_amt > 0:
|
||||
paid_amt = flt(party_dict.paid_amt - partywise_advance_amount.get(party, 0))
|
||||
|
||||
row += [
|
||||
party_dict.invoiced_amt, party_dict.paid_amt, party_dict.credit_amt, party_dict.outstanding_amt,
|
||||
party_dict.invoiced_amt, paid_amt, party_dict.credit_amt, party_dict.outstanding_amt,
|
||||
party_dict.range1, party_dict.range2, party_dict.range3, party_dict.range4,
|
||||
]
|
||||
|
||||
@@ -205,7 +210,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
|
||||
|
||||
cols += ["invoiced_amt", "paid_amt", "credit_amt",
|
||||
"outstanding_amt", "age", "range1", "range2", "range3", "range4", "currency", "pdc/lc_date", "pdc/lc_ref",
|
||||
"pdc/lc_amount", "remaining_balance"]
|
||||
"pdc/lc_amount"]
|
||||
|
||||
if args.get("party_type") == "Supplier":
|
||||
cols += ["supplier_group", "remarks"]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import erpnext
|
||||
from frappe import _
|
||||
from frappe import _, scrub
|
||||
from frappe.utils import getdate, nowdate
|
||||
from six import iteritems, itervalues
|
||||
|
||||
@@ -14,6 +14,9 @@ class PartyLedgerSummaryReport(object):
|
||||
self.filters.from_date = getdate(self.filters.from_date or nowdate())
|
||||
self.filters.to_date = getdate(self.filters.to_date or nowdate())
|
||||
|
||||
if not self.filters.get("company"):
|
||||
self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_company')
|
||||
|
||||
def run(self, args):
|
||||
if self.filters.from_date > self.filters.to_date:
|
||||
frappe.throw(_("From Date must be before To Date"))
|
||||
@@ -21,10 +24,9 @@ class PartyLedgerSummaryReport(object):
|
||||
self.filters.party_type = args.get("party_type")
|
||||
self.party_naming_by = frappe.db.get_value(args.get("naming_by")[0], None, args.get("naming_by")[1])
|
||||
|
||||
discount_account_field = "discount_allowed_account" if self.filters.party_type == "Customer" \
|
||||
else "discount_received_account"
|
||||
self.round_off_account, self.write_off_account, self.discount_account = frappe.get_cached_value('Company',
|
||||
self.filters.company, ["round_off_account", "write_off_account", discount_account_field])
|
||||
self.get_gl_entries()
|
||||
self.get_return_invoices()
|
||||
self.get_party_adjustment_amounts()
|
||||
|
||||
columns = self.get_columns()
|
||||
data = self.get_data()
|
||||
@@ -48,7 +50,6 @@ class PartyLedgerSummaryReport(object):
|
||||
})
|
||||
|
||||
credit_or_debit_note = "Credit Note" if self.filters.party_type == "Customer" else "Debit Note"
|
||||
discount_allowed_or_received = "Discount Allowed" if self.filters.party_type == "Customer" else "Discount Received"
|
||||
|
||||
columns += [
|
||||
{
|
||||
@@ -79,27 +80,19 @@ class PartyLedgerSummaryReport(object):
|
||||
"options": "currency",
|
||||
"width": 120
|
||||
},
|
||||
{
|
||||
"label": _(discount_allowed_or_received),
|
||||
"fieldname": "discount_amount",
|
||||
]
|
||||
|
||||
for account in self.party_adjustment_accounts:
|
||||
columns.append({
|
||||
"label": account,
|
||||
"fieldname": "adj_" + scrub(account),
|
||||
"fieldtype": "Currency",
|
||||
"options": "currency",
|
||||
"width": 120
|
||||
},
|
||||
{
|
||||
"label": _("Write Off Amount"),
|
||||
"fieldname": "write_off_amount",
|
||||
"fieldtype": "Currency",
|
||||
"options": "currency",
|
||||
"width": 120
|
||||
},
|
||||
{
|
||||
"label": _("Other Adjustments"),
|
||||
"fieldname": "adjustment_amount",
|
||||
"fieldtype": "Currency",
|
||||
"options": "currency",
|
||||
"width": 120
|
||||
},
|
||||
"width": 120,
|
||||
"is_adjustment": 1
|
||||
})
|
||||
|
||||
columns += [
|
||||
{
|
||||
"label": _("Closing Balance"),
|
||||
"fieldname": "closing_balance",
|
||||
@@ -119,17 +112,10 @@ class PartyLedgerSummaryReport(object):
|
||||
return columns
|
||||
|
||||
def get_data(self):
|
||||
if not self.filters.get("company"):
|
||||
self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_company')
|
||||
|
||||
company_currency = frappe.get_cached_value('Company', self.filters.get("company"), "default_currency")
|
||||
invoice_dr_or_cr = "debit" if self.filters.party_type == "Customer" else "credit"
|
||||
reverse_dr_or_cr = "credit" if self.filters.party_type == "Customer" else "debit"
|
||||
|
||||
self.get_gl_entries()
|
||||
self.get_return_invoices()
|
||||
self.get_party_adjustment_amounts()
|
||||
|
||||
self.party_data = frappe._dict({})
|
||||
for gle in self.gl_entries:
|
||||
self.party_data.setdefault(gle.party, frappe._dict({
|
||||
@@ -146,7 +132,7 @@ class PartyLedgerSummaryReport(object):
|
||||
amount = gle.get(invoice_dr_or_cr) - gle.get(reverse_dr_or_cr)
|
||||
self.party_data[gle.party].closing_balance += amount
|
||||
|
||||
if gle.posting_date < self.filters.from_date:
|
||||
if gle.posting_date < self.filters.from_date or gle.is_opening == "Yes":
|
||||
self.party_data[gle.party].opening_balance += amount
|
||||
else:
|
||||
if amount > 0:
|
||||
@@ -161,9 +147,10 @@ class PartyLedgerSummaryReport(object):
|
||||
if row.opening_balance or row.invoiced_amount or row.paid_amount or row.return_amount or row.closing_amount:
|
||||
total_party_adjustment = sum([amount for amount in itervalues(self.party_adjustment_details.get(party, {}))])
|
||||
row.paid_amount -= total_party_adjustment
|
||||
row.discount_amount = self.party_adjustment_details.get(party, {}).get(self.discount_account, 0)
|
||||
row.write_off_amount = self.party_adjustment_details.get(party, {}).get(self.write_off_account, 0)
|
||||
row.adjustment_amount = total_party_adjustment - row.discount_amount - row.write_off_amount
|
||||
|
||||
adjustments = self.party_adjustment_details.get(party, {})
|
||||
for account in self.party_adjustment_accounts:
|
||||
row["adj_" + scrub(account)] = adjustments.get(account, 0)
|
||||
|
||||
out.append(row)
|
||||
|
||||
@@ -182,7 +169,7 @@ class PartyLedgerSummaryReport(object):
|
||||
self.gl_entries = frappe.db.sql("""
|
||||
select
|
||||
gle.posting_date, gle.party, gle.voucher_type, gle.voucher_no, gle.against_voucher_type,
|
||||
gle.against_voucher, gle.debit, gle.credit {join_field}
|
||||
gle.against_voucher, gle.debit, gle.credit, gle.is_opening {join_field}
|
||||
from `tabGL Entry` gle
|
||||
{join}
|
||||
where
|
||||
@@ -195,7 +182,7 @@ class PartyLedgerSummaryReport(object):
|
||||
conditions = [""]
|
||||
|
||||
if self.filters.company:
|
||||
conditions.append("company=%(company)s")
|
||||
conditions.append("gle.company=%(company)s")
|
||||
|
||||
self.filters.company_finance_book = erpnext.get_default_finance_book(self.filters.company)
|
||||
|
||||
@@ -254,9 +241,10 @@ class PartyLedgerSummaryReport(object):
|
||||
|
||||
def get_party_adjustment_amounts(self):
|
||||
conditions = self.prepare_conditions()
|
||||
income_or_expense = "Expense" if self.filters.party_type == "Customer" else "Income"
|
||||
income_or_expense = "Expense Account" if self.filters.party_type == "Customer" else "Income Account"
|
||||
invoice_dr_or_cr = "debit" if self.filters.party_type == "Customer" else "credit"
|
||||
reverse_dr_or_cr = "credit" if self.filters.party_type == "Customer" else "debit"
|
||||
round_off_account = frappe.get_cached_value('Company', self.filters.company, "round_off_account")
|
||||
|
||||
gl_entries = frappe.db.sql("""
|
||||
select
|
||||
@@ -267,7 +255,7 @@ class PartyLedgerSummaryReport(object):
|
||||
docstatus < 2
|
||||
and (voucher_type, voucher_no) in (
|
||||
select voucher_type, voucher_no from `tabGL Entry` gle, `tabAccount` acc
|
||||
where acc.name = gle.account and acc.root_type = '{income_or_expense}'
|
||||
where acc.name = gle.account and acc.account_type = '{income_or_expense}'
|
||||
and gle.posting_date between %(from_date)s and %(to_date)s and gle.docstatus < 2
|
||||
) and (voucher_type, voucher_no) in (
|
||||
select voucher_type, voucher_no from `tabGL Entry` gle
|
||||
@@ -277,6 +265,7 @@ class PartyLedgerSummaryReport(object):
|
||||
""".format(conditions=conditions, income_or_expense=income_or_expense), self.filters, as_dict=True)
|
||||
|
||||
self.party_adjustment_details = {}
|
||||
self.party_adjustment_accounts = set()
|
||||
adjustment_voucher_entries = {}
|
||||
for gle in gl_entries:
|
||||
adjustment_voucher_entries.setdefault((gle.voucher_type, gle.voucher_no), [])
|
||||
@@ -288,12 +277,12 @@ class PartyLedgerSummaryReport(object):
|
||||
has_irrelevant_entry = False
|
||||
|
||||
for gle in voucher_gl_entries:
|
||||
if gle.account == self.round_off_account:
|
||||
if gle.account == round_off_account:
|
||||
continue
|
||||
elif gle.party:
|
||||
parties.setdefault(gle.party, 0)
|
||||
parties[gle.party] += gle.get(reverse_dr_or_cr) - gle.get(invoice_dr_or_cr)
|
||||
elif frappe.get_cached_value("Account", gle.account, "root_type") == income_or_expense:
|
||||
elif frappe.get_cached_value("Account", gle.account, "account_type") == income_or_expense:
|
||||
accounts.setdefault(gle.account, 0)
|
||||
accounts[gle.account] += gle.get(invoice_dr_or_cr) - gle.get(reverse_dr_or_cr)
|
||||
else:
|
||||
@@ -303,11 +292,13 @@ class PartyLedgerSummaryReport(object):
|
||||
if len(parties) == 1:
|
||||
party = parties.keys()[0]
|
||||
for account, amount in iteritems(accounts):
|
||||
self.party_adjustment_accounts.add(account)
|
||||
self.party_adjustment_details.setdefault(party, {})
|
||||
self.party_adjustment_details[party].setdefault(account, 0)
|
||||
self.party_adjustment_details[party][account] += amount
|
||||
elif len(accounts) == 1 and not has_irrelevant_entry:
|
||||
account = accounts.keys()[0]
|
||||
self.party_adjustment_accounts.add(account)
|
||||
for party, amount in iteritems(parties):
|
||||
self.party_adjustment_details.setdefault(party, {})
|
||||
self.party_adjustment_details[party].setdefault(account, 0)
|
||||
|
||||
@@ -125,10 +125,11 @@ class GrossProfitGenerator(object):
|
||||
|
||||
# get buying amount
|
||||
if row.item_code in product_bundles:
|
||||
row.buying_amount = self.get_buying_amount_from_product_bundle(row,
|
||||
product_bundles[row.item_code])
|
||||
row.buying_amount = flt(self.get_buying_amount_from_product_bundle(row,
|
||||
product_bundles[row.item_code]), self.currency_precision)
|
||||
else:
|
||||
row.buying_amount = self.get_buying_amount(row, row.item_code)
|
||||
row.buying_amount = flt(self.get_buying_amount(row, row.item_code),
|
||||
self.currency_precision)
|
||||
|
||||
# get buying rate
|
||||
if row.qty:
|
||||
@@ -215,7 +216,7 @@ class GrossProfitGenerator(object):
|
||||
if packed_item.get("parent_detail_docname")==row.item_row:
|
||||
buying_amount += self.get_buying_amount(row, packed_item.item_code)
|
||||
|
||||
return buying_amount
|
||||
return flt(buying_amount, self.currency_precision)
|
||||
|
||||
def get_buying_amount(self, row, item_code):
|
||||
# IMP NOTE
|
||||
|
||||
@@ -54,8 +54,10 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
||||
delivery_note, d.income_account, d.cost_center, d.stock_qty, d.stock_uom
|
||||
]
|
||||
|
||||
row += [(d.base_net_rate * d.qty)/d.stock_qty, d.base_net_amount] \
|
||||
if d.stock_uom != d.uom and d.stock_qty != 0 else [d.base_net_rate, d.base_net_amount]
|
||||
if d.stock_uom != d.uom and d.stock_qty:
|
||||
row += [(d.base_net_rate * d.qty)/d.stock_qty, d.base_net_amount]
|
||||
else:
|
||||
row += [d.base_net_rate, d.base_net_amount]
|
||||
|
||||
total_tax = 0
|
||||
for tax in tax_columns:
|
||||
@@ -108,13 +110,13 @@ def get_conditions(filters):
|
||||
conditions += """ and exists(select name from `tabSales Invoice Payment`
|
||||
where parent=`tabSales Invoice`.name
|
||||
and ifnull(`tabSales Invoice Payment`.mode_of_payment, '') = %(mode_of_payment)s)"""
|
||||
|
||||
|
||||
if filters.get("warehouse"):
|
||||
conditions += """ and exists(select name from `tabSales Invoice Item`
|
||||
where parent=`tabSales Invoice`.name
|
||||
and ifnull(`tabSales Invoice Item`.warehouse, '') = %(warehouse)s)"""
|
||||
|
||||
|
||||
|
||||
if filters.get("brand"):
|
||||
conditions += """ and exists(select name from `tabSales Invoice Item`
|
||||
where parent=`tabSales Invoice`.name
|
||||
@@ -131,10 +133,10 @@ def get_conditions(filters):
|
||||
def get_items(filters, additional_query_columns):
|
||||
conditions = get_conditions(filters)
|
||||
match_conditions = frappe.build_match_conditions("Sales Invoice")
|
||||
|
||||
|
||||
if match_conditions:
|
||||
match_conditions = " and {0} ".format(match_conditions)
|
||||
|
||||
|
||||
if additional_query_columns:
|
||||
additional_query_columns = ', ' + ', '.join(additional_query_columns)
|
||||
|
||||
|
||||
@@ -133,6 +133,13 @@ def get_columns(filters):
|
||||
"options": filters.get("based_on"),
|
||||
"width": 300
|
||||
},
|
||||
{
|
||||
"fieldname": "currency",
|
||||
"label": _("Currency"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Currency",
|
||||
"hidden": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "income",
|
||||
"label": _("Income"),
|
||||
@@ -153,13 +160,6 @@ def get_columns(filters):
|
||||
"fieldtype": "Currency",
|
||||
"options": "currency",
|
||||
"width": 120
|
||||
},
|
||||
{
|
||||
"fieldname": "currency",
|
||||
"label": _("Currency"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Currency",
|
||||
"hidden": 1
|
||||
}
|
||||
]
|
||||
|
||||
@@ -191,4 +191,4 @@ def set_gl_entries_by_account(company, from_date, to_date, based_on, gl_entries_
|
||||
for entry in gl_entries:
|
||||
gl_entries_by_account.setdefault(entry.based_on, []).append(entry)
|
||||
|
||||
return gl_entries_by_account
|
||||
return gl_entries_by_account
|
||||
|
||||
@@ -66,8 +66,8 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
||||
total_tax += tax_amount
|
||||
row.append(tax_amount)
|
||||
|
||||
# total tax, grand total, outstanding amount & rounded total
|
||||
row += [total_tax, inv.base_grand_total, flt(inv.base_grand_total, 2), inv.outstanding_amount]
|
||||
# total tax, grand total, rounded total & outstanding amount
|
||||
row += [total_tax, inv.base_grand_total, flt(inv.base_grand_total, 0), inv.outstanding_amount]
|
||||
data.append(row)
|
||||
|
||||
return columns, data
|
||||
|
||||
@@ -35,9 +35,9 @@ frappe.query_reports["Supplier Ledger Summary"] = {
|
||||
},
|
||||
{
|
||||
"fieldname":"party",
|
||||
"label": __("Customer"),
|
||||
"label": __("Supplier"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Customer",
|
||||
"options": "Supplier",
|
||||
on_change: () => {
|
||||
var party = frappe.query_report.get_filter_value('party');
|
||||
if (party) {
|
||||
|
||||
@@ -55,12 +55,15 @@ def get_result(filters):
|
||||
supplier = supplier_map[d]
|
||||
|
||||
tds_doc = tds_docs[supplier.tax_withholding_category]
|
||||
account = [i.account for i in tds_doc.accounts if i.company == filters.company][0]
|
||||
account_list = [i.account for i in tds_doc.accounts if i.company == filters.company]
|
||||
|
||||
if account_list:
|
||||
account = account_list[0]
|
||||
|
||||
for k in gle_map[d]:
|
||||
if k.party == supplier_map[d] and k.credit > 0:
|
||||
total_amount_credited += k.credit
|
||||
elif k.account == account and k.credit > 0:
|
||||
elif account_list and k.account == account and k.credit > 0:
|
||||
tds_deducted = k.credit
|
||||
total_amount_credited += k.credit
|
||||
|
||||
|
||||
@@ -544,14 +544,14 @@ def fix_total_debit_credit():
|
||||
(dr_or_cr, dr_or_cr, '%s', '%s', '%s', dr_or_cr),
|
||||
(d.diff, d.voucher_type, d.voucher_no))
|
||||
|
||||
def get_stock_and_account_difference(account_list=None, posting_date=None):
|
||||
def get_stock_and_account_difference(account_list=None, posting_date=None, company=None):
|
||||
from erpnext.stock.utils import get_stock_value_on
|
||||
from erpnext.stock import get_warehouse_account_map
|
||||
|
||||
if not posting_date: posting_date = nowdate()
|
||||
|
||||
difference = {}
|
||||
warehouse_account = get_warehouse_account_map()
|
||||
warehouse_account = get_warehouse_account_map(company)
|
||||
|
||||
for warehouse, account_data in iteritems(warehouse_account):
|
||||
if account_data.get('account') in account_list:
|
||||
|
||||
@@ -31,7 +31,7 @@ frappe.ui.form.on('Asset', {
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
frm.set_query("cost_center", function() {
|
||||
return {
|
||||
"filters": {
|
||||
@@ -206,12 +206,10 @@ frappe.ui.form.on('Asset', {
|
||||
erpnext.asset.set_accululated_depreciation(frm);
|
||||
},
|
||||
|
||||
depreciation_method: function(frm) {
|
||||
frm.events.make_schedules_editable(frm);
|
||||
},
|
||||
|
||||
make_schedules_editable: function(frm) {
|
||||
var is_editable = frm.doc.depreciation_method==="Manual" ? true : false;
|
||||
var is_editable = frm.doc.finance_books.filter(d => d.depreciation_method == "Manual").length > 0
|
||||
? true : false;
|
||||
|
||||
frm.toggle_enable("schedules", is_editable);
|
||||
frm.fields_dict["schedules"].grid.toggle_enable("schedule_date", is_editable);
|
||||
frm.fields_dict["schedules"].grid.toggle_enable("depreciation_amount", is_editable);
|
||||
@@ -296,6 +294,44 @@ frappe.ui.form.on('Asset', {
|
||||
})
|
||||
|
||||
frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation);
|
||||
},
|
||||
|
||||
set_depreciation_rate: function(frm, row) {
|
||||
if (row.total_number_of_depreciations && row.frequency_of_depreciation) {
|
||||
frappe.call({
|
||||
method: "get_depreciation_rate",
|
||||
doc: frm.doc,
|
||||
args: row,
|
||||
callback: function(r) {
|
||||
if (r.message) {
|
||||
frappe.model.set_value(row.doctype, row.name, "rate_of_depreciation", r.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
frappe.ui.form.on('Asset Finance Book', {
|
||||
depreciation_method: function(frm, cdt, cdn) {
|
||||
const row = locals[cdt][cdn];
|
||||
frm.events.set_depreciation_rate(frm, row);
|
||||
frm.events.make_schedules_editable(frm);
|
||||
},
|
||||
|
||||
expected_value_after_useful_life: function(frm, cdt, cdn) {
|
||||
const row = locals[cdt][cdn];
|
||||
frm.events.set_depreciation_rate(frm, row);
|
||||
},
|
||||
|
||||
frequency_of_depreciation: function(frm, cdt, cdn) {
|
||||
const row = locals[cdt][cdn];
|
||||
frm.events.set_depreciation_rate(frm, row);
|
||||
},
|
||||
|
||||
total_number_of_depreciations: function(frm, cdt, cdn) {
|
||||
const row = locals[cdt][cdn];
|
||||
frm.events.set_depreciation_rate(frm, row);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe, erpnext
|
||||
import frappe, erpnext, math, json
|
||||
from frappe import _
|
||||
from six import string_types
|
||||
from frappe.utils import flt, add_months, cint, nowdate, getdate, today, date_diff
|
||||
from frappe.model.document import Document
|
||||
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
|
||||
@@ -20,6 +21,7 @@ class Asset(AccountsController):
|
||||
self.validate_item()
|
||||
self.set_missing_values()
|
||||
if self.calculate_depreciation:
|
||||
self.set_depreciation_rate()
|
||||
self.make_depreciation_schedule()
|
||||
self.set_accumulated_depreciation()
|
||||
else:
|
||||
@@ -33,7 +35,7 @@ class Asset(AccountsController):
|
||||
self.validate_in_use_date()
|
||||
self.set_status()
|
||||
self.update_stock_movement()
|
||||
if not self.booked_fixed_asset:
|
||||
if not self.booked_fixed_asset and not is_cwip_accounting_disabled():
|
||||
self.make_gl_entries()
|
||||
|
||||
def on_cancel(self):
|
||||
@@ -71,14 +73,15 @@ class Asset(AccountsController):
|
||||
if not flt(self.gross_purchase_amount):
|
||||
frappe.throw(_("Gross Purchase Amount is mandatory"), frappe.MandatoryError)
|
||||
|
||||
if not self.is_existing_asset and not (self.purchase_receipt or self.purchase_invoice):
|
||||
frappe.throw(_("Please create purchase receipt or purchase invoice for the item {0}").
|
||||
format(self.item_code))
|
||||
if not is_cwip_accounting_disabled():
|
||||
if not self.is_existing_asset and not (self.purchase_receipt or self.purchase_invoice):
|
||||
frappe.throw(_("Please create purchase receipt or purchase invoice for the item {0}").
|
||||
format(self.item_code))
|
||||
|
||||
if (not self.purchase_receipt and self.purchase_invoice
|
||||
and not frappe.db.get_value('Purchase Invoice', self.purchase_invoice, 'update_stock')):
|
||||
frappe.throw(_("Update stock must be enable for the purchase invoice {0}").
|
||||
format(self.purchase_invoice))
|
||||
if (not self.purchase_receipt and self.purchase_invoice
|
||||
and not frappe.db.get_value('Purchase Invoice', self.purchase_invoice, 'update_stock')):
|
||||
frappe.throw(_("Update stock must be enable for the purchase invoice {0}").
|
||||
format(self.purchase_invoice))
|
||||
|
||||
if not self.calculate_depreciation:
|
||||
return
|
||||
@@ -88,17 +91,22 @@ class Asset(AccountsController):
|
||||
if self.is_existing_asset:
|
||||
return
|
||||
|
||||
date = nowdate()
|
||||
docname = self.purchase_receipt or self.purchase_invoice
|
||||
if docname:
|
||||
doctype = 'Purchase Receipt' if self.purchase_receipt else 'Purchase Invoice'
|
||||
date = frappe.db.get_value(doctype, docname, 'posting_date')
|
||||
|
||||
if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(date):
|
||||
if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(self.purchase_date):
|
||||
frappe.throw(_("Available-for-use Date should be after purchase date"))
|
||||
|
||||
def set_depreciation_rate(self):
|
||||
for d in self.get("finance_books"):
|
||||
d.rate_of_depreciation = self.get_depreciation_rate(d)
|
||||
|
||||
def make_depreciation_schedule(self):
|
||||
if self.depreciation_method != 'Manual':
|
||||
depreciation_method = [d.depreciation_method for d in self.finance_books]
|
||||
|
||||
if 'Manual' not in depreciation_method:
|
||||
self.schedules = []
|
||||
|
||||
if not self.get("schedules") and self.available_for_use_date:
|
||||
@@ -253,14 +261,16 @@ class Asset(AccountsController):
|
||||
return flt(self.get('finance_books')[cint(idx)-1].value_after_depreciation)
|
||||
|
||||
def get_depreciation_amount(self, depreciable_value, total_number_of_depreciations, row):
|
||||
percentage_value = 100.0 if row.depreciation_method == 'Written Down Value' else 200.0
|
||||
if row.depreciation_method in ["Straight Line", "Manual"]:
|
||||
amt = (flt(self.gross_purchase_amount) - flt(row.expected_value_after_useful_life) -
|
||||
flt(self.opening_accumulated_depreciation))
|
||||
|
||||
factor = percentage_value / total_number_of_depreciations
|
||||
depreciation_amount = flt(depreciable_value * factor / 100, 0)
|
||||
|
||||
value_after_depreciation = flt(depreciable_value) - depreciation_amount
|
||||
if value_after_depreciation < flt(row.expected_value_after_useful_life):
|
||||
depreciation_amount = flt(depreciable_value) - flt(row.expected_value_after_useful_life)
|
||||
depreciation_amount = amt * row.rate_of_depreciation
|
||||
else:
|
||||
depreciation_amount = flt(depreciable_value) * (flt(row.rate_of_depreciation) / 100)
|
||||
value_after_depreciation = flt(depreciable_value) - depreciation_amount
|
||||
if value_after_depreciation < flt(row.expected_value_after_useful_life):
|
||||
depreciation_amount = flt(depreciable_value) - flt(row.expected_value_after_useful_life)
|
||||
|
||||
return depreciation_amount
|
||||
|
||||
@@ -275,7 +285,7 @@ class Asset(AccountsController):
|
||||
flt(row.expected_value_after_useful_life)) / (cint(row.total_number_of_depreciations) -
|
||||
cint(self.number_of_depreciations_booked)) * prorata_temporis
|
||||
else:
|
||||
depreciation_amount = self.get_depreciation_amount(depreciable_value, row)
|
||||
depreciation_amount = self.get_depreciation_amount(depreciable_value, row.total_number_of_depreciations, row)
|
||||
|
||||
return depreciation_amount
|
||||
|
||||
@@ -393,6 +403,32 @@ class Asset(AccountsController):
|
||||
make_gl_entries(gl_entries)
|
||||
self.db_set('booked_fixed_asset', 1)
|
||||
|
||||
def get_depreciation_rate(self, args):
|
||||
if isinstance(args, string_types):
|
||||
args = json.loads(args)
|
||||
|
||||
number_of_depreciations_booked = 0
|
||||
if self.is_existing_asset:
|
||||
number_of_depreciations_booked = self.number_of_depreciations_booked
|
||||
|
||||
float_precision = cint(frappe.db.get_default("float_precision")) or 2
|
||||
tot_no_of_depreciation = flt(args.get("total_number_of_depreciations")) - flt(number_of_depreciations_booked)
|
||||
|
||||
if args.get("depreciation_method") in ["Straight Line", "Manual"]:
|
||||
return 1.0 / tot_no_of_depreciation
|
||||
|
||||
if args.get("depreciation_method") == 'Double Declining Balance':
|
||||
return 200.0 / args.get("total_number_of_depreciations")
|
||||
|
||||
if args.get("depreciation_method") == "Written Down Value" and not args.get("rate_of_depreciation"):
|
||||
no_of_years = flt(args.get("total_number_of_depreciations") * flt(args.get("frequency_of_depreciation"))) / 12
|
||||
value = flt(args.get("expected_value_after_useful_life")) / flt(self.gross_purchase_amount)
|
||||
|
||||
# square root of flt(salvage_value) / flt(asset_cost)
|
||||
depreciation_rate = math.pow(value, 1.0/flt(no_of_years, 2))
|
||||
|
||||
return 100 * (1 - flt(depreciation_rate, float_precision))
|
||||
|
||||
def update_maintenance_status():
|
||||
assets = frappe.get_all('Asset', filters = {'docstatus': 1, 'maintenance_required': 1})
|
||||
|
||||
@@ -404,6 +440,9 @@ def update_maintenance_status():
|
||||
asset.set_status('Out of Order')
|
||||
|
||||
def make_post_gl_entry():
|
||||
if is_cwip_accounting_disabled():
|
||||
return
|
||||
|
||||
assets = frappe.db.sql_list(""" select name from `tabAsset`
|
||||
where ifnull(booked_fixed_asset, 0) = 0 and available_for_use_date = %s""", nowdate())
|
||||
|
||||
@@ -476,7 +515,6 @@ def create_asset_adjustment(asset, asset_category, company):
|
||||
|
||||
@frappe.whitelist()
|
||||
def transfer_asset(args):
|
||||
import json
|
||||
args = json.loads(args)
|
||||
|
||||
if args.get('serial_no'):
|
||||
@@ -551,3 +589,6 @@ def make_journal_entry(asset_name):
|
||||
})
|
||||
|
||||
return je
|
||||
|
||||
def is_cwip_accounting_disabled():
|
||||
return cint(frappe.db.get_single_value("Asset Settings", "disable_cwip_accounting"))
|
||||
|
||||
@@ -160,9 +160,9 @@ class TestAsset(unittest.TestCase):
|
||||
asset.save()
|
||||
|
||||
expected_schedules = [
|
||||
["2020-06-06", 66667.0, 66667.0],
|
||||
["2021-04-06", 22222.0, 88889.0],
|
||||
["2022-02-06", 1111.0, 90000.0]
|
||||
["2020-06-06", 66666.67, 66666.67],
|
||||
["2021-04-06", 22222.22, 88888.89],
|
||||
["2022-02-06", 1111.11, 90000.0]
|
||||
]
|
||||
|
||||
schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
|
||||
@@ -192,8 +192,8 @@ class TestAsset(unittest.TestCase):
|
||||
asset.save()
|
||||
|
||||
expected_schedules = [
|
||||
["2020-06-06", 33333.0, 83333.0],
|
||||
["2021-04-06", 6667.0, 90000.0]
|
||||
["2020-06-06", 33333.33, 83333.33],
|
||||
["2021-04-06", 6666.67, 90000.0]
|
||||
]
|
||||
|
||||
schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
|
||||
@@ -209,7 +209,7 @@ class TestAsset(unittest.TestCase):
|
||||
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
|
||||
asset = frappe.get_doc('Asset', asset_name)
|
||||
asset.calculate_depreciation = 1
|
||||
asset.purchase_date = '2020-06-06'
|
||||
asset.purchase_date = '2020-01-30'
|
||||
asset.is_existing_asset = 0
|
||||
asset.available_for_use_date = "2020-01-30"
|
||||
asset.append("finance_books", {
|
||||
@@ -244,7 +244,7 @@ class TestAsset(unittest.TestCase):
|
||||
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
|
||||
asset = frappe.get_doc('Asset', asset_name)
|
||||
asset.calculate_depreciation = 1
|
||||
asset.purchase_date = '2020-06-06'
|
||||
asset.purchase_date = '2020-01-30'
|
||||
asset.available_for_use_date = "2020-01-30"
|
||||
asset.append("finance_books", {
|
||||
"expected_value_after_useful_life": 10000,
|
||||
@@ -277,6 +277,37 @@ class TestAsset(unittest.TestCase):
|
||||
self.assertEqual(gle, expected_gle)
|
||||
self.assertEqual(asset.get("value_after_depreciation"), 0)
|
||||
|
||||
def test_depreciation_entry_for_wdv(self):
|
||||
pr = make_purchase_receipt(item_code="Macbook Pro",
|
||||
qty=1, rate=8000.0, location="Test Location")
|
||||
|
||||
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
|
||||
asset = frappe.get_doc('Asset', asset_name)
|
||||
asset.calculate_depreciation = 1
|
||||
asset.available_for_use_date = '2030-06-06'
|
||||
asset.purchase_date = '2030-06-06'
|
||||
asset.append("finance_books", {
|
||||
"expected_value_after_useful_life": 1000,
|
||||
"depreciation_method": "Written Down Value",
|
||||
"total_number_of_depreciations": 3,
|
||||
"frequency_of_depreciation": 12,
|
||||
"depreciation_start_date": "2030-12-31"
|
||||
})
|
||||
asset.save(ignore_permissions=True)
|
||||
|
||||
self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0)
|
||||
|
||||
expected_schedules = [
|
||||
["2030-12-31", 4000.0, 4000.0],
|
||||
["2031-12-31", 2000.0, 6000.0],
|
||||
["2032-12-31", 1000.0, 7000.0],
|
||||
]
|
||||
|
||||
schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)]
|
||||
for d in asset.get("schedules")]
|
||||
|
||||
self.assertEqual(schedules, expected_schedules)
|
||||
|
||||
def test_depreciation_entry_cancellation(self):
|
||||
pr = make_purchase_receipt(item_code="Macbook Pro",
|
||||
qty=1, rate=100000.0, location="Test Location")
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
@@ -14,11 +15,13 @@
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "finance_book",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -42,14 +45,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "depreciation_method",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
@@ -73,14 +79,17 @@
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "total_number_of_depreciations",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
@@ -103,14 +112,17 @@
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_5",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@@ -133,14 +145,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "frequency_of_depreciation",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
@@ -163,15 +178,18 @@
|
||||
"reqd": 1,
|
||||
"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": "eval:parent.doctype == 'Asset'",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "depreciation_start_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
@@ -194,16 +212,19 @@
|
||||
"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": "0",
|
||||
"depends_on": "eval:parent.doctype == 'Asset'",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "expected_value_after_useful_life",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
@@ -227,14 +248,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "value_after_depreciation",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 1,
|
||||
@@ -258,20 +282,54 @@
|
||||
"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": "eval:doc.depreciation_method == 'Written Down Value'",
|
||||
"description": "In Percentage",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "rate_of_depreciation",
|
||||
"fieldtype": "Percent",
|
||||
"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": "Rate of Depreciation",
|
||||
"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
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-05-12 14:56:44.800046",
|
||||
"modified": "2019-04-09 19:45:14.523488",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Asset Finance Book",
|
||||
@@ -280,10 +338,10 @@
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
@@ -14,10 +15,12 @@
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "depreciation_options",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@@ -40,14 +43,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "schedule_based_on_fiscal_year",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@@ -70,10 +76,12 @@
|
||||
"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,
|
||||
@@ -81,6 +89,7 @@
|
||||
"default": "360",
|
||||
"depends_on": "eval:doc.schedule_based_on_fiscal_year",
|
||||
"description": "This value is used for pro-rata temporis calculation",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "number_of_days_in_fiscal_year",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
@@ -103,6 +112,40 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "disable_cwip_accounting",
|
||||
"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": "Disable CWIP Accounting",
|
||||
"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
|
||||
}
|
||||
],
|
||||
@@ -116,7 +159,7 @@
|
||||
"issingle": 1,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-01-05 10:10:39.803255",
|
||||
"modified": "2019-03-08 10:44:41.924547",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Asset Settings",
|
||||
@@ -125,7 +168,6 @@
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
@@ -145,7 +187,6 @@
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
@@ -171,5 +212,6 @@
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
@@ -379,7 +379,9 @@ def make_purchase_invoice(source_name, target_doc=None):
|
||||
def postprocess(source, target):
|
||||
set_missing_values(source, target)
|
||||
#Get the advance paid Journal Entries in Purchase Invoice Advance
|
||||
target.set_advances()
|
||||
|
||||
if target.get("allocate_advances_automatically"):
|
||||
target.set_advances()
|
||||
|
||||
def update_item(obj, target, source_parent):
|
||||
target.amount = flt(obj.amount) - flt(obj.billed_amt)
|
||||
@@ -388,9 +390,10 @@ def make_purchase_invoice(source_name, target_doc=None):
|
||||
|
||||
item = get_item_defaults(target.item_code, source_parent.company)
|
||||
item_group = get_item_group_defaults(target.item_code, source_parent.company)
|
||||
target.cost_center = frappe.db.get_value("Project", obj.project, "cost_center") \
|
||||
or item.get("buying_cost_center") \
|
||||
or item_group.get("buying_cost_center")
|
||||
target.cost_center = (obj.cost_center
|
||||
or frappe.db.get_value("Project", obj.project, "cost_center")
|
||||
or item.get("buying_cost_center")
|
||||
or item_group.get("buying_cost_center"))
|
||||
|
||||
doc = get_mapped_doc("Purchase Order", source_name, {
|
||||
"Purchase Order": {
|
||||
|
||||
@@ -325,7 +325,7 @@ def get_data():
|
||||
{
|
||||
"type": "help",
|
||||
"label": _("Sales Order to Payment"),
|
||||
"youtube_id": "7AMq4lqkN4A"
|
||||
"youtube_id": "1eP90MWoDQM"
|
||||
},
|
||||
{
|
||||
"type": "help",
|
||||
|
||||
@@ -116,6 +116,12 @@ class AccountsController(TransactionBase):
|
||||
self.validate_non_invoice_documents_schedule()
|
||||
|
||||
def before_print(self):
|
||||
if self.doctype in ['Journal Entry', 'Payment Entry', 'Sales Invoice', 'Purchase Invoice']:
|
||||
self.gl_entries = frappe.get_list("GL Entry", filters={
|
||||
"voucher_type": self.doctype,
|
||||
"voucher_no": self.name
|
||||
}, fields=["account", "party_type", "party", "debit", "credit", "remarks"])
|
||||
|
||||
if self.doctype in ['Purchase Order', 'Sales Order', 'Sales Invoice', 'Purchase Invoice',
|
||||
'Supplier Quotation', 'Purchase Receipt', 'Delivery Note', 'Quotation']:
|
||||
if self.get("group_same_items"):
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import frappe, erpnext
|
||||
from frappe import _
|
||||
from frappe.model.meta import get_field_precision
|
||||
from frappe.utils import flt, get_datetime, format_datetime
|
||||
|
||||
class StockOverReturnError(frappe.ValidationError): pass
|
||||
@@ -116,6 +117,10 @@ def validate_quantity(doc, args, ref, valid_items, already_returned_items):
|
||||
|
||||
already_returned_data = already_returned_items.get(args.item_code) or {}
|
||||
|
||||
company_currency = erpnext.get_company_currency(doc.company)
|
||||
stock_qty_precision = get_field_precision(frappe.get_meta(doc.doctype + " Item")
|
||||
.get_field("stock_qty"), company_currency)
|
||||
|
||||
for column in fields:
|
||||
returned_qty = flt(already_returned_data.get(column, 0)) if len(already_returned_data) > 0 else 0
|
||||
|
||||
@@ -126,7 +131,7 @@ def validate_quantity(doc, args, ref, valid_items, already_returned_items):
|
||||
reference_qty = ref.get(column) * ref.get("conversion_factor", 1.0)
|
||||
current_stock_qty = args.get(column) * args.get("conversion_factor", 1.0)
|
||||
|
||||
max_returnable_qty = flt(reference_qty) - returned_qty
|
||||
max_returnable_qty = flt(reference_qty, stock_qty_precision) - returned_qty
|
||||
label = column.replace('_', ' ').title()
|
||||
|
||||
if reference_qty:
|
||||
@@ -135,7 +140,7 @@ def validate_quantity(doc, args, ref, valid_items, already_returned_items):
|
||||
elif returned_qty >= reference_qty and args.get(column):
|
||||
frappe.throw(_("Item {0} has already been returned")
|
||||
.format(args.item_code), StockOverReturnError)
|
||||
elif abs(current_stock_qty) > max_returnable_qty:
|
||||
elif abs(flt(current_stock_qty, stock_qty_precision)) > max_returnable_qty:
|
||||
frappe.throw(_("Row # {0}: Cannot return more than {1} for Item {2}")
|
||||
.format(args.idx, max_returnable_qty, args.item_code), StockOverReturnError)
|
||||
|
||||
@@ -239,6 +244,10 @@ def make_return_doc(doctype, source_name, target_doc=None):
|
||||
doc.paid_amount = -1 * source.paid_amount
|
||||
doc.base_paid_amount = -1 * source.base_paid_amount
|
||||
|
||||
if doc.get("is_return") and hasattr(doc, "packed_items"):
|
||||
for d in doc.get("packed_items"):
|
||||
d.qty = d.qty * -1
|
||||
|
||||
doc.discount_amount = -1 * source.discount_amount
|
||||
doc.run_method("calculate_taxes_and_totals")
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ class StockController(AccountsController):
|
||||
delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
||||
|
||||
if cint(erpnext.is_perpetual_inventory_enabled(self.company)):
|
||||
warehouse_account = get_warehouse_account_map()
|
||||
warehouse_account = get_warehouse_account_map(self.company)
|
||||
|
||||
if self.docstatus==1:
|
||||
if not gl_entries:
|
||||
@@ -36,7 +36,7 @@ class StockController(AccountsController):
|
||||
if repost_future_gle:
|
||||
items, warehouses = self.get_items_and_warehouses()
|
||||
update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items,
|
||||
warehouse_account)
|
||||
warehouse_account, company=self.company)
|
||||
elif self.doctype in ['Purchase Receipt', 'Purchase Invoice'] and self.docstatus == 1:
|
||||
gl_entries = []
|
||||
gl_entries = self.get_asset_gl_entry(gl_entries)
|
||||
@@ -46,7 +46,7 @@ class StockController(AccountsController):
|
||||
default_cost_center=None):
|
||||
|
||||
if not warehouse_account:
|
||||
warehouse_account = get_warehouse_account_map()
|
||||
warehouse_account = get_warehouse_account_map(self.company)
|
||||
|
||||
sle_map = self.get_stock_ledger_details()
|
||||
voucher_details = self.get_voucher_details(default_expense_account, default_cost_center, sle_map)
|
||||
@@ -199,7 +199,8 @@ class StockController(AccountsController):
|
||||
def make_adjustment_entry(self, expected_gle, voucher_obj):
|
||||
from erpnext.accounts.utils import get_stock_and_account_difference
|
||||
account_list = [d.account for d in expected_gle]
|
||||
acc_diff = get_stock_and_account_difference(account_list, expected_gle[0].posting_date)
|
||||
acc_diff = get_stock_and_account_difference(account_list,
|
||||
expected_gle[0].posting_date, self.company)
|
||||
|
||||
cost_center = self.get_company_default("cost_center")
|
||||
stock_adjustment_account = self.get_company_default("stock_adjustment_account")
|
||||
@@ -361,13 +362,13 @@ class StockController(AccountsController):
|
||||
frappe.get_doc("Blanket Order", blanket_order).update_ordered_qty()
|
||||
|
||||
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
|
||||
warehouse_account=None):
|
||||
warehouse_account=None, company=None):
|
||||
def _delete_gl_entries(voucher_type, voucher_no):
|
||||
frappe.db.sql("""delete from `tabGL Entry`
|
||||
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
|
||||
|
||||
if not warehouse_account:
|
||||
warehouse_account = get_warehouse_account_map()
|
||||
warehouse_account = get_warehouse_account_map(company)
|
||||
|
||||
future_stock_vouchers = get_future_stock_vouchers(posting_date, posting_time, for_warehouses, for_items)
|
||||
gle = get_voucherwise_gl_entries(future_stock_vouchers, posting_date)
|
||||
|
||||
@@ -42,10 +42,10 @@ def create_variant_with_tables(item, args):
|
||||
return variant
|
||||
|
||||
def make_item_variant():
|
||||
frappe.delete_doc_if_exists("Item", "_Test Variant Item-S", force=1)
|
||||
variant = create_variant_with_tables("_Test Variant Item", '{"Test Size": "Small"}')
|
||||
variant.item_code = "_Test Variant Item-S"
|
||||
variant.item_name = "_Test Variant Item-S"
|
||||
frappe.delete_doc_if_exists("Item", "_Test Variant Item-XSL", force=1)
|
||||
variant = create_variant_with_tables("_Test Variant Item", '{"Test Size": "Extra Small"}')
|
||||
variant.item_code = "_Test Variant Item-XSL"
|
||||
variant.item_name = "_Test Variant Item-XSL"
|
||||
variant.save()
|
||||
return variant
|
||||
|
||||
|
||||
@@ -162,6 +162,8 @@ def create_item_code(amazon_item_json, sku):
|
||||
igroup.parent_item_group = mws_settings.item_group
|
||||
igroup.insert()
|
||||
|
||||
item.append("item_defaults", {'company':mws_settings.company})
|
||||
|
||||
item.insert(ignore_permissions=True)
|
||||
create_item_price(amazon_item_json, item.item_code)
|
||||
|
||||
@@ -213,7 +215,7 @@ def get_orders(after_date):
|
||||
fulfillment_channels=["MFN", "AFN"],
|
||||
lastupdatedafter=after_date,
|
||||
orderstatus=statuses,
|
||||
max_results='20')
|
||||
max_results='50')
|
||||
|
||||
while True:
|
||||
orders_list = []
|
||||
@@ -432,8 +434,8 @@ def get_order_items(market_place_order_id):
|
||||
return final_order_items
|
||||
|
||||
def get_item_code(order_item):
|
||||
asin = order_item.ASIN
|
||||
item_code = frappe.db.get_value("Item", {"amazon_item_code": asin}, "item_code")
|
||||
sku = order_item.SellerSKU
|
||||
item_code = frappe.db.get_value("Item", {"item_code": sku}, "item_code")
|
||||
if item_code:
|
||||
return item_code
|
||||
|
||||
@@ -451,11 +453,16 @@ def get_charges_and_fees(market_place_order_id):
|
||||
shipment_item_list = return_as_list(shipment_event.ShipmentEvent.ShipmentItemList.ShipmentItem)
|
||||
|
||||
for shipment_item in shipment_item_list:
|
||||
charges = return_as_list(shipment_item.ItemChargeList.ChargeComponent)
|
||||
fees = return_as_list(shipment_item.ItemFeeList.FeeComponent)
|
||||
charges, fees = []
|
||||
|
||||
if 'ItemChargeList' in shipment_item.keys():
|
||||
charges = return_as_list(shipment_item.ItemChargeList.ChargeComponent)
|
||||
|
||||
if 'ItemFeeList' in shipment_item.keys():
|
||||
fees = return_as_list(shipment_item.ItemFeeList.FeeComponent)
|
||||
|
||||
for charge in charges:
|
||||
if(charge.ChargeType != "Principal"):
|
||||
if(charge.ChargeType != "Principal") and float(charge.ChargeAmount.CurrencyAmount) != 0:
|
||||
charge_account = get_account(charge.ChargeType)
|
||||
charges_fees.get("charges").append({
|
||||
"charge_type":"Actual",
|
||||
@@ -465,13 +472,14 @@ def get_charges_and_fees(market_place_order_id):
|
||||
})
|
||||
|
||||
for fee in fees:
|
||||
fee_account = get_account(fee.FeeType)
|
||||
charges_fees.get("fees").append({
|
||||
"charge_type":"Actual",
|
||||
"account_head": fee_account,
|
||||
"tax_amount": fee.FeeAmount.CurrencyAmount,
|
||||
"description": fee.FeeType + " for " + shipment_item.SellerSKU
|
||||
})
|
||||
if float(fee.FeeAmount.CurrencyAmount) != 0:
|
||||
fee_account = get_account(fee.FeeType)
|
||||
charges_fees.get("fees").append({
|
||||
"charge_type":"Actual",
|
||||
"account_head": fee_account,
|
||||
"tax_amount": fee.FeeAmount.CurrencyAmount,
|
||||
"description": fee.FeeType + " for " + shipment_item.SellerSKU
|
||||
})
|
||||
|
||||
return charges_fees
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ class WoocommerceSettings(Document):
|
||||
if not frappe.get_value("Item Group",{"name": "WooCommerce Products"}):
|
||||
item_group = frappe.new_doc("Item Group")
|
||||
item_group.item_group_name = "WooCommerce Products"
|
||||
item_group.parent_item_group = "All Item Groups"
|
||||
item_group.parent_item_group = _("All Item Groups")
|
||||
item_group.save()
|
||||
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ frappe.ui.form.on('Healthcare Service Unit Type', {
|
||||
var disable = function(frm){
|
||||
var doc = frm.doc;
|
||||
frappe.call({
|
||||
method: "erpnext.healthcare.doctype.healthcare_service_unit_type.healthcare_service_unit_type.disable_enable",
|
||||
method: "erpnext.healthcare.doctype.healthcare_service_unit_type.healthcare_service_unit_type.disable_enable",
|
||||
args: {status: 1, doc_name: doc.name, item: doc.item, is_billable: doc.is_billable},
|
||||
callback: function(){
|
||||
cur_frm.reload_doc();
|
||||
@@ -60,7 +60,7 @@ var disable = function(frm){
|
||||
var enable = function(frm){
|
||||
var doc = frm.doc;
|
||||
frappe.call({
|
||||
method: "erpnext.healthcare.doctype.healthcare_service_unit_type.healthcare_service_unit_type.disable_enable",
|
||||
method: "erpnext.healthcare.doctype.healthcare_service_unit_type.healthcare_service_unit_type.disable_enable",
|
||||
args: {status: 0, doc_name: doc.name, item: doc.item, is_billable: doc.is_billable},
|
||||
callback: function(){
|
||||
cur_frm.reload_doc();
|
||||
|
||||
@@ -111,7 +111,7 @@ def change_item_code(item, item_code, doc_name):
|
||||
frappe.db.set_value("Healthcare Service Unit Type", doc_name, "item_code", item_code)
|
||||
|
||||
@frappe.whitelist()
|
||||
def disable_enable(status, doc_name, item, is_billable):
|
||||
def disable_enable(status, doc_name, item=None, is_billable=None):
|
||||
frappe.db.set_value("Healthcare Service Unit Type", doc_name, "disabled", status)
|
||||
if(is_billable == 1):
|
||||
frappe.db.set_value("Item", item, "disabled", status)
|
||||
|
||||
@@ -19,8 +19,6 @@ class AdditionalSalary(Document):
|
||||
["date_of_joining", "relieving_date"])
|
||||
if date_of_joining and getdate(self.payroll_date) < getdate(date_of_joining):
|
||||
frappe.throw(_("Payroll date can not be less than employee's joining date"))
|
||||
elif relieving_date and getdate(self.payroll_date) > getdate(relieving_date):
|
||||
frappe.throw(_("To date can not greater than employee's relieving date"))
|
||||
|
||||
def get_amount(self, sal_start_date, sal_end_date):
|
||||
start_date = getdate(sal_start_date)
|
||||
|
||||
@@ -399,6 +399,19 @@ def get_leave_balance_on(employee, leave_type, date, allocation_records=None, do
|
||||
|
||||
return flt(allocation.total_leaves_allocated) - (flt(leaves_taken) + flt(leaves_encashed))
|
||||
|
||||
def get_total_allocated_leaves(employee, leave_type, date):
|
||||
filters= {
|
||||
'from_date': ['<=', date],
|
||||
'to_date': ['>=', date],
|
||||
'docstatus': 1,
|
||||
'leave_type': leave_type,
|
||||
'employee': employee
|
||||
}
|
||||
|
||||
leave_allocation_records = frappe.db.get_all('Leave Allocation', filters=filters, fields=['total_leaves_allocated'])
|
||||
|
||||
return flt(leave_allocation_records[0]['total_leaves_allocated']) if leave_allocation_records else flt(0)
|
||||
|
||||
def get_leaves_for_period(employee, leave_type, from_date, to_date, status, docname=None):
|
||||
leave_applications = frappe.db.sql("""
|
||||
select name, employee, leave_type, from_date, to_date, total_leave_days
|
||||
@@ -499,14 +512,12 @@ def add_department_leaves(events, start, end, employee, company):
|
||||
department_employees = frappe.db.sql_list("""select name from tabEmployee where department=%s
|
||||
and company=%s""", (department, company))
|
||||
|
||||
filter_conditions = "employee in (\"%s\")" % '", "'.join(department_employees)
|
||||
filter_conditions = " and employee in (\"%s\")" % '", "'.join(department_employees)
|
||||
add_leaves(events, start, end, filter_conditions=filter_conditions)
|
||||
|
||||
def add_leaves(events, start, end, filter_conditions=None):
|
||||
conditions = []
|
||||
|
||||
if filter_conditions:
|
||||
conditions.append(filter_conditions)
|
||||
|
||||
if not cint(frappe.db.get_value("HR Settings", None, "show_leaves_of_all_department_members_in_calendar")):
|
||||
from frappe.desk.reportview import build_match_conditions
|
||||
@@ -520,11 +531,14 @@ def add_leaves(events, start, end, filter_conditions=None):
|
||||
from `tabLeave Application` where
|
||||
from_date <= %(end)s and to_date >= %(start)s <= to_date
|
||||
and docstatus < 2
|
||||
and status!="Rejected" """
|
||||
and status!='Rejected' """
|
||||
|
||||
if conditions:
|
||||
query += ' and ' + ' and '.join(conditions)
|
||||
|
||||
if filter_conditions:
|
||||
query += filter_conditions
|
||||
|
||||
for d in frappe.db.sql(query, {"start":start, "end": end}, as_dict=True):
|
||||
e = {
|
||||
"name": d.name,
|
||||
|
||||
@@ -441,7 +441,7 @@ class SalarySlip(TransactionBase):
|
||||
def calculate_net_pay(self):
|
||||
if self.salary_structure:
|
||||
self.calculate_component_amounts()
|
||||
|
||||
|
||||
disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, "disable_rounded_total"))
|
||||
precision = frappe.defaults.get_global_default("currency_precision")
|
||||
self.total_deduction = 0
|
||||
@@ -452,10 +452,10 @@ class SalarySlip(TransactionBase):
|
||||
|
||||
self.set_loan_repayment()
|
||||
|
||||
self.net_pay = flt(self.gross_pay) - (flt(self.total_deduction) + flt(self.total_loan_repayment))
|
||||
self.net_pay = (flt(self.gross_pay) - (flt(self.total_deduction) + flt(self.total_loan_repayment))) * flt(self.payment_days / self.total_working_days)
|
||||
self.rounded_total = rounded(self.net_pay,
|
||||
self.precision("net_pay") if disable_rounded_total else 0)
|
||||
|
||||
|
||||
if self.net_pay < 0:
|
||||
frappe.throw(_("Net Pay cannnot be negative"))
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ class StaffingPlan(Document):
|
||||
self.total_estimated_budget = 0
|
||||
|
||||
for detail in self.get("staffing_details"):
|
||||
self.set_vacancies(detail)
|
||||
self.validate_overlap(detail)
|
||||
self.validate_with_subsidiary_plans(detail)
|
||||
self.validate_with_parent_plan(detail)
|
||||
@@ -39,6 +40,15 @@ class StaffingPlan(Document):
|
||||
else: detail.vacancies = detail.number_of_positions = detail.total_estimated_cost = 0
|
||||
self.total_estimated_budget += detail.total_estimated_cost
|
||||
|
||||
def set_vacancies(self, row):
|
||||
if not row.vacancies:
|
||||
current_openings = 0
|
||||
for field in ['current_count', 'current_openings']:
|
||||
if row.get(field):
|
||||
current_openings += row.get(field)
|
||||
|
||||
row.vacancies = row.number_of_positions - current_openings
|
||||
|
||||
def validate_overlap(self, staffing_plan_detail):
|
||||
# Validate if any submitted Staffing Plan exist for any Designations in this plan
|
||||
# and spd.vacancies>0 ?
|
||||
|
||||
@@ -18,7 +18,7 @@ class TestStaffingPlan(unittest.TestCase):
|
||||
if frappe.db.exists("Staffing Plan", "Test"):
|
||||
return
|
||||
staffing_plan = frappe.new_doc("Staffing Plan")
|
||||
staffing_plan.company = "_Test Company 3"
|
||||
staffing_plan.company = "_Test Company 10"
|
||||
staffing_plan.name = "Test"
|
||||
staffing_plan.from_date = nowdate()
|
||||
staffing_plan.to_date = add_days(nowdate(), 10)
|
||||
@@ -67,7 +67,7 @@ class TestStaffingPlan(unittest.TestCase):
|
||||
if frappe.db.exists("Staffing Plan", "Test 1"):
|
||||
return
|
||||
staffing_plan = frappe.new_doc("Staffing Plan")
|
||||
staffing_plan.company = "_Test Company 3"
|
||||
staffing_plan.company = "_Test Company 10"
|
||||
staffing_plan.name = "Test 1"
|
||||
staffing_plan.from_date = nowdate()
|
||||
staffing_plan.to_date = add_days(nowdate(), 10)
|
||||
@@ -85,11 +85,11 @@ def _set_up():
|
||||
make_company()
|
||||
|
||||
def make_company():
|
||||
if frappe.db.exists("Company", "_Test Company 3"):
|
||||
if frappe.db.exists("Company", "_Test Company 10"):
|
||||
return
|
||||
company = frappe.new_doc("Company")
|
||||
company.company_name = "_Test Company 3"
|
||||
company.abbr = "_TC3"
|
||||
company.company_name = "_Test Company 10"
|
||||
company.abbr = "_TC10"
|
||||
company.parent_company = "_Test Company"
|
||||
company.default_currency = "INR"
|
||||
company.country = "India"
|
||||
|
||||
@@ -15,9 +15,11 @@ class TrainingFeedback(Document):
|
||||
|
||||
def on_submit(self):
|
||||
training_event = frappe.get_doc("Training Event", self.training_event)
|
||||
status = None
|
||||
for e in training_event.employees:
|
||||
if e.employee == self.employee:
|
||||
training_event.status = 'Feedback Submitted'
|
||||
status = 'Feedback Submitted'
|
||||
break
|
||||
|
||||
training_event.save()
|
||||
if status:
|
||||
frappe.db.set_value("Training Event", self.training_event, "status", status)
|
||||
|
||||
@@ -5,21 +5,21 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from erpnext.hr.doctype.leave_application.leave_application \
|
||||
import get_leave_allocation_records, get_leave_balance_on, get_approved_leaves_for_period
|
||||
import get_leave_allocation_records, get_leave_balance_on, get_approved_leaves_for_period, get_total_allocated_leaves
|
||||
|
||||
|
||||
def execute(filters=None):
|
||||
leave_types = frappe.db.sql_list("select name from `tabLeave Type` order by name asc")
|
||||
|
||||
|
||||
columns = get_columns(leave_types)
|
||||
data = get_data(filters, leave_types)
|
||||
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
def get_columns(leave_types):
|
||||
columns = [
|
||||
_("Employee") + ":Link/Employee:150",
|
||||
_("Employee Name") + "::200",
|
||||
_("Employee") + ":Link/Employee:150",
|
||||
_("Employee Name") + "::200",
|
||||
_("Department") +"::150"
|
||||
]
|
||||
|
||||
@@ -27,18 +27,18 @@ def get_columns(leave_types):
|
||||
columns.append(_(leave_type) + " " + _("Opening") + ":Float:160")
|
||||
columns.append(_(leave_type) + " " + _("Taken") + ":Float:160")
|
||||
columns.append(_(leave_type) + " " + _("Balance") + ":Float:160")
|
||||
|
||||
|
||||
return columns
|
||||
|
||||
|
||||
def get_data(filters, leave_types):
|
||||
user = frappe.session.user
|
||||
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)
|
||||
|
||||
active_employees = frappe.get_all("Employee",
|
||||
filters = { "status": "Active", "company": filters.company},
|
||||
active_employees = frappe.get_all("Employee",
|
||||
filters = { "status": "Active", "company": filters.company},
|
||||
fields = ["name", "employee_name", "department", "user_id"])
|
||||
|
||||
|
||||
data = []
|
||||
for employee in active_employees:
|
||||
leave_approvers = get_approvers(employee.department)
|
||||
@@ -51,8 +51,7 @@ def get_data(filters, leave_types):
|
||||
filters.from_date, filters.to_date)
|
||||
|
||||
# opening balance
|
||||
opening = get_leave_balance_on(employee.name, leave_type, filters.from_date,
|
||||
allocation_records_based_on_from_date.get(employee.name, frappe._dict()))
|
||||
opening = get_total_allocated_leaves(employee.name, leave_type, filters.to_date)
|
||||
|
||||
# closing balance
|
||||
closing = get_leave_balance_on(employee.name, leave_type, filters.to_date,
|
||||
@@ -61,7 +60,7 @@ def get_data(filters, leave_types):
|
||||
row += [opening, leaves_taken, closing]
|
||||
|
||||
data.append(row)
|
||||
|
||||
|
||||
return data
|
||||
|
||||
def get_approvers(department):
|
||||
|
||||
@@ -580,7 +580,7 @@ def get_list_context(context):
|
||||
context.title = _("Bill of Materials")
|
||||
# context.introduction = _('Boms')
|
||||
|
||||
def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_items=0, include_non_stock_items=False):
|
||||
def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_items=0, include_non_stock_items=False, fetch_qty_in_stock_uom=True):
|
||||
item_dict = {}
|
||||
|
||||
# Did not use qty_consumed_per_unit in the query, as it leads to rounding loss
|
||||
@@ -588,7 +588,7 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite
|
||||
bom_item.item_code,
|
||||
bom_item.idx,
|
||||
item.item_name,
|
||||
sum(bom_item.stock_qty/ifnull(bom.quantity, 1)) * %(qty)s as qty,
|
||||
sum(bom_item.{qty_field}/ifnull(bom.quantity, 1)) * %(qty)s as qty,
|
||||
item.description,
|
||||
item.image,
|
||||
item.stock_uom,
|
||||
@@ -616,16 +616,18 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite
|
||||
query = query.format(table="BOM Explosion Item",
|
||||
where_conditions="",
|
||||
is_stock_item=is_stock_item,
|
||||
qty_field="stock_qty",
|
||||
select_columns = """, bom_item.source_warehouse, bom_item.operation, bom_item.include_item_in_manufacturing,
|
||||
(Select idx from `tabBOM Item` where item_code = bom_item.item_code and parent = %(parent)s ) as idx""")
|
||||
(Select idx from `tabBOM Item` where item_code = bom_item.item_code and parent = %(parent)s limit 1) as idx""")
|
||||
|
||||
items = frappe.db.sql(query, { "parent": bom, "qty": qty, "bom": bom, "company": company }, as_dict=True)
|
||||
elif fetch_scrap_items:
|
||||
query = query.format(table="BOM Scrap Item", where_conditions="", select_columns=", bom_item.idx", is_stock_item=is_stock_item)
|
||||
query = query.format(table="BOM Scrap Item", where_conditions="", select_columns=", bom_item.idx", is_stock_item=is_stock_item, qty_field="stock_qty")
|
||||
items = frappe.db.sql(query, { "qty": qty, "bom": bom, "company": company }, as_dict=True)
|
||||
else:
|
||||
query = query.format(table="BOM Item", where_conditions="", is_stock_item=is_stock_item,
|
||||
select_columns = ", bom_item.source_warehouse, bom_item.idx, bom_item.operation, bom_item.include_item_in_manufacturing")
|
||||
qty_field="stock_qty" if fetch_qty_in_stock_uom else "qty",
|
||||
select_columns = ", bom_item.uom, bom_item.conversion_factor, bom_item.source_warehouse, bom_item.idx, bom_item.operation, bom_item.include_item_in_manufacturing")
|
||||
items = frappe.db.sql(query, { "qty": qty, "bom": bom, "company": company }, as_dict=True)
|
||||
|
||||
for item in items:
|
||||
|
||||
@@ -18,20 +18,27 @@ frappe.ui.form.on('Job Card', {
|
||||
}
|
||||
|
||||
if (frm.doc.docstatus == 0) {
|
||||
if (!frm.doc.actual_start_date || !frm.doc.actual_end_date) {
|
||||
frm.trigger("make_dashboard");
|
||||
}
|
||||
frm.trigger("make_dashboard");
|
||||
|
||||
if (!frm.doc.actual_start_date) {
|
||||
if (!frm.doc.job_started) {
|
||||
frm.add_custom_button(__("Start Job"), () => {
|
||||
frm.set_value('actual_start_date', frappe.datetime.now_datetime());
|
||||
let row = frappe.model.add_child(frm.doc, 'Job Card Time Log', 'time_logs');
|
||||
row.from_time = frappe.datetime.now_datetime();
|
||||
frm.set_value('job_started', 1);
|
||||
frm.set_value('started_time' , row.from_time);
|
||||
frm.save();
|
||||
});
|
||||
} else if (!frm.doc.actual_end_date) {
|
||||
} else {
|
||||
frm.add_custom_button(__("Complete Job"), () => {
|
||||
frm.set_value('actual_end_date', frappe.datetime.now_datetime());
|
||||
frm.save();
|
||||
frm.savesubmit();
|
||||
let completed_time = frappe.datetime.now_datetime();
|
||||
frm.doc.time_logs.forEach(d => {
|
||||
if (d.from_time && !d.to_time) {
|
||||
d.to_time = completed_time;
|
||||
frm.set_value('started_time' , '');
|
||||
frm.set_value('job_started', 0);
|
||||
frm.save();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -53,8 +60,8 @@ frappe.ui.form.on('Job Card', {
|
||||
|
||||
var section = frm.dashboard.add_section(timer);
|
||||
|
||||
if (frm.doc.actual_start_date) {
|
||||
let currentIncrement = moment(frappe.datetime.now_datetime()).diff(moment(frm.doc.actual_start_date),"seconds");
|
||||
if (frm.doc.started_time) {
|
||||
let currentIncrement = moment(frappe.datetime.now_datetime()).diff(moment(frm.doc.started_time),"seconds");
|
||||
initialiseTimer();
|
||||
|
||||
function initialiseTimer() {
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "work_order",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -54,6 +55,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "bom_no",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -87,6 +89,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "workstation",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -120,6 +123,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "operation",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -153,6 +157,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@@ -185,6 +190,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Today",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "posting_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
@@ -217,6 +223,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -250,6 +257,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "for_quantity",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
@@ -282,6 +290,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "wip_warehouse",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -315,6 +324,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "timing_detail",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@@ -347,6 +357,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "employee",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -380,7 +391,74 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "time_in_mins",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "time_logs",
|
||||
"fieldtype": "Table",
|
||||
"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": "Time Logs",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Job Card Time Log",
|
||||
"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,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_13",
|
||||
"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,
|
||||
"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,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "total_completed_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
@@ -389,7 +467,7 @@
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Time In Mins",
|
||||
"label": "Total Completed Qty",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
@@ -412,7 +490,8 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_13",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_15",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
@@ -443,8 +522,9 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "actual_start_date",
|
||||
"fieldtype": "Datetime",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "total_time_in_mins",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -452,46 +532,14 @@
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Actual Start Date",
|
||||
"label": "Total Time in Mins",
|
||||
"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": "actual_end_date",
|
||||
"fieldtype": "Datetime",
|
||||
"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": "Actual End Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
@@ -507,6 +555,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_8",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@@ -539,6 +588,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "items",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
@@ -572,6 +622,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "more_information",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@@ -604,6 +655,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "operation_id",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
@@ -637,6 +689,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "transferred_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
@@ -670,6 +723,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "requested_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
@@ -702,6 +756,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "project",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -735,6 +790,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "remarks",
|
||||
"fieldtype": "Small Text",
|
||||
"hidden": 0,
|
||||
@@ -767,6 +823,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_20",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@@ -799,6 +856,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Open",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
@@ -832,6 +890,73 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "job_started",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 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": "Job Started",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"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": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "started_time",
|
||||
"fieldtype": "Datetime",
|
||||
"hidden": 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": "Started Time",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"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": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -868,7 +993,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-12-13 17:23:57.986381",
|
||||
"modified": "2019-03-10 17:38:37.499871",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Job Card",
|
||||
|
||||
@@ -11,44 +11,56 @@ from frappe.model.document import Document
|
||||
|
||||
class JobCard(Document):
|
||||
def validate(self):
|
||||
self.validate_actual_dates()
|
||||
self.set_time_in_mins()
|
||||
self.validate_time_logs()
|
||||
self.set_status()
|
||||
|
||||
def validate_actual_dates(self):
|
||||
if get_datetime(self.actual_start_date) > get_datetime(self.actual_end_date):
|
||||
frappe.throw(_("Actual start date must be less than actual end date"))
|
||||
def validate_time_logs(self):
|
||||
self.total_completed_qty = 0.0
|
||||
self.total_time_in_mins = 0.0
|
||||
|
||||
if not (self.employee and self.actual_start_date and self.actual_end_date):
|
||||
return
|
||||
for d in self.get('time_logs'):
|
||||
if get_datetime(d.from_time) > get_datetime(d.to_time):
|
||||
frappe.throw(_("Row {0}: From time must be less than to time").format(d.idx))
|
||||
|
||||
data = frappe.db.sql(""" select name from `tabJob Card`
|
||||
where
|
||||
((%(actual_start_date)s > actual_start_date and %(actual_start_date)s < actual_end_date) or
|
||||
(%(actual_end_date)s > actual_start_date and %(actual_end_date)s < actual_end_date) or
|
||||
(%(actual_start_date)s <= actual_start_date and %(actual_end_date)s >= actual_end_date)) and
|
||||
name != %(name)s and employee = %(employee)s and docstatus =1
|
||||
""", {
|
||||
'actual_start_date': self.actual_start_date,
|
||||
'actual_end_date': self.actual_end_date,
|
||||
'employee': self.employee,
|
||||
'name': self.name
|
||||
}, as_dict=1)
|
||||
data = self.get_overlap_for(d)
|
||||
if data:
|
||||
frappe.throw(_("Row {0}: From Time and To Time of {1} is overlapping with {2}")
|
||||
.format(d.idx, self.name, data.name))
|
||||
|
||||
if data:
|
||||
frappe.throw(_("Start date and end date is overlapping with the job card <a href='#Form/Job Card/{0}'>{1}</a>")
|
||||
.format(data[0].name, data[0].name))
|
||||
if d.from_time and d.to_time:
|
||||
d.time_in_mins = time_diff_in_hours(d.to_time, d.from_time) * 60
|
||||
self.total_time_in_mins += d.time_in_mins
|
||||
|
||||
def set_time_in_mins(self):
|
||||
if self.actual_start_date and self.actual_end_date:
|
||||
self.time_in_mins = time_diff_in_hours(self.actual_end_date, self.actual_start_date) * 60
|
||||
if d.completed_qty:
|
||||
self.total_completed_qty += d.completed_qty
|
||||
|
||||
def get_overlap_for(self, args):
|
||||
existing = frappe.db.sql("""select jc.name as name from
|
||||
`tabJob Card Time Log` jctl, `tabJob Card` jc where jctl.parent = jc.name and
|
||||
(
|
||||
(%(from_time)s > jctl.from_time and %(from_time)s < jctl.to_time) or
|
||||
(%(to_time)s > jctl.from_time and %(to_time)s < jctl.to_time) or
|
||||
(%(from_time)s <= jctl.from_time and %(to_time)s >= jctl.to_time))
|
||||
and jctl.name!=%(name)s
|
||||
and jc.name!=%(parent)s
|
||||
and jc.docstatus < 2
|
||||
and jc.employee = %(employee)s """,
|
||||
{
|
||||
"from_time": args.from_time,
|
||||
"to_time": args.to_time,
|
||||
"name": args.name or "No Name",
|
||||
"parent": args.parent or "No Name",
|
||||
"employee": self.employee
|
||||
}, as_dict=True)
|
||||
|
||||
return existing[0] if existing else None
|
||||
|
||||
def get_required_items(self):
|
||||
if not self.get('work_order'):
|
||||
return
|
||||
|
||||
doc = frappe.get_doc('Work Order', self.get('work_order'))
|
||||
if doc.transfer_material_against == 'Work Order' and doc.skip_transfer:
|
||||
if doc.transfer_material_against == 'Work Order' or doc.skip_transfer:
|
||||
return
|
||||
|
||||
for d in doc.required_items:
|
||||
@@ -67,36 +79,51 @@ class JobCard(Document):
|
||||
})
|
||||
|
||||
def on_submit(self):
|
||||
self.validate_dates()
|
||||
self.validate_job_card()
|
||||
self.update_work_order()
|
||||
self.set_transferred_qty()
|
||||
|
||||
def validate_dates(self):
|
||||
if not self.actual_start_date and not self.actual_end_date:
|
||||
frappe.throw(_("Actual start date and actual end date is mandatory"))
|
||||
|
||||
def on_cancel(self):
|
||||
self.update_work_order()
|
||||
self.set_transferred_qty()
|
||||
|
||||
def validate_job_card(self):
|
||||
if not self.time_logs:
|
||||
frappe.throw(_("Time logs are required for job card {0}").format(self.name))
|
||||
|
||||
if self.total_completed_qty <= 0.0:
|
||||
frappe.throw(_("Total completed qty must be greater than zero"))
|
||||
|
||||
if self.total_completed_qty > self.for_quantity:
|
||||
frappe.throw(_("Total completed qty can not be greater than for quantity"))
|
||||
|
||||
def update_work_order(self):
|
||||
if not self.work_order:
|
||||
return
|
||||
|
||||
data = frappe.db.get_value("Job Card", {'docstatus': 1, 'operation_id': self.operation_id},
|
||||
['sum(time_in_mins)', 'min(actual_start_date)', 'max(actual_end_date)', 'sum(for_quantity)'])
|
||||
for_quantity, time_in_mins = 0, 0
|
||||
from_time_list, to_time_list = [], []
|
||||
|
||||
if data:
|
||||
time_in_mins, actual_start_date, actual_end_date, for_quantity = data
|
||||
|
||||
for d in frappe.get_all('Job Card',
|
||||
filters = {'docstatus': 1, 'operation_id': self.operation_id}):
|
||||
doc = frappe.get_doc('Job Card', d.name)
|
||||
|
||||
for_quantity += doc.total_completed_qty
|
||||
time_in_mins += doc.total_time_in_mins
|
||||
for time_log in doc.time_logs:
|
||||
from_time_list.append(time_log.from_time)
|
||||
to_time_list.append(time_log.to_time)
|
||||
|
||||
if for_quantity:
|
||||
wo = frappe.get_doc('Work Order', self.work_order)
|
||||
|
||||
for data in wo.operations:
|
||||
if data.name == self.operation_id:
|
||||
data.completed_qty = for_quantity
|
||||
data.actual_operation_time = time_in_mins
|
||||
data.actual_start_time = actual_start_date
|
||||
data.actual_end_time = actual_end_date
|
||||
data.actual_start_time = min(from_time_list)
|
||||
data.actual_end_time = max(to_time_list)
|
||||
|
||||
wo.flags.ignore_validate_update_after_submit = True
|
||||
wo.update_operation_status()
|
||||
@@ -132,9 +159,11 @@ class JobCard(Document):
|
||||
break
|
||||
|
||||
if completed:
|
||||
job_cards = frappe.get_all('Job Card', filters = {'work_order': self.work_order,
|
||||
job_cards = frappe.get_all('Job Card', filters = {'work_order': self.work_order,
|
||||
'docstatus': ('!=', 2)}, fields = 'sum(transferred_qty) as qty', group_by='operation_id')
|
||||
qty = min([d.qty for d in job_cards])
|
||||
|
||||
if job_cards:
|
||||
qty = min([d.qty for d in job_cards])
|
||||
|
||||
doc.db_set('material_transferred_for_manufacturing', qty)
|
||||
|
||||
@@ -147,7 +176,7 @@ class JobCard(Document):
|
||||
2: "Cancelled"
|
||||
}[self.docstatus or 0]
|
||||
|
||||
if self.actual_start_date:
|
||||
if self.time_logs:
|
||||
self.status = 'Work In Progress'
|
||||
|
||||
if (self.docstatus == 1 and
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2019-03-08 23:56:43.187569",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "from_time",
|
||||
"fieldtype": "Datetime",
|
||||
"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": "From Time",
|
||||
"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,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "to_time",
|
||||
"fieldtype": "Datetime",
|
||||
"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": "To Time",
|
||||
"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,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_2",
|
||||
"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,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "time_in_mins",
|
||||
"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": "Time In Mins",
|
||||
"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": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "completed_qty",
|
||||
"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": "Completed Qty",
|
||||
"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": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-03-10 17:08:46.504910",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Job Card Time Log",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "ASC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
|
||||
class JobCardTimeLog(Document):
|
||||
pass
|
||||
@@ -302,6 +302,19 @@ class TestWorkOrder(unittest.TestCase):
|
||||
self.assertEqual(len(ste.additional_costs), 1)
|
||||
self.assertEqual(ste.total_additional_costs, 1000)
|
||||
|
||||
def test_job_card(self):
|
||||
data = frappe.get_cached_value('BOM',
|
||||
{'docstatus': 1, 'with_operations': 1, 'company': '_Test Company'}, ['name', 'item'])
|
||||
|
||||
if data:
|
||||
bom, bom_item = data
|
||||
|
||||
bom_doc = frappe.get_doc('BOM', bom)
|
||||
work_order = make_wo_order_test_record(item=bom_item, qty=1, bom_no=bom)
|
||||
|
||||
job_cards = frappe.get_all('Job Card', filters = {'work_order': work_order})
|
||||
self.assertEqual(len(job_cards), len(bom_doc.operations))
|
||||
|
||||
def test_work_order_with_non_transfer_item(self):
|
||||
items = {'Finished Good Transfer Item': 1, '_Test FG Item': 1, '_Test FG Item 1': 0}
|
||||
for item, allow_transfer in items.items():
|
||||
@@ -346,7 +359,7 @@ def make_wo_order_test_record(**args):
|
||||
|
||||
wo_order = frappe.new_doc("Work Order")
|
||||
wo_order.production_item = args.production_item or args.item or args.item_code or "_Test FG Item"
|
||||
wo_order.bom_no = frappe.db.get_value("BOM", {"item": wo_order.production_item,
|
||||
wo_order.bom_no = args.bom_no or frappe.db.get_value("BOM", {"item": wo_order.production_item,
|
||||
"is_active": 1, "is_default": 1})
|
||||
wo_order.qty = args.qty or 10
|
||||
wo_order.wip_warehouse = args.wip_warehouse or "_Test Warehouse - _TC"
|
||||
|
||||
@@ -571,7 +571,7 @@ execute:frappe.delete_doc_if_exists("Page", "sales-analytics")
|
||||
execute:frappe.delete_doc_if_exists("Page", "purchase-analytics")
|
||||
execute:frappe.delete_doc_if_exists("Page", "stock-analytics")
|
||||
execute:frappe.delete_doc_if_exists("Page", "production-analytics")
|
||||
erpnext.patches.v11_0.ewaybill_fields_gst_india #2018-11-13 #2019-01-09
|
||||
erpnext.patches.v11_0.ewaybill_fields_gst_india #2018-11-13 #2019-01-09 #2019-04-01
|
||||
erpnext.patches.v11_0.drop_column_max_days_allowed
|
||||
erpnext.patches.v11_0.change_healthcare_desktop_icons
|
||||
erpnext.patches.v10_0.update_user_image_in_employee
|
||||
@@ -587,4 +587,6 @@ erpnext.patches.v11_1.setup_guardian_role
|
||||
execute:frappe.delete_doc('DocType', 'Notification Control')
|
||||
erpnext.patches.v11_0.remove_barcodes_field_from_copy_fields_to_variants
|
||||
erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019
|
||||
erpnext.patches.v11_0.make_italian_localization_fields # 01-03-2019
|
||||
erpnext.patches.v11_0.make_italian_localization_fields # 26-03-2019
|
||||
erpnext.patches.v11_1.make_job_card_time_logs
|
||||
erpnext.patches.v11_1.set_variant_based_on
|
||||
@@ -6,7 +6,6 @@ from erpnext.regional.italy.setup import make_custom_fields, setup_report
|
||||
from erpnext.regional.italy import state_codes
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
company = frappe.get_all('Company', filters = {'country': 'Italy'})
|
||||
if not company:
|
||||
@@ -27,4 +26,12 @@ def execute():
|
||||
frappe.db.sql("""
|
||||
UPDATE tabAddress set {condition} country_code = UPPER(ifnull((select code
|
||||
from `tabCountry` where name = `tabAddress`.country), ''))
|
||||
where country_code is null and state_code is null
|
||||
""".format(condition=condition))
|
||||
|
||||
frappe.db.sql("""
|
||||
UPDATE `tabSales Invoice Item` si, `tabSales Order` so
|
||||
set si.customer_po_no = so.po_no, si.customer_po_date = so.po_date
|
||||
WHERE
|
||||
si.sales_order = so.name and so.po_no is not null
|
||||
""")
|
||||
|
||||
29
erpnext/patches/v11_1/make_job_card_time_logs.py
Normal file
29
erpnext/patches/v11_1/make_job_card_time_logs.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# 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
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc('manufacturing', 'doctype', 'job_card_time_log')
|
||||
|
||||
if (frappe.db.table_exists("Job Card")
|
||||
and frappe.get_meta("Job Card").has_field("actual_start_date")):
|
||||
time_logs = []
|
||||
for d in frappe.get_all('Job Card',
|
||||
fields = ["actual_start_date", "actual_end_date", "time_in_mins", "name", "for_quantity"],
|
||||
filters = {'docstatus': ("<", 2)}):
|
||||
if d.actual_start_date:
|
||||
time_logs.append([d.actual_start_date, d.actual_end_date, d.time_in_mins,
|
||||
d.for_quantity, d.name, 'Job Card', 'time_logs', frappe.generate_hash("", 10)])
|
||||
|
||||
if time_logs:
|
||||
frappe.db.sql(""" INSERT INTO
|
||||
`tabJob Card Time Log`
|
||||
(from_time, to_time, time_in_mins, completed_qty, parent, parenttype, parentfield, name)
|
||||
values {values}
|
||||
""".format(values = ','.join(['%s'] * len(time_logs))), tuple(time_logs))
|
||||
|
||||
frappe.reload_doc('manufacturing', 'doctype', 'job_card')
|
||||
frappe.db.sql(""" update `tabJob Card` set total_completed_qty = for_quantity,
|
||||
total_time_in_mins = time_in_mins where docstatus < 2 """)
|
||||
11
erpnext/patches/v11_1/set_variant_based_on.py
Normal file
11
erpnext/patches/v11_1/set_variant_based_on.py
Normal file
@@ -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
|
||||
|
||||
def execute():
|
||||
frappe.db.sql("""update tabItem set variant_based_on = 'Item Attribute'
|
||||
where ifnull(variant_based_on, '') = ''
|
||||
and (has_variants=1 or ifnull(variant_of, '') != '')
|
||||
""")
|
||||
@@ -10,14 +10,15 @@ from erpnext.controllers.stock_controller import update_gl_entries_after
|
||||
def execute():
|
||||
company_list = frappe.db.sql_list("""Select name from tabCompany where enable_perpetual_inventory = 1""")
|
||||
frappe.reload_doc('accounts', 'doctype', 'sales_invoice')
|
||||
|
||||
frappe.reload_doctype("Purchase Invoice")
|
||||
|
||||
frappe.reload_doctype("Purchase Invoice")
|
||||
wh_account = get_warehouse_account_map()
|
||||
|
||||
|
||||
for pi in frappe.get_all("Purchase Invoice", fields=["name", "company"], filters={"docstatus": 1, "update_stock": 1}):
|
||||
if pi.company in company_list:
|
||||
pi_doc = frappe.get_doc("Purchase Invoice", pi.name)
|
||||
items, warehouses = pi_doc.get_items_and_warehouses()
|
||||
update_gl_entries_after(pi_doc.posting_date, pi_doc.posting_time, warehouses, items, wh_account)
|
||||
|
||||
update_gl_entries_after(pi_doc.posting_date, pi_doc.posting_time,
|
||||
warehouses, items, wh_account, company = pi.company)
|
||||
|
||||
frappe.db.commit()
|
||||
@@ -159,6 +159,13 @@ class Task(NestedSet):
|
||||
|
||||
self.update_nsm_model()
|
||||
|
||||
def update_status(self):
|
||||
if self.status not in ('Cancelled', 'Closed') and self.exp_end_date:
|
||||
from datetime import datetime
|
||||
if self.exp_end_date < datetime.now().date():
|
||||
self.db_set('status', 'Overdue')
|
||||
self.update_project()
|
||||
|
||||
@frappe.whitelist()
|
||||
def check_if_child_exists(name):
|
||||
child_tasks = frappe.get_all("Task", filters={"parent_task": name})
|
||||
@@ -186,10 +193,9 @@ def set_multiple_status(names, status):
|
||||
task.save()
|
||||
|
||||
def set_tasks_as_overdue():
|
||||
frappe.db.sql("""update tabTask set `status`='Overdue'
|
||||
where exp_end_date is not null
|
||||
and exp_end_date < CURDATE()
|
||||
and `status` not in ('Closed', 'Cancelled')""")
|
||||
tasks = frappe.get_all("Task", filters={'status':['not in',['Cancelled', 'Closed']]})
|
||||
for task in tasks:
|
||||
frappe.get_doc("Task", task.name).update_status()
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_children(doctype, parent, task=None, project=None, is_root=False):
|
||||
|
||||
@@ -117,4 +117,4 @@ def create_task(subject, start=None, end=None, depends_on=None, project=None, sa
|
||||
if save:
|
||||
task.save()
|
||||
|
||||
return task
|
||||
return task
|
||||
|
||||
@@ -10,8 +10,8 @@ frappe.ui.form.on("Timesheet", {
|
||||
filters:{
|
||||
'status': 'Active'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
frm.fields_dict['time_logs'].grid.get_field('task').get_query = function(frm, cdt, cdn) {
|
||||
var child = locals[cdt][cdn];
|
||||
@@ -20,33 +20,37 @@ frappe.ui.form.on("Timesheet", {
|
||||
'project': child.project,
|
||||
'status': ["!=", "Cancelled"]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
frm.fields_dict['time_logs'].grid.get_field('project').get_query = function() {
|
||||
return{
|
||||
filters: {
|
||||
'company': frm.doc.company
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
},
|
||||
|
||||
onload: function(frm){
|
||||
if (frm.doc.__islocal && frm.doc.time_logs) {
|
||||
calculate_time_and_amount(frm);
|
||||
}
|
||||
|
||||
if (frm.is_new()) {
|
||||
set_employee_and_company(frm);
|
||||
}
|
||||
},
|
||||
|
||||
refresh: function(frm) {
|
||||
if(frm.doc.docstatus==1) {
|
||||
if(frm.doc.per_billed < 100 && frm.doc.total_billable_hours && frm.doc.total_billable_hours > frm.doc.total_billed_hours){
|
||||
frm.add_custom_button(__("Make Sales Invoice"), function() { frm.trigger("make_invoice") },
|
||||
frm.add_custom_button(__("Make Sales Invoice"), function() { frm.trigger("make_invoice"); },
|
||||
"fa fa-file-alt");
|
||||
}
|
||||
|
||||
if(!frm.doc.salary_slip && frm.doc.employee){
|
||||
frm.add_custom_button(__("Make Salary Slip"), function() { frm.trigger("make_salary_slip") },
|
||||
frm.add_custom_button(__("Make Salary Slip"), function() { frm.trigger("make_salary_slip"); },
|
||||
"fa fa-file-alt");
|
||||
}
|
||||
}
|
||||
@@ -58,7 +62,7 @@ frappe.ui.form.on("Timesheet", {
|
||||
if ((row.from_time <= frappe.datetime.now_datetime()) && !row.completed) {
|
||||
button = 'Resume Timer';
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
frm.add_custom_button(__(button), function() {
|
||||
var flag = true;
|
||||
@@ -77,7 +81,7 @@ frappe.ui.form.on("Timesheet", {
|
||||
erpnext.timesheet.timer(frm, row, timestamp);
|
||||
flag = false;
|
||||
}
|
||||
})
|
||||
});
|
||||
// If no activities found to start a timer, create new
|
||||
if (flag) {
|
||||
erpnext.timesheet.timer(frm);
|
||||
@@ -94,7 +98,7 @@ frappe.ui.form.on("Timesheet", {
|
||||
frappe.db.get_value('Company', { 'company_name' : frm.doc.company }, 'standard_working_hours')
|
||||
.then(({ message }) => {
|
||||
(frappe.working_hours = message.standard_working_hours || 0);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
make_invoice: function(frm) {
|
||||
@@ -125,8 +129,8 @@ frappe.ui.form.on("Timesheet", {
|
||||
frappe.set_route("Form", r.message.doctype, r.message.name);
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
dialog.show();
|
||||
},
|
||||
|
||||
@@ -136,7 +140,7 @@ frappe.ui.form.on("Timesheet", {
|
||||
frm: frm
|
||||
});
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
frappe.ui.form.on("Timesheet Detail", {
|
||||
time_logs_remove: function(frm) {
|
||||
@@ -171,22 +175,22 @@ frappe.ui.form.on("Timesheet Detail", {
|
||||
.find('[data-fieldname="timer"]')
|
||||
.append(frappe.render_template("timesheet"));
|
||||
frm.trigger("control_timer");
|
||||
})
|
||||
});
|
||||
},
|
||||
hours: function(frm, cdt, cdn) {
|
||||
calculate_end_time(frm, cdt, cdn)
|
||||
calculate_end_time(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
billing_hours: function(frm, cdt, cdn) {
|
||||
calculate_billing_costing_amount(frm, cdt, cdn)
|
||||
calculate_billing_costing_amount(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
billing_rate: function(frm, cdt, cdn) {
|
||||
calculate_billing_costing_amount(frm, cdt, cdn)
|
||||
calculate_billing_costing_amount(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
costing_rate: function(frm, cdt, cdn) {
|
||||
calculate_billing_costing_amount(frm, cdt, cdn)
|
||||
calculate_billing_costing_amount(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
billable: function(frm, cdt, cdn) {
|
||||
@@ -212,7 +216,7 @@ frappe.ui.form.on("Timesheet Detail", {
|
||||
calculate_billing_costing_amount(frm, cdt, cdn);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -240,23 +244,23 @@ var calculate_end_time = function(frm, cdt, cdn) {
|
||||
frm._setting_hours = true;
|
||||
frappe.model.set_value(cdt, cdn, "to_time",
|
||||
d.format(frappe.defaultDatetimeFormat)).then(() => {
|
||||
frm._setting_hours = false;
|
||||
});
|
||||
frm._setting_hours = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var update_billing_hours = function(frm, cdt, cdn){
|
||||
var child = locals[cdt][cdn];
|
||||
if(!child.billable) frappe.model.set_value(cdt, cdn, 'billing_hours', 0.0);
|
||||
}
|
||||
};
|
||||
|
||||
var update_time_rates = function(frm, cdt, cdn){
|
||||
var child = locals[cdt][cdn];
|
||||
if(!child.billable){
|
||||
frappe.model.set_value(cdt, cdn, 'billing_rate', 0.0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var calculate_billing_costing_amount = function(frm, cdt, cdn){
|
||||
var child = locals[cdt][cdn];
|
||||
@@ -270,7 +274,7 @@ var calculate_billing_costing_amount = function(frm, cdt, cdn){
|
||||
frappe.model.set_value(cdt, cdn, 'billing_amount', billing_amount);
|
||||
frappe.model.set_value(cdt, cdn, 'costing_amount', costing_amount);
|
||||
calculate_time_and_amount(frm);
|
||||
}
|
||||
};
|
||||
|
||||
var calculate_time_and_amount = function(frm) {
|
||||
var tl = frm.doc.time_logs || [];
|
||||
@@ -294,4 +298,17 @@ var calculate_time_and_amount = function(frm) {
|
||||
frm.set_value("total_hours", total_working_hr);
|
||||
frm.set_value("total_billable_amount", total_billable_amount);
|
||||
frm.set_value("total_costing_amount", total_costing_amount);
|
||||
}
|
||||
};
|
||||
|
||||
// set employee (and company) to the one that's currently logged in
|
||||
const set_employee_and_company = function(frm) {
|
||||
const options = { user_id: frappe.session.user };
|
||||
const fields = ['name', 'company'];
|
||||
frappe.db.get_value('Employee', options, fields).then(({ message }) => {
|
||||
if (message) {
|
||||
// there is an employee with the currently logged in user_id
|
||||
frm.set_value("employee", message.name);
|
||||
frm.set_value("company", message.company);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -739,7 +739,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "total_costing_amount",
|
||||
"fieldtype": "Float",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -805,7 +805,7 @@
|
||||
"depends_on": "",
|
||||
"description": "",
|
||||
"fieldname": "total_billable_amount",
|
||||
"fieldtype": "Float",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -837,7 +837,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "total_billed_amount",
|
||||
"fieldtype": "Float",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -1000,7 +1000,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-01-30 11:28:18.518590",
|
||||
"modified": "2019-03-05 21:54:02.654690",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Projects",
|
||||
"name": "Timesheet",
|
||||
|
||||
147
erpnext/projects/report/billing_summary.py
Normal file
147
erpnext/projects/report/billing_summary.py
Normal file
@@ -0,0 +1,147 @@
|
||||
# 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 _
|
||||
from frappe.utils import time_diff_in_hours
|
||||
|
||||
def get_columns():
|
||||
return [
|
||||
{
|
||||
"label": _("Employee ID"),
|
||||
"fieldtype": "Link",
|
||||
"fieldname": "employee",
|
||||
"options": "Employee",
|
||||
"width": 300
|
||||
},
|
||||
{
|
||||
"label": _("Employee Name"),
|
||||
"fieldtype": "data",
|
||||
"fieldname": "employee_name",
|
||||
"hidden": 1,
|
||||
"width": 200
|
||||
},
|
||||
{
|
||||
"label": _("Timesheet"),
|
||||
"fieldtype": "Link",
|
||||
"fieldname": "timesheet",
|
||||
"options": "Timesheet",
|
||||
"width": 150
|
||||
},
|
||||
{
|
||||
"label": _("Billable Hours"),
|
||||
"fieldtype": "Float",
|
||||
"fieldname": "total_billable_hours",
|
||||
"width": 50
|
||||
},
|
||||
{
|
||||
"label": _("Working Hours"),
|
||||
"fieldtype": "Float",
|
||||
"fieldname": "total_hours",
|
||||
"width": 50
|
||||
},
|
||||
{
|
||||
"label": _("Amount"),
|
||||
"fieldtype": "Currency",
|
||||
"fieldname": "amount",
|
||||
"width": 100
|
||||
}
|
||||
]
|
||||
|
||||
def get_data(filters):
|
||||
data = []
|
||||
record = get_records(filters)
|
||||
|
||||
billable_hours_worked = 0
|
||||
hours_worked = 0
|
||||
working_cost = 0
|
||||
for entries in record:
|
||||
total_hours = 0
|
||||
total_billable_hours = 0
|
||||
total_amount = 0
|
||||
entries_exists = False
|
||||
timesheet_details = get_timesheet_details(filters, entries.name)
|
||||
|
||||
for activity in timesheet_details:
|
||||
entries_exists = True
|
||||
time_start = activity.from_time
|
||||
time_end = frappe.utils.add_to_date(activity.from_time, hours=activity.hours)
|
||||
from_date = frappe.utils.get_datetime(filters.from_date)
|
||||
to_date = frappe.utils.get_datetime(filters.to_date)
|
||||
|
||||
if time_start <= from_date and time_end >= from_date:
|
||||
total_hours, total_billable_hours, total_amount = get_billable_and_total_hours(activity,
|
||||
time_end, from_date, total_hours, total_billable_hours, total_amount)
|
||||
|
||||
billable_hours_worked += total_billable_hours
|
||||
hours_worked += total_hours
|
||||
working_cost += total_amount
|
||||
elif time_start >= from_date and time_end >= to_date:
|
||||
total_hours, total_billable_hours, total_amount = get_billable_and_total_hours(activity,
|
||||
to_date, time_start, total_hours, total_billable_hours, total_amount)
|
||||
|
||||
billable_hours_worked += total_billable_hours
|
||||
hours_worked += total_hours
|
||||
working_cost += total_amount
|
||||
elif time_start >= from_date and time_end <= to_date:
|
||||
total_hours, total_billable_hours, total_amount = get_billable_and_total_hours(activity,
|
||||
time_end, time_start, total_hours, total_billable_hours, total_amount)
|
||||
|
||||
billable_hours_worked += total_billable_hours
|
||||
hours_worked += total_hours
|
||||
working_cost += total_amount
|
||||
|
||||
row = {
|
||||
"employee": entries.employee,
|
||||
"employee_name": entries.employee_name,
|
||||
"timesheet": entries.name,
|
||||
"total_billable_hours": total_billable_hours,
|
||||
"total_hours": total_hours,
|
||||
"amount": total_amount
|
||||
}
|
||||
|
||||
if entries_exists:
|
||||
data.append(row)
|
||||
entries_exists = False
|
||||
|
||||
total = {
|
||||
"total_billable_hours": billable_hours_worked,
|
||||
"total_hours": hours_worked,
|
||||
"amount": working_cost
|
||||
}
|
||||
if billable_hours_worked !=0 or hours_worked !=0 or working_cost !=0:
|
||||
data.append(total)
|
||||
return data
|
||||
|
||||
def get_records(filters):
|
||||
record_filters = [
|
||||
["start_date", "<=", filters.to_date],
|
||||
["end_date", ">=", filters.from_date],
|
||||
["docstatus", "=", 1]
|
||||
]
|
||||
|
||||
if "employee" in filters:
|
||||
record_filters.append(["employee", "=", filters.employee])
|
||||
|
||||
return frappe.get_all("Timesheet", filters=record_filters, fields=[" * "] )
|
||||
|
||||
def get_billable_and_total_hours(activity, end, start, total_hours, total_billable_hours, total_amount):
|
||||
total_hours += abs(time_diff_in_hours(end, start))
|
||||
if activity.billable:
|
||||
total_billable_hours += abs(time_diff_in_hours(end, start))
|
||||
total_amount += total_billable_hours * activity.billing_rate
|
||||
return total_hours, total_billable_hours, total_amount
|
||||
|
||||
def get_timesheet_details(filters, parent):
|
||||
timesheet_details_filter = {"parent": parent}
|
||||
|
||||
if "project" in filters:
|
||||
timesheet_details_filter["project"] = filters.project
|
||||
|
||||
return frappe.get_all(
|
||||
"Timesheet Detail",
|
||||
filters = timesheet_details_filter,
|
||||
fields=["*"]
|
||||
)
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
/* eslint-disable */
|
||||
|
||||
frappe.query_reports["Employee Billing Summary"] = {
|
||||
"filters": [
|
||||
{
|
||||
fieldname: "employee",
|
||||
label: __("Employee"),
|
||||
fieldtype: "Link",
|
||||
options: "Employee",
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname:"from_date",
|
||||
label: __("From Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.datetime.add_months(frappe.datetime.month_start(), -1),
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname:"to_date",
|
||||
label: __("To Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.datetime.add_days(frappe.datetime.month_start(), -1),
|
||||
reqd: 1
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"add_total_row": 0,
|
||||
"creation": "2019-03-08 15:08:19.929728",
|
||||
"disable_prepared_report": 0,
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2019-03-08 15:08:19.929728",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Projects",
|
||||
"name": "Employee Billing Summary",
|
||||
"owner": "Administrator",
|
||||
"prepared_report": 0,
|
||||
"ref_doctype": "Timesheet",
|
||||
"report_name": "Employee Billing Summary",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
||||
"role": "Projects User"
|
||||
},
|
||||
{
|
||||
"role": "HR User"
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing User"
|
||||
},
|
||||
{
|
||||
"role": "Employee"
|
||||
},
|
||||
{
|
||||
"role": "Accounts User"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
# 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 _
|
||||
from erpnext.projects.report.billing_summary import get_columns, get_data
|
||||
|
||||
def execute(filters=None):
|
||||
filters = frappe._dict(filters or {})
|
||||
columns = get_columns()
|
||||
|
||||
data = get_data(filters)
|
||||
return columns, data
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
/* eslint-disable */
|
||||
|
||||
frappe.query_reports["Project Billing Summary"] = {
|
||||
"filters": [
|
||||
{
|
||||
fieldname: "project",
|
||||
label: __("Project"),
|
||||
fieldtype: "Link",
|
||||
options: "Project",
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname:"from_date",
|
||||
label: __("From Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.datetime.add_months(frappe.datetime.month_start(), -1),
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname:"to_date",
|
||||
label: __("To Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.datetime.add_days(frappe.datetime.month_start(),-1),
|
||||
reqd: 1
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"add_total_row": 0,
|
||||
"creation": "2019-03-11 16:22:39.460524",
|
||||
"disable_prepared_report": 0,
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2019-03-11 16:22:39.460524",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Projects",
|
||||
"name": "Project Billing Summary",
|
||||
"owner": "Administrator",
|
||||
"prepared_report": 0,
|
||||
"ref_doctype": "Timesheet",
|
||||
"report_name": "Project Billing Summary",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
||||
"role": "Projects User"
|
||||
},
|
||||
{
|
||||
"role": "HR User"
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing User"
|
||||
},
|
||||
{
|
||||
"role": "Employee"
|
||||
},
|
||||
{
|
||||
"role": "Accounts User"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
# 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 _
|
||||
from erpnext.projects.report.billing_summary import get_columns, get_data
|
||||
|
||||
def execute(filters=None):
|
||||
filters = frappe._dict(filters or {})
|
||||
columns = get_columns()
|
||||
|
||||
data = get_data(filters)
|
||||
return columns, data
|
||||
@@ -27,8 +27,6 @@ $(document).bind('toolbar_setup', function() {
|
||||
target="_blank">'+__('Documentation')+'</a></li>').insertBefore($help_menu);
|
||||
$('<li><a data-link-type="forum" href="https://discuss.erpnext.com" \
|
||||
target="_blank">'+__('User Forum')+'</a></li>').insertBefore($help_menu);
|
||||
$('<li class="gitter-chat-link"><a href="https://gitter.im/frappe/erpnext" \
|
||||
target="_blank">'+__('Gitter Chat')+'</a></li>').insertBefore($help_menu);
|
||||
$('<li><a href="https://github.com/frappe/erpnext/issues" \
|
||||
target="_blank">'+__('Report an Issue')+'</a></li>').insertBefore($help_menu);
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ def add_print_formats():
|
||||
def make_custom_fields(update=True):
|
||||
hsn_sac_field = 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=1)
|
||||
allow_on_submit=1, print_hide=1, fetch_if_empty=1)
|
||||
invoice_gst_fields = [
|
||||
dict(fieldname='gst_section', label='GST Details', fieldtype='Section Break',
|
||||
insert_after='language', print_hide=1, collapsible=1),
|
||||
@@ -243,6 +243,7 @@ def make_custom_fields(update=True):
|
||||
'Purchase Order Item': [hsn_sac_field],
|
||||
'Purchase Receipt Item': [hsn_sac_field],
|
||||
'Purchase Invoice Item': [hsn_sac_field],
|
||||
'Material Request Item': [hsn_sac_field],
|
||||
'Employee': [
|
||||
dict(fieldname='ifsc_code', label='IFSC Code',
|
||||
fieldtype='Data', insert_after='bank_ac_no', print_hide=1,
|
||||
|
||||
@@ -9,6 +9,8 @@ from erpnext.hr.utils import get_salary_assignment
|
||||
from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip
|
||||
|
||||
def validate_gstin_for_india(doc, method):
|
||||
if hasattr(doc, 'gst_state') and doc.gst_state:
|
||||
doc.gst_state_number = state_numbers[doc.gst_state]
|
||||
if not hasattr(doc, 'gstin') or not doc.gstin:
|
||||
return
|
||||
|
||||
|
||||
@@ -95,13 +95,12 @@
|
||||
<Cognome>{{ doc.customer_data.last_name }}</Cognome>
|
||||
</Anagrafica>
|
||||
{%- else %}
|
||||
{%- if doc.customer_data.is_public_administration %}
|
||||
<CodiceFiscale>{{ doc.customer_data.fiscal_code }}</CodiceFiscale>
|
||||
{%- else %}
|
||||
<IdFiscaleIVA>
|
||||
<IdPaese>{{ doc.customer_address_data.country_code }}</IdPaese>
|
||||
<IdCodice>{{ doc.tax_id | replace("IT","") }}</IdCodice>
|
||||
</IdFiscaleIVA>
|
||||
{%- if doc.customer_data.fiscal_code %}
|
||||
<CodiceFiscale>{{ doc.customer_data.fiscal_code }}</CodiceFiscale>
|
||||
{%- endif %}
|
||||
<Anagrafica>
|
||||
<Denominazione>{{ doc.customer_name }}</Denominazione>
|
||||
@@ -128,22 +127,42 @@
|
||||
<ImportoBollo>{{ format_float(doc.stamp_duty) }}</ImportoBollo>
|
||||
</DatiBollo>
|
||||
{%- endif %}
|
||||
<ImportoTotaleDocumento>{{ format_float(doc.grand_total) }}</ImportoTotaleDocumento>
|
||||
{%- if doc.discount_amount %}
|
||||
<ScontoMaggiorazione>
|
||||
{%- if doc.discount_amount > 0.0 %}
|
||||
<Tipo>SC</Tipo>
|
||||
{%- else %}
|
||||
<Tipo>MG</Tipo>
|
||||
{%- endif %}
|
||||
{%- if doc.additional_discount_percentage > 0.0 %}
|
||||
<Percentuale>{{ format_float(doc.additional_discount_percentage) }}</Percentuale>
|
||||
{%- endif %}
|
||||
<Importo>{{ format_float(doc.discount_amount) }}</Importo>
|
||||
</ScontoMaggiorazione>
|
||||
{%- endif %}
|
||||
<ImportoTotaleDocumento>{{ format_float(doc.rounded_total or doc.grand_total) }}</ImportoTotaleDocumento>
|
||||
<Causale>VENDITA</Causale>
|
||||
</DatiGeneraliDocumento>
|
||||
{%- if doc.po_no %}
|
||||
<DatiOrdineAcquisto>
|
||||
<IdDocumento>{{ doc.po_no }}</IdDocumento>
|
||||
{%- if doc.po_date %}
|
||||
<Data>{{ doc.po_date }}</Data>
|
||||
{%- endif %}
|
||||
</DatiOrdineAcquisto>
|
||||
{%- endif %}
|
||||
{%- for po_no, po_date in doc.customer_po_data.items() %}
|
||||
<DatiOrdineAcquisto>
|
||||
<IdDocumento>{{ po_no }}</IdDocumento>
|
||||
<Data>{{ po_date }}</Data>
|
||||
</DatiOrdineAcquisto>
|
||||
{%- endfor %}
|
||||
{%- if doc.is_return and doc.return_against_unamended %}
|
||||
<DatiFattureCollegate>
|
||||
<IdDocumento>{{ doc.return_against_unamended }}</IdDocumento>
|
||||
</DatiFattureCollegate>
|
||||
{%- endif %}
|
||||
{%- for row in doc.e_invoice_items %}
|
||||
{%- if row.delivery_note %}
|
||||
<DatiDDT>
|
||||
<NumeroDDT>{{ row.delivery_note }}</NumeroDDT>
|
||||
<DataDDT>{{ frappe.db.get_value('Delivery Note', row.delivery_note, 'posting_date') }}</DataDDT>
|
||||
<RiferimentoNumeroLinea>{{ row.idx }}</RiferimentoNumeroLinea>
|
||||
</DatiDDT>
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
{%- if doc.shipping_address_data %}
|
||||
<DatiTrasporto>
|
||||
<IndirizzoResa>
|
||||
@@ -199,7 +218,9 @@
|
||||
<ModalitaPagamento>{{ payment_term.mode_of_payment_code.split("-")[0] }}</ModalitaPagamento>
|
||||
<DataScadenzaPagamento>{{ payment_term.due_date }}</DataScadenzaPagamento>
|
||||
<ImportoPagamento>{{ format_float(payment_term.payment_amount) }}</ImportoPagamento>
|
||||
<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 %}
|
||||
<IBAN>{{ payment_term.bank_account_iban }}</IBAN>
|
||||
<ABI>{{ payment_term.bank_account_iban[5:10] }}</ABI>
|
||||
|
||||
@@ -3,15 +3,26 @@ erpnext.setup_e_invoice_button = (doctype) => {
|
||||
refresh: (frm) => {
|
||||
if(frm.doc.docstatus == 1) {
|
||||
frm.add_custom_button('Generate E-Invoice', () => {
|
||||
var w = window.open(
|
||||
frappe.urllib.get_full_url(
|
||||
"/api/method/erpnext.regional.italy.utils.generate_single_invoice?"
|
||||
+ "docname=" + frm.doc.name
|
||||
)
|
||||
)
|
||||
if (!w) {
|
||||
frappe.msgprint(__("Please enable pop-ups")); return;
|
||||
}
|
||||
frm.call({
|
||||
method: "erpnext.regional.italy.utils.generate_single_invoice",
|
||||
args: {
|
||||
docname: frm.doc.name
|
||||
},
|
||||
callback: function(r) {
|
||||
frm.reload_doc();
|
||||
if(r.message) {
|
||||
var w = window.open(
|
||||
frappe.urllib.get_full_url(
|
||||
"/api/method/erpnext.regional.italy.utils.download_e_invoice_file?"
|
||||
+ "file_name=" + r.message
|
||||
)
|
||||
)
|
||||
if (!w) {
|
||||
frappe.msgprint(__("Please enable pop-ups")); return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,22 @@ def make_custom_fields(update=True):
|
||||
print_hide=1, hidden=1, read_only=1, options="currency")
|
||||
]
|
||||
|
||||
customer_po_fields = [
|
||||
dict(fieldname='customer_po_details', label='Customer PO',
|
||||
fieldtype='Section Break', insert_after='image'),
|
||||
dict(fieldname='customer_po_no', label='Customer PO No',
|
||||
fieldtype='Data', insert_after='customer_po_details',
|
||||
fetch_from = 'sales_order.po_no',
|
||||
print_hide=1, allow_on_submit=1, fetch_if_empty= 1, read_only=1, no_copy=1),
|
||||
dict(fieldname='customer_po_clm_brk', label='',
|
||||
fieldtype='Column Break', insert_after='customer_po_no',
|
||||
print_hide=1, read_only=1),
|
||||
dict(fieldname='customer_po_date', label='Customer PO Date',
|
||||
fieldtype='Date', insert_after='customer_po_clm_brk',
|
||||
fetch_from = 'sales_order.po_date',
|
||||
print_hide=1, allow_on_submit=1, fetch_if_empty= 1, read_only=1, no_copy=1)
|
||||
]
|
||||
|
||||
custom_fields = {
|
||||
'Company': [
|
||||
dict(fieldname='sb_e_invoicing', label='E-Invoicing',
|
||||
@@ -128,7 +144,7 @@ def make_custom_fields(update=True):
|
||||
'Purchase Invoice Item': invoice_item_fields,
|
||||
'Sales Order Item': invoice_item_fields,
|
||||
'Delivery Note Item': invoice_item_fields,
|
||||
'Sales Invoice Item': invoice_item_fields,
|
||||
'Sales Invoice Item': invoice_item_fields + customer_po_fields,
|
||||
'Quotation Item': invoice_item_fields,
|
||||
'Purchase Order Item': invoice_item_fields,
|
||||
'Purchase Receipt Item': invoice_item_fields,
|
||||
|
||||
@@ -4,6 +4,7 @@ import frappe, json, os
|
||||
from frappe.utils import flt, cstr
|
||||
from erpnext.controllers.taxes_and_totals import get_itemised_tax
|
||||
from frappe import _
|
||||
from six import string_types
|
||||
from frappe.utils.file_manager import save_file, remove_file
|
||||
from frappe.desk.form.load import get_attachments
|
||||
from erpnext.regional.italy import state_codes
|
||||
@@ -82,6 +83,14 @@ def prepare_invoice(invoice, progressive_number):
|
||||
if item.tax_rate == 0.0 and item.tax_amount == 0.0:
|
||||
item.tax_exemption_reason = tax_data["0.0"]["tax_exemption_reason"]
|
||||
|
||||
customer_po_data = {}
|
||||
for d in invoice.e_invoice_items:
|
||||
if (d.customer_po_no and d.customer_po_date
|
||||
and d.customer_po_no not in customer_po_data):
|
||||
customer_po_data[d.customer_po_no] = d.customer_po_date
|
||||
|
||||
invoice.customer_po_data = customer_po_data
|
||||
|
||||
return invoice
|
||||
|
||||
def get_conditions(filters):
|
||||
@@ -134,6 +143,7 @@ def get_invoice_summary(items, taxes):
|
||||
idx=len(items)+1,
|
||||
item_code=reference_row.description,
|
||||
item_name=reference_row.description,
|
||||
description=reference_row.description,
|
||||
rate=reference_row.tax_amount,
|
||||
qty=1.0,
|
||||
amount=reference_row.tax_amount,
|
||||
@@ -142,7 +152,7 @@ def get_invoice_summary(items, taxes):
|
||||
tax_amount=(reference_row.tax_amount * tax.rate) / 100,
|
||||
net_amount=reference_row.tax_amount,
|
||||
taxable_amount=reference_row.tax_amount,
|
||||
item_tax_rate="{}",
|
||||
item_tax_rate={tax.account_head: tax.rate},
|
||||
charges=True
|
||||
)
|
||||
)
|
||||
@@ -150,10 +160,16 @@ def get_invoice_summary(items, taxes):
|
||||
#Check item tax rates if tax rate is zero.
|
||||
if tax.rate == 0:
|
||||
for item in items:
|
||||
item_tax_rate = json.loads(item.item_tax_rate)
|
||||
if tax.account_head in item_tax_rate:
|
||||
item_tax_rate = item.item_tax_rate
|
||||
if isinstance(item.item_tax_rate, string_types):
|
||||
item_tax_rate = json.loads(item.item_tax_rate)
|
||||
|
||||
if item_tax_rate and tax.account_head in item_tax_rate:
|
||||
key = cstr(item_tax_rate[tax.account_head])
|
||||
summary_data.setdefault(key, {"tax_amount": 0.0, "taxable_amount": 0.0, "tax_exemption_reason": "", "tax_exemption_law": ""})
|
||||
if key not in summary_data:
|
||||
summary_data.setdefault(key, {"tax_amount": 0.0, "taxable_amount": 0.0,
|
||||
"tax_exemption_reason": "", "tax_exemption_law": ""})
|
||||
|
||||
summary_data[key]["tax_amount"] += item.tax_amount
|
||||
summary_data[key]["taxable_amount"] += item.net_amount
|
||||
if key == "0.0":
|
||||
@@ -198,19 +214,25 @@ def sales_invoice_validate(doc):
|
||||
else:
|
||||
doc.company_fiscal_regime = company_fiscal_regime
|
||||
|
||||
doc.company_tax_id = frappe.get_cached_value("Company", doc.company, 'tax_id')
|
||||
doc.company_fiscal_code = frappe.get_cached_value("Company", doc.company, 'fiscal_code')
|
||||
if not doc.company_tax_id and not doc.company_fiscal_code:
|
||||
frappe.throw(_("Please set either the Tax ID or Fiscal Code on Company '%s'" % doc.company), title=_("E-Invoicing Information Missing"))
|
||||
|
||||
#Validate customer details
|
||||
customer_type, is_public_administration = frappe.db.get_value("Customer", doc.customer, ["customer_type", "is_public_administration"])
|
||||
if customer_type == _("Individual"):
|
||||
customer = frappe.get_doc("Customer", doc.customer)
|
||||
|
||||
if customer.customer_type == _("Individual"):
|
||||
doc.customer_fiscal_code = customer.fiscal_code
|
||||
if not doc.customer_fiscal_code:
|
||||
frappe.throw(_("Please set Fiscal Code for the customer '%s'" % doc.customer), title=_("E-Invoicing Information Missing"))
|
||||
else:
|
||||
if is_public_administration:
|
||||
if customer.is_public_administration:
|
||||
doc.customer_fiscal_code = customer.fiscal_code
|
||||
if not doc.customer_fiscal_code:
|
||||
frappe.throw(_("Please set Fiscal Code for the public administration '%s'" % doc.customer), title=_("E-Invoicing Information Missing"))
|
||||
else:
|
||||
doc.tax_id = customer.tax_id
|
||||
if not doc.tax_id:
|
||||
frappe.throw(_("Please set Tax ID for the customer '%s'" % doc.customer), title=_("E-Invoicing Information Missing"))
|
||||
|
||||
@@ -266,13 +288,18 @@ def prepare_and_attach_invoice(doc, replace=False):
|
||||
def generate_single_invoice(docname):
|
||||
doc = frappe.get_doc("Sales Invoice", docname)
|
||||
|
||||
|
||||
e_invoice = prepare_and_attach_invoice(doc, True)
|
||||
|
||||
return e_invoice.file_name
|
||||
|
||||
@frappe.whitelist()
|
||||
def download_e_invoice_file(file_name):
|
||||
content = None
|
||||
with open(frappe.get_site_path('private', 'files', e_invoice.file_name), "r") as f:
|
||||
with open(frappe.get_site_path('private', 'files', file_name), "r") as f:
|
||||
content = f.read()
|
||||
|
||||
frappe.local.response.filename = e_invoice.file_name
|
||||
frappe.local.response.filename = file_name
|
||||
frappe.local.response.filecontent = content
|
||||
frappe.local.response.type = "download"
|
||||
|
||||
|
||||
@@ -87,8 +87,8 @@ def get_gl_entries(filters):
|
||||
left join `tabPurchase Invoice` pur on gl.voucher_no = pur.name
|
||||
left join `tabJournal Entry` jnl on gl.voucher_no = jnl.name
|
||||
left join `tabPayment Entry` pay on gl.voucher_no = pay.name
|
||||
left join `tabCustomer` cus on gl.party = cus.customer_name
|
||||
left join `tabSupplier` sup on gl.party = sup.supplier_name
|
||||
left join `tabCustomer` cus on gl.party = cus.name
|
||||
left join `tabSupplier` sup on gl.party = sup.name
|
||||
where gl.company=%(company)s and gl.fiscal_year=%(fiscal_year)s
|
||||
{group_by_condition}
|
||||
order by GlPostDate, voucher_no"""\
|
||||
|
||||
@@ -28,24 +28,24 @@ def make_custom_fields():
|
||||
purchase_invoice_fields = [
|
||||
dict(fieldname='company_trn', label='Company TRN',
|
||||
fieldtype='Read Only', insert_after='shipping_address',
|
||||
options='company.tax_id', print_hide=1),
|
||||
fetch_from='company.tax_id', print_hide=1),
|
||||
dict(fieldname='supplier_name_in_arabic', label='Supplier Name in Arabic',
|
||||
fieldtype='Read Only', insert_after='supplier_name',
|
||||
options='supplier.supplier_name_in_arabic', print_hide=1)
|
||||
fetch_from='supplier.supplier_name_in_arabic', print_hide=1)
|
||||
]
|
||||
|
||||
sales_invoice_fields = [
|
||||
dict(fieldname='company_trn', label='Company TRN',
|
||||
fieldtype='Read Only', insert_after='company_address',
|
||||
options='company.tax_id', print_hide=1),
|
||||
fetch_from='company.tax_id', print_hide=1),
|
||||
dict(fieldname='customer_name_in_arabic', label='Customer Name in Arabic',
|
||||
fieldtype='Read Only', insert_after='customer_name',
|
||||
options='customer.customer_name_in_arabic', print_hide=1),
|
||||
fetch_from='customer.customer_name_in_arabic', print_hide=1),
|
||||
]
|
||||
|
||||
invoice_item_fields = [
|
||||
dict(fieldname='tax_code', label='Tax Code',
|
||||
fieldtype='Read Only', options='item_code.tax_code', insert_after='description',
|
||||
fieldtype='Read Only', fetch_from='item_code.tax_code', insert_after='description',
|
||||
allow_on_submit=1, print_hide=1),
|
||||
dict(fieldname='tax_rate', label='Tax Rate',
|
||||
fieldtype='Float', insert_after='tax_code',
|
||||
|
||||
@@ -388,6 +388,7 @@ class SalesOrder(SellingController):
|
||||
items.append(dict(
|
||||
name= i.name,
|
||||
item_code= i.item_code,
|
||||
description= i.description,
|
||||
bom = bom,
|
||||
warehouse = i.warehouse,
|
||||
pending_qty = pending_qty,
|
||||
@@ -398,6 +399,7 @@ class SalesOrder(SellingController):
|
||||
items.append(dict(
|
||||
name= i.name,
|
||||
item_code= i.item_code,
|
||||
description= i.description,
|
||||
bom = '',
|
||||
warehouse = i.warehouse,
|
||||
pending_qty = pending_qty,
|
||||
@@ -610,7 +612,8 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
|
||||
def postprocess(source, target):
|
||||
set_missing_values(source, target)
|
||||
#Get the advance paid Journal Entries in Sales Invoice Advance
|
||||
target.set_advances()
|
||||
if target.get("allocate_advances_automatically"):
|
||||
target.set_advances()
|
||||
|
||||
def set_missing_values(source, target):
|
||||
target.is_pos = 0
|
||||
@@ -901,7 +904,8 @@ def make_work_orders(items, sales_order, company, project=None):
|
||||
sales_order=sales_order,
|
||||
sales_order_item=i['sales_order_item'],
|
||||
project=project,
|
||||
fg_warehouse=i['warehouse']
|
||||
fg_warehouse=i['warehouse'],
|
||||
description=i['description']
|
||||
)).insert()
|
||||
work_order.set_work_order_operations()
|
||||
work_order.save()
|
||||
|
||||
@@ -573,7 +573,8 @@ class TestSalesOrder(unittest.TestCase):
|
||||
"item_code": item.get("item_code"),
|
||||
"pending_qty": item.get("pending_qty"),
|
||||
"sales_order_item": item.get("sales_order_item"),
|
||||
"bom": item.get("bom")
|
||||
"bom": item.get("bom"),
|
||||
"description": item.get("description")
|
||||
})
|
||||
so_item_name[item.get("sales_order_item")]= item.get("pending_qty")
|
||||
make_work_orders(json.dumps({"items":po_items}), so.name, so.company)
|
||||
|
||||
@@ -446,16 +446,15 @@ erpnext.pos.PointOfSale = class PointOfSale {
|
||||
}
|
||||
|
||||
setup_company() {
|
||||
this.company = frappe.sys_defaults.company;
|
||||
return new Promise(resolve => {
|
||||
if(!this.company) {
|
||||
if(!frappe.sys_defaults.company) {
|
||||
frappe.prompt({fieldname:"company", options: "Company", fieldtype:"Link",
|
||||
label: __("Select Company"), reqd: 1}, (data) => {
|
||||
this.company = data.company;
|
||||
resolve(this.company);
|
||||
}, __("Select Company"));
|
||||
} else {
|
||||
resolve(this.company);
|
||||
resolve();
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -509,7 +508,9 @@ erpnext.pos.PointOfSale = class PointOfSale {
|
||||
}
|
||||
|
||||
set_pos_profile_data() {
|
||||
this.frm.doc.company = this.company;
|
||||
if (this.company) {
|
||||
this.frm.doc.company = this.company;
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
return this.frm.call({
|
||||
|
||||
@@ -39,7 +39,7 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p
|
||||
|
||||
|
||||
if display_items_in_stock == 0:
|
||||
res = frappe.db.sql("""select i.name as item_code, i.item_name, i.image as item_image,
|
||||
res = frappe.db.sql("""select i.name as item_code, i.item_name, i.image as item_image, i.idx as idx,
|
||||
i.is_stock_item, item_det.price_list_rate, item_det.currency
|
||||
from `tabItem` i LEFT JOIN
|
||||
(select item_code, price_list_rate, currency from
|
||||
@@ -49,7 +49,7 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p
|
||||
where
|
||||
i.disabled = 0 and i.has_variants = 0 and i.is_sales_item = 1
|
||||
and i.item_group in (select name from `tabItem Group` where lft >= {lft} and rgt <= {rgt})
|
||||
and {condition} limit {start}, {page_length}""".format(start=start,page_length=page_length,lft=lft, rgt=rgt, condition=condition),
|
||||
and {condition} order by idx desc limit {start}, {page_length}""".format(start=start,page_length=page_length,lft=lft, rgt=rgt, condition=condition),
|
||||
{
|
||||
'item_code': item_code,
|
||||
'price_list': price_list
|
||||
@@ -60,7 +60,7 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p
|
||||
}
|
||||
|
||||
elif display_items_in_stock == 1:
|
||||
query = """select i.name as item_code, i.item_name, i.image as item_image,
|
||||
query = """select i.name as item_code, i.item_name, i.image as item_image, i.idx as idx,
|
||||
i.is_stock_item, item_det.price_list_rate, item_det.currency
|
||||
from `tabItem` i LEFT JOIN
|
||||
(select item_code, price_list_rate, currency from
|
||||
@@ -79,7 +79,7 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p
|
||||
where
|
||||
i.disabled = 0 and i.has_variants = 0 and i.is_sales_item = 1
|
||||
and i.item_group in (select name from `tabItem Group` where lft >= {lft} and rgt <= {rgt})
|
||||
and {condition} limit {start}, {page_length}""".format
|
||||
and {condition} order by idx desc limit {start}, {page_length}""".format
|
||||
(start=start,page_length=page_length,lft=lft, rgt=rgt, condition=condition),
|
||||
{
|
||||
'item_code': item_code,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"brand": "_Test Brand",
|
||||
"brand": "_Test Brand",
|
||||
"doctype": "Brand"
|
||||
}
|
||||
]
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user