Merge branch 'hotfix' into ar-credit-note
This commit is contained in:
@@ -5,7 +5,7 @@ import frappe
|
|||||||
from erpnext.hooks import regional_overrides
|
from erpnext.hooks import regional_overrides
|
||||||
from frappe.utils import getdate
|
from frappe.utils import getdate
|
||||||
|
|
||||||
__version__ = '11.1.19'
|
__version__ = '11.1.20'
|
||||||
|
|
||||||
def get_default_company(user=None):
|
def get_default_company(user=None):
|
||||||
'''Get default company for user'''
|
'''Get default company for user'''
|
||||||
@@ -145,14 +145,3 @@ def is_member():
|
|||||||
if last_membership and getdate(last_membership.to_date) > getdate():
|
if last_membership and getdate(last_membership.to_date) > getdate():
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def check_branch_compatibility_with_frappe():
|
|
||||||
from frappe.utils.change_log import get_versions
|
|
||||||
versions = get_versions()
|
|
||||||
frappe_branch = versions["frappe"]["branch"]
|
|
||||||
erpnext_branch = versions["erpnext"]["branch"]
|
|
||||||
|
|
||||||
if frappe_branch in ("hotfix", "master") and erpnext_branch == "develop":
|
|
||||||
raise frappe.IncompatibleApp("Frappe is on branch: {} and ERPNext is on branch: {}".format(frappe_branch, erpnext_branch))
|
|
||||||
if erpnext_branch in ("hotfix", "master") and frappe_branch == "develop":
|
|
||||||
raise frappe.IncompatibleApp("Frappe is on branch: {} and ERPNext is on branch: {}".format(frappe_branch, erpnext_branch))
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -344,6 +344,7 @@ class TestPurchaseInvoice(unittest.TestCase):
|
|||||||
|
|
||||||
pi = frappe.copy_doc(test_records[0])
|
pi = frappe.copy_doc(test_records[0])
|
||||||
pi.disable_rounded_total = 1
|
pi.disable_rounded_total = 1
|
||||||
|
pi.allocate_advances_automatically = 0
|
||||||
pi.append("advances", {
|
pi.append("advances", {
|
||||||
"reference_type": "Journal Entry",
|
"reference_type": "Journal Entry",
|
||||||
"reference_name": jv.name,
|
"reference_name": jv.name,
|
||||||
@@ -383,6 +384,7 @@ class TestPurchaseInvoice(unittest.TestCase):
|
|||||||
|
|
||||||
pi = frappe.copy_doc(test_records[0])
|
pi = frappe.copy_doc(test_records[0])
|
||||||
pi.disable_rounded_total = 1
|
pi.disable_rounded_total = 1
|
||||||
|
pi.allocate_advances_automatically = 0
|
||||||
pi.append("advances", {
|
pi.append("advances", {
|
||||||
"reference_type": "Journal Entry",
|
"reference_type": "Journal Entry",
|
||||||
"reference_name": jv.name,
|
"reference_name": jv.name,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -855,6 +855,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
jv.submit()
|
jv.submit()
|
||||||
|
|
||||||
si = frappe.copy_doc(test_records[0])
|
si = frappe.copy_doc(test_records[0])
|
||||||
|
si.allocate_advances_automatically = 0
|
||||||
si.append("advances", {
|
si.append("advances", {
|
||||||
"doctype": "Sales Invoice Advance",
|
"doctype": "Sales Invoice Advance",
|
||||||
"reference_type": "Journal Entry",
|
"reference_type": "Journal Entry",
|
||||||
|
|||||||
@@ -206,12 +206,10 @@ frappe.ui.form.on('Asset', {
|
|||||||
erpnext.asset.set_accululated_depreciation(frm);
|
erpnext.asset.set_accululated_depreciation(frm);
|
||||||
},
|
},
|
||||||
|
|
||||||
depreciation_method: function(frm) {
|
|
||||||
frm.events.make_schedules_editable(frm);
|
|
||||||
},
|
|
||||||
|
|
||||||
make_schedules_editable: function(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.toggle_enable("schedules", is_editable);
|
||||||
frm.fields_dict["schedules"].grid.toggle_enable("schedule_date", is_editable);
|
frm.fields_dict["schedules"].grid.toggle_enable("schedule_date", is_editable);
|
||||||
frm.fields_dict["schedules"].grid.toggle_enable("depreciation_amount", 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);
|
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
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe, erpnext
|
import frappe, erpnext, math, json
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
from six import string_types
|
||||||
from frappe.utils import flt, add_months, cint, nowdate, getdate, today, date_diff
|
from frappe.utils import flt, add_months, cint, nowdate, getdate, today, date_diff
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
|
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
|
||||||
@@ -20,6 +21,7 @@ class Asset(AccountsController):
|
|||||||
self.validate_item()
|
self.validate_item()
|
||||||
self.set_missing_values()
|
self.set_missing_values()
|
||||||
if self.calculate_depreciation:
|
if self.calculate_depreciation:
|
||||||
|
self.set_depreciation_rate()
|
||||||
self.make_depreciation_schedule()
|
self.make_depreciation_schedule()
|
||||||
self.set_accumulated_depreciation()
|
self.set_accumulated_depreciation()
|
||||||
else:
|
else:
|
||||||
@@ -89,17 +91,22 @@ class Asset(AccountsController):
|
|||||||
if self.is_existing_asset:
|
if self.is_existing_asset:
|
||||||
return
|
return
|
||||||
|
|
||||||
date = nowdate()
|
|
||||||
docname = self.purchase_receipt or self.purchase_invoice
|
docname = self.purchase_receipt or self.purchase_invoice
|
||||||
if docname:
|
if docname:
|
||||||
doctype = 'Purchase Receipt' if self.purchase_receipt else 'Purchase Invoice'
|
doctype = 'Purchase Receipt' if self.purchase_receipt else 'Purchase Invoice'
|
||||||
date = frappe.db.get_value(doctype, docname, 'posting_date')
|
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"))
|
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):
|
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 = []
|
self.schedules = []
|
||||||
|
|
||||||
if not self.get("schedules") and self.available_for_use_date:
|
if not self.get("schedules") and self.available_for_use_date:
|
||||||
@@ -254,14 +261,16 @@ class Asset(AccountsController):
|
|||||||
return flt(self.get('finance_books')[cint(idx)-1].value_after_depreciation)
|
return flt(self.get('finance_books')[cint(idx)-1].value_after_depreciation)
|
||||||
|
|
||||||
def get_depreciation_amount(self, depreciable_value, total_number_of_depreciations, row):
|
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 / cint(total_number_of_depreciations)
|
depreciation_amount = amt * row.rate_of_depreciation
|
||||||
depreciation_amount = flt(depreciable_value * factor / 100, 0)
|
else:
|
||||||
|
depreciation_amount = flt(depreciable_value) * (flt(row.rate_of_depreciation) / 100)
|
||||||
value_after_depreciation = flt(depreciable_value) - depreciation_amount
|
value_after_depreciation = flt(depreciable_value) - depreciation_amount
|
||||||
if value_after_depreciation < flt(row.expected_value_after_useful_life):
|
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 = flt(depreciable_value) - flt(row.expected_value_after_useful_life)
|
||||||
|
|
||||||
return depreciation_amount
|
return depreciation_amount
|
||||||
|
|
||||||
@@ -394,6 +403,32 @@ class Asset(AccountsController):
|
|||||||
make_gl_entries(gl_entries)
|
make_gl_entries(gl_entries)
|
||||||
self.db_set('booked_fixed_asset', 1)
|
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():
|
def update_maintenance_status():
|
||||||
assets = frappe.get_all('Asset', filters = {'docstatus': 1, 'maintenance_required': 1})
|
assets = frappe.get_all('Asset', filters = {'docstatus': 1, 'maintenance_required': 1})
|
||||||
|
|
||||||
@@ -480,7 +515,6 @@ def create_asset_adjustment(asset, asset_category, company):
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def transfer_asset(args):
|
def transfer_asset(args):
|
||||||
import json
|
|
||||||
args = json.loads(args)
|
args = json.loads(args)
|
||||||
|
|
||||||
if args.get('serial_no'):
|
if args.get('serial_no'):
|
||||||
|
|||||||
@@ -160,9 +160,9 @@ class TestAsset(unittest.TestCase):
|
|||||||
asset.save()
|
asset.save()
|
||||||
|
|
||||||
expected_schedules = [
|
expected_schedules = [
|
||||||
["2020-06-06", 66667.0, 66667.0],
|
["2020-06-06", 66666.67, 66666.67],
|
||||||
["2021-04-06", 22222.0, 88889.0],
|
["2021-04-06", 22222.22, 88888.89],
|
||||||
["2022-02-06", 1111.0, 90000.0]
|
["2022-02-06", 1111.11, 90000.0]
|
||||||
]
|
]
|
||||||
|
|
||||||
schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
|
schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
|
||||||
@@ -192,8 +192,8 @@ class TestAsset(unittest.TestCase):
|
|||||||
asset.save()
|
asset.save()
|
||||||
|
|
||||||
expected_schedules = [
|
expected_schedules = [
|
||||||
["2020-06-06", 33333.0, 83333.0],
|
["2020-06-06", 33333.33, 83333.33],
|
||||||
["2021-04-06", 6667.0, 90000.0]
|
["2021-04-06", 6666.67, 90000.0]
|
||||||
]
|
]
|
||||||
|
|
||||||
schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
|
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_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
|
||||||
asset = frappe.get_doc('Asset', asset_name)
|
asset = frappe.get_doc('Asset', asset_name)
|
||||||
asset.calculate_depreciation = 1
|
asset.calculate_depreciation = 1
|
||||||
asset.purchase_date = '2020-06-06'
|
asset.purchase_date = '2020-01-30'
|
||||||
asset.is_existing_asset = 0
|
asset.is_existing_asset = 0
|
||||||
asset.available_for_use_date = "2020-01-30"
|
asset.available_for_use_date = "2020-01-30"
|
||||||
asset.append("finance_books", {
|
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_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
|
||||||
asset = frappe.get_doc('Asset', asset_name)
|
asset = frappe.get_doc('Asset', asset_name)
|
||||||
asset.calculate_depreciation = 1
|
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.available_for_use_date = "2020-01-30"
|
||||||
asset.append("finance_books", {
|
asset.append("finance_books", {
|
||||||
"expected_value_after_useful_life": 10000,
|
"expected_value_after_useful_life": 10000,
|
||||||
@@ -277,6 +277,37 @@ class TestAsset(unittest.TestCase):
|
|||||||
self.assertEqual(gle, expected_gle)
|
self.assertEqual(gle, expected_gle)
|
||||||
self.assertEqual(asset.get("value_after_depreciation"), 0)
|
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):
|
def test_depreciation_entry_cancellation(self):
|
||||||
pr = make_purchase_receipt(item_code="Macbook Pro",
|
pr = make_purchase_receipt(item_code="Macbook Pro",
|
||||||
qty=1, rate=100000.0, location="Test Location")
|
qty=1, rate=100000.0, location="Test Location")
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"allow_copy": 0,
|
||||||
|
"allow_events_in_timeline": 0,
|
||||||
"allow_guest_to_view": 0,
|
"allow_guest_to_view": 0,
|
||||||
"allow_import": 0,
|
"allow_import": 0,
|
||||||
"allow_rename": 0,
|
"allow_rename": 0,
|
||||||
@@ -14,11 +15,13 @@
|
|||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "",
|
"depends_on": "",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "finance_book",
|
"fieldname": "finance_book",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -42,14 +45,17 @@
|
|||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
|
"translatable": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "depreciation_method",
|
"fieldname": "depreciation_method",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -73,14 +79,17 @@
|
|||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
|
"translatable": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "total_number_of_depreciations",
|
"fieldname": "total_number_of_depreciations",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -103,14 +112,17 @@
|
|||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
|
"translatable": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "column_break_5",
|
"fieldname": "column_break_5",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -133,14 +145,17 @@
|
|||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
|
"translatable": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "frequency_of_depreciation",
|
"fieldname": "frequency_of_depreciation",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -163,15 +178,18 @@
|
|||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
|
"translatable": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:parent.doctype == 'Asset'",
|
"depends_on": "eval:parent.doctype == 'Asset'",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "depreciation_start_date",
|
"fieldname": "depreciation_start_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -194,16 +212,19 @@
|
|||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
|
"translatable": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"depends_on": "eval:parent.doctype == 'Asset'",
|
"depends_on": "eval:parent.doctype == 'Asset'",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "expected_value_after_useful_life",
|
"fieldname": "expected_value_after_useful_life",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -227,14 +248,17 @@
|
|||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
|
"translatable": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "value_after_depreciation",
|
"fieldname": "value_after_depreciation",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
@@ -258,20 +282,54 @@
|
|||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 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
|
"unique": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"has_web_view": 0,
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
"hide_toolbar": 0,
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
"in_create": 0,
|
||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2018-05-12 14:56:44.800046",
|
"modified": "2019-04-09 19:45:14.523488",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Assets",
|
"module": "Assets",
|
||||||
"name": "Asset Finance Book",
|
"name": "Asset Finance Book",
|
||||||
@@ -280,10 +338,10 @@
|
|||||||
"permissions": [],
|
"permissions": [],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
"show_name_in_global_search": 0,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"track_changes": 1,
|
"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):
|
def postprocess(source, target):
|
||||||
set_missing_values(source, target)
|
set_missing_values(source, target)
|
||||||
#Get the advance paid Journal Entries in Purchase Invoice Advance
|
#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):
|
def update_item(obj, target, source_parent):
|
||||||
target.amount = flt(obj.amount) - flt(obj.billed_amt)
|
target.amount = flt(obj.amount) - flt(obj.billed_amt)
|
||||||
|
|||||||
@@ -244,6 +244,10 @@ def make_return_doc(doctype, source_name, target_doc=None):
|
|||||||
doc.paid_amount = -1 * source.paid_amount
|
doc.paid_amount = -1 * source.paid_amount
|
||||||
doc.base_paid_amount = -1 * source.base_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.discount_amount = -1 * source.discount_amount
|
||||||
doc.run_method("calculate_taxes_and_totals")
|
doc.run_method("calculate_taxes_and_totals")
|
||||||
|
|
||||||
|
|||||||
@@ -42,10 +42,10 @@ def create_variant_with_tables(item, args):
|
|||||||
return variant
|
return variant
|
||||||
|
|
||||||
def make_item_variant():
|
def make_item_variant():
|
||||||
frappe.delete_doc_if_exists("Item", "_Test Variant Item-S", force=1)
|
frappe.delete_doc_if_exists("Item", "_Test Variant Item-XSL", force=1)
|
||||||
variant = create_variant_with_tables("_Test Variant Item", '{"Test Size": "Small"}')
|
variant = create_variant_with_tables("_Test Variant Item", '{"Test Size": "Extra Small"}')
|
||||||
variant.item_code = "_Test Variant Item-S"
|
variant.item_code = "_Test Variant Item-XSL"
|
||||||
variant.item_name = "_Test Variant Item-S"
|
variant.item_name = "_Test Variant Item-XSL"
|
||||||
variant.save()
|
variant.save()
|
||||||
return variant
|
return variant
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ doctype_js = {
|
|||||||
|
|
||||||
welcome_email = "erpnext.setup.utils.welcome_email"
|
welcome_email = "erpnext.setup.utils.welcome_email"
|
||||||
|
|
||||||
connect = "erpnext.check_branch_compatibility_with_frappe"
|
|
||||||
|
|
||||||
# setup wizard
|
# setup wizard
|
||||||
setup_wizard_requires = "assets/erpnext/js/setup_wizard.js"
|
setup_wizard_requires = "assets/erpnext/js/setup_wizard.js"
|
||||||
setup_wizard_stages = "erpnext.setup.setup_wizard.setup_wizard.get_setup_stages"
|
setup_wizard_stages = "erpnext.setup.setup_wizard.setup_wizard.get_setup_stages"
|
||||||
|
|||||||
@@ -15,9 +15,11 @@ class TrainingFeedback(Document):
|
|||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
training_event = frappe.get_doc("Training Event", self.training_event)
|
training_event = frappe.get_doc("Training Event", self.training_event)
|
||||||
|
status = None
|
||||||
for e in training_event.employees:
|
for e in training_event.employees:
|
||||||
if e.employee == self.employee:
|
if e.employee == self.employee:
|
||||||
training_event.status = 'Feedback Submitted'
|
status = 'Feedback Submitted'
|
||||||
break
|
break
|
||||||
|
|
||||||
training_event.save()
|
if status:
|
||||||
|
frappe.db.set_value("Training Event", self.training_event, "status", status)
|
||||||
|
|||||||
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
|
||||||
@@ -612,7 +612,8 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
|
|||||||
def postprocess(source, target):
|
def postprocess(source, target):
|
||||||
set_missing_values(source, target)
|
set_missing_values(source, target)
|
||||||
#Get the advance paid Journal Entries in Sales Invoice Advance
|
#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):
|
def set_missing_values(source, target):
|
||||||
target.is_pos = 0
|
target.is_pos = 0
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p
|
|||||||
|
|
||||||
|
|
||||||
if display_items_in_stock == 0:
|
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
|
i.is_stock_item, item_det.price_list_rate, item_det.currency
|
||||||
from `tabItem` i LEFT JOIN
|
from `tabItem` i LEFT JOIN
|
||||||
(select item_code, price_list_rate, currency from
|
(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
|
where
|
||||||
i.disabled = 0 and i.has_variants = 0 and i.is_sales_item = 1
|
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 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,
|
'item_code': item_code,
|
||||||
'price_list': price_list
|
'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:
|
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
|
i.is_stock_item, item_det.price_list_rate, item_det.currency
|
||||||
from `tabItem` i LEFT JOIN
|
from `tabItem` i LEFT JOIN
|
||||||
(select item_code, price_list_rate, currency from
|
(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
|
where
|
||||||
i.disabled = 0 and i.has_variants = 0 and i.is_sales_item = 1
|
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 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),
|
(start=start,page_length=page_length,lft=lft, rgt=rgt, condition=condition),
|
||||||
{
|
{
|
||||||
'item_code': item_code,
|
'item_code': item_code,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "name_and_employee_id",
|
"fieldname": "name_and_employee_id",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -54,6 +55,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "sales_person_name",
|
"fieldname": "sales_person_name",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -88,6 +90,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"description": "Select company name first.",
|
"description": "Select company name first.",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "parent_sales_person",
|
"fieldname": "parent_sales_person",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -122,6 +125,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "commission_rate",
|
"fieldname": "commission_rate",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -154,6 +158,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "is_group",
|
"fieldname": "is_group",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -189,6 +194,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"default": "1",
|
"default": "1",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "enabled",
|
"fieldname": "enabled",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -221,6 +227,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "cb0",
|
"fieldname": "cb0",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -251,6 +258,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "employee",
|
"fieldname": "employee",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -270,7 +278,7 @@
|
|||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"remember_last_selected_value": 0,
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 1,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
@@ -284,6 +292,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fetch_from": "employee.department",
|
"fetch_from": "employee.department",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "department",
|
"fieldname": "department",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -317,6 +326,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "lft",
|
"fieldname": "lft",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
@@ -350,6 +360,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "rgt",
|
"fieldname": "rgt",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
@@ -383,6 +394,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "old_parent",
|
"fieldname": "old_parent",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
@@ -417,6 +429,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"description": "Set targets Item Group-wise for this Sales Person.",
|
"description": "Set targets Item Group-wise for this Sales Person.",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "target_details_section_break",
|
"fieldname": "target_details_section_break",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -450,6 +463,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "targets",
|
"fieldname": "targets",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -485,6 +499,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"description": "Select Monthly Distribution to unevenly distribute targets across months.",
|
"description": "Select Monthly Distribution to unevenly distribute targets across months.",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "distribution_id",
|
"fieldname": "distribution_id",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -524,7 +539,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2019-01-30 11:28:16.966735",
|
"modified": "2019-04-09 20:03:35.967037",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Setup",
|
"module": "Setup",
|
||||||
"name": "Sales Person",
|
"name": "Sales Person",
|
||||||
@@ -594,7 +609,7 @@
|
|||||||
"search_fields": "parent_sales_person",
|
"search_fields": "parent_sales_person",
|
||||||
"show_name_in_global_search": 1,
|
"show_name_in_global_search": 1,
|
||||||
"sort_order": "ASC",
|
"sort_order": "ASC",
|
||||||
"track_changes": 1,
|
"track_changes": 0,
|
||||||
"track_seen": 0,
|
"track_seen": 0,
|
||||||
"track_views": 0
|
"track_views": 0
|
||||||
}
|
}
|
||||||
@@ -48,10 +48,11 @@ class SalesPerson(NestedSet):
|
|||||||
return frappe.db.get_value("User", user, "email") or user
|
return frappe.db.get_value("User", user, "email") or user
|
||||||
|
|
||||||
def validate_employee_id(self):
|
def validate_employee_id(self):
|
||||||
sales_person = frappe.db.get_value("Sales Person", {"employee": self.employee})
|
if self.employee:
|
||||||
|
sales_person = frappe.db.get_value("Sales Person", {"employee": self.employee})
|
||||||
|
|
||||||
if sales_person and sales_person != self.name:
|
if sales_person and sales_person != self.name:
|
||||||
frappe.throw(_("Another Sales Person {0} exists with the same Employee id").format(sales_person))
|
frappe.throw(_("Another Sales Person {0} exists with the same Employee id").format(sales_person))
|
||||||
|
|
||||||
def on_doctype_update():
|
def on_doctype_update():
|
||||||
frappe.db.add_index("Sales Person", ["lft", "rgt"])
|
frappe.db.add_index("Sales Person", ["lft", "rgt"])
|
||||||
@@ -97,5 +98,3 @@ def get_timeline_data(doctype, name):
|
|||||||
out[key] = delivery_note[key]
|
out[key] = delivery_note[key]
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -725,7 +725,7 @@ class Item(WebsiteGenerator):
|
|||||||
_('Cannot change Attributes after stock transaction. Make a new Item and transfer stock to the new Item'))
|
_('Cannot change Attributes after stock transaction. Make a new Item and transfer stock to the new Item'))
|
||||||
|
|
||||||
def validate_variant_based_on_change(self):
|
def validate_variant_based_on_change(self):
|
||||||
if self.variant_of or (self.has_variants and frappe.get_all("Item", {"variant_of": self.name})):
|
if not self.is_new() and (self.variant_of or (self.has_variants and frappe.get_all("Item", {"variant_of": self.name}))):
|
||||||
if self.variant_based_on != frappe.db.get_value("Item", self.name, "variant_based_on"):
|
if self.variant_based_on != frappe.db.get_value("Item", self.name, "variant_based_on"):
|
||||||
frappe.throw(_("Variant Based On cannot be changed"))
|
frappe.throw(_("Variant Based On cannot be changed"))
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
"item_attribute_values": [
|
"item_attribute_values": [
|
||||||
{"attribute_value": "Small", "abbr": "S"},
|
{"attribute_value": "Small", "abbr": "S"},
|
||||||
{"attribute_value": "Medium", "abbr": "M"},
|
{"attribute_value": "Medium", "abbr": "M"},
|
||||||
{"attribute_value": "Large", "abbr": "L"}
|
{"attribute_value": "Large", "abbr": "L"},
|
||||||
|
{"attribute_value": "Extra Small", "abbr": "XSL"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
{{doc.terms}}
|
{{doc.terms}}
|
||||||
</div>
|
</div>
|
||||||
<div class="cart-link">
|
<div class="cart-link">
|
||||||
<a href="#" onclick="show_terms();return false;">*{{ __("Terms and Conditions") }}</a>
|
<a href="#" onclick="show_terms();return false;">*{{ _("Terms and Conditions") }}</a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user