fix: merge conflict
This commit is contained in:
commit
e38192cb6d
23
.github/workflows/ci-tests.yml
vendored
23
.github/workflows/ci-tests.yml
vendored
@ -80,14 +80,29 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
TYPE: ${{ matrix.TYPE }}
|
TYPE: ${{ matrix.TYPE }}
|
||||||
|
|
||||||
- name: Coverage
|
- name: Coverage - Pull Request
|
||||||
if: matrix.TYPE == 'server'
|
if: matrix.TYPE == 'server' && github.event_name == 'pull_request'
|
||||||
run: |
|
run: |
|
||||||
cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE}
|
cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE}
|
||||||
cd ${GITHUB_WORKSPACE}
|
cd ${GITHUB_WORKSPACE}
|
||||||
pip install coveralls==3.0.1
|
pip install coveralls==2.2.0
|
||||||
pip install coverage==5.5
|
pip install coverage==4.5.4
|
||||||
coveralls --service=github
|
coveralls --service=github
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
|
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
|
||||||
|
COVERALLS_SERVICE_NAME: github
|
||||||
|
|
||||||
|
- name: Coverage - Push
|
||||||
|
if: matrix.TYPE == 'server' && github.event_name == 'push'
|
||||||
|
run: |
|
||||||
|
cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE}
|
||||||
|
cd ${GITHUB_WORKSPACE}
|
||||||
|
pip install coveralls==2.2.0
|
||||||
|
pip install coverage==4.5.4
|
||||||
|
coveralls --service=github-actions
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
|
||||||
|
COVERALLS_SERVICE_NAME: github-actions
|
||||||
|
|
||||||
|
@ -7,26 +7,30 @@
|
|||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"auto_accounting_for_stock",
|
"accounts_transactions_settings_section",
|
||||||
"acc_frozen_upto",
|
|
||||||
"frozen_accounts_modifier",
|
|
||||||
"determine_address_tax_category_from",
|
|
||||||
"over_billing_allowance",
|
"over_billing_allowance",
|
||||||
"role_allowed_to_over_bill",
|
"role_allowed_to_over_bill",
|
||||||
"column_break_4",
|
|
||||||
"credit_controller",
|
|
||||||
"check_supplier_invoice_uniqueness",
|
|
||||||
"make_payment_via_journal_entry",
|
"make_payment_via_journal_entry",
|
||||||
|
"column_break_11",
|
||||||
|
"check_supplier_invoice_uniqueness",
|
||||||
"unlink_payment_on_cancellation_of_invoice",
|
"unlink_payment_on_cancellation_of_invoice",
|
||||||
"unlink_advance_payment_on_cancelation_of_order",
|
|
||||||
"book_asset_depreciation_entry_automatically",
|
|
||||||
"add_taxes_from_item_tax_template",
|
|
||||||
"automatically_fetch_payment_terms",
|
"automatically_fetch_payment_terms",
|
||||||
"delete_linked_ledger_entries",
|
"delete_linked_ledger_entries",
|
||||||
|
"book_asset_depreciation_entry_automatically",
|
||||||
|
"unlink_advance_payment_on_cancelation_of_order",
|
||||||
|
"tax_settings_section",
|
||||||
|
"determine_address_tax_category_from",
|
||||||
|
"column_break_19",
|
||||||
|
"add_taxes_from_item_tax_template",
|
||||||
|
"period_closing_settings_section",
|
||||||
|
"acc_frozen_upto",
|
||||||
|
"frozen_accounts_modifier",
|
||||||
|
"column_break_4",
|
||||||
|
"credit_controller",
|
||||||
"deferred_accounting_settings_section",
|
"deferred_accounting_settings_section",
|
||||||
"automatically_process_deferred_accounting_entry",
|
|
||||||
"book_deferred_entries_based_on",
|
"book_deferred_entries_based_on",
|
||||||
"column_break_18",
|
"column_break_18",
|
||||||
|
"automatically_process_deferred_accounting_entry",
|
||||||
"book_deferred_entries_via_journal_entry",
|
"book_deferred_entries_via_journal_entry",
|
||||||
"submit_journal_entries",
|
"submit_journal_entries",
|
||||||
"print_settings",
|
"print_settings",
|
||||||
@ -40,15 +44,6 @@
|
|||||||
"use_custom_cash_flow"
|
"use_custom_cash_flow"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
|
||||||
"default": "1",
|
|
||||||
"description": "If enabled, the system will post accounting entries for inventory automatically",
|
|
||||||
"fieldname": "auto_accounting_for_stock",
|
|
||||||
"fieldtype": "Check",
|
|
||||||
"hidden": 1,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"label": "Make Accounting Entry For Every Stock Movement"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"description": "Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below",
|
"description": "Accounting entries are frozen up to this date. Nobody can create or modify entries except users with the role specified below",
|
||||||
"fieldname": "acc_frozen_upto",
|
"fieldname": "acc_frozen_upto",
|
||||||
@ -94,6 +89,7 @@
|
|||||||
"default": "0",
|
"default": "0",
|
||||||
"fieldname": "make_payment_via_journal_entry",
|
"fieldname": "make_payment_via_journal_entry",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
|
"hidden": 1,
|
||||||
"label": "Make Payment via Journal Entry"
|
"label": "Make Payment via Journal Entry"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -234,6 +230,29 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Role Allowed to Over Bill ",
|
"label": "Role Allowed to Over Bill ",
|
||||||
"options": "Role"
|
"options": "Role"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "period_closing_settings_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Period Closing Settings"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "accounts_transactions_settings_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Transactions Settings"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_11",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "tax_settings_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Tax Settings"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_19",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "icon-cog",
|
"icon": "icon-cog",
|
||||||
@ -241,7 +260,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-03-11 18:52:05.601996",
|
"modified": "2021-04-30 15:25:10.381008",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Accounts Settings",
|
"name": "Accounts Settings",
|
||||||
|
@ -42,9 +42,9 @@ class TestDunning(unittest.TestCase):
|
|||||||
['Sales - _TC', 0.0, 20.44]
|
['Sales - _TC', 0.0, 20.44]
|
||||||
])
|
])
|
||||||
for gle in gl_entries:
|
for gle in gl_entries:
|
||||||
self.assertEquals(expected_values[gle.account][0], gle.account)
|
self.assertEqual(expected_values[gle.account][0], gle.account)
|
||||||
self.assertEquals(expected_values[gle.account][1], gle.debit)
|
self.assertEqual(expected_values[gle.account][1], gle.debit)
|
||||||
self.assertEquals(expected_values[gle.account][2], gle.credit)
|
self.assertEqual(expected_values[gle.account][2], gle.credit)
|
||||||
|
|
||||||
def test_payment_entry(self):
|
def test_payment_entry(self):
|
||||||
dunning = create_dunning()
|
dunning = create_dunning()
|
||||||
|
@ -54,4 +54,4 @@ class TestGLEntry(unittest.TestCase):
|
|||||||
self.assertTrue(all(new.name != old.name for new, old in zip(gl_entries, new_gl_entries)))
|
self.assertTrue(all(new.name != old.name for new, old in zip(gl_entries, new_gl_entries)))
|
||||||
|
|
||||||
new_naming_series_current_value = frappe.db.sql("SELECT current from tabSeries where name = %s", naming_series)[0][0]
|
new_naming_series_current_value = frappe.db.sql("SELECT current from tabSeries where name = %s", naming_series)[0][0]
|
||||||
self.assertEquals(old_naming_series_current_value + 2, new_naming_series_current_value)
|
self.assertEqual(old_naming_series_current_value + 2, new_naming_series_current_value)
|
||||||
|
@ -1,87 +1,39 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_import": 0,
|
"creation": "2014-08-29 16:02:39.740505",
|
||||||
"allow_rename": 0,
|
"doctype": "DocType",
|
||||||
"beta": 0,
|
"editable_grid": 1,
|
||||||
"creation": "2014-08-29 16:02:39.740505",
|
"field_order": [
|
||||||
"custom": 0,
|
"company",
|
||||||
"docstatus": 0,
|
"account"
|
||||||
"doctype": "DocType",
|
],
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"fieldname": "company",
|
||||||
"bold": 0,
|
"fieldtype": "Link",
|
||||||
"collapsible": 0,
|
"in_list_view": 1,
|
||||||
"fieldname": "company",
|
"label": "Company",
|
||||||
"fieldtype": "Link",
|
"options": "Company",
|
||||||
"hidden": 0,
|
"reqd": 1
|
||||||
"ignore_user_permissions": 0,
|
},
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"label": "Company",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Company",
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"fieldname": "account",
|
||||||
"bold": 0,
|
"fieldtype": "Link",
|
||||||
"collapsible": 0,
|
"in_list_view": 1,
|
||||||
"fieldname": "account",
|
"label": "Account",
|
||||||
"fieldtype": "Link",
|
"options": "Account"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"label": "Account",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Account",
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"hide_heading": 0,
|
"index_web_pages_for_search": 1,
|
||||||
"hide_toolbar": 0,
|
"istable": 1,
|
||||||
"idx": 0,
|
"links": [],
|
||||||
"image_view": 0,
|
"modified": "2021-04-07 18:13:08.833822",
|
||||||
"in_create": 0,
|
"modified_by": "Administrator",
|
||||||
|
"module": "Accounts",
|
||||||
"is_submittable": 0,
|
"name": "Party Account",
|
||||||
"issingle": 0,
|
"owner": "Administrator",
|
||||||
"istable": 1,
|
"permissions": [],
|
||||||
"max_attachments": 0,
|
"quick_entry": 1,
|
||||||
"modified": "2016-07-11 03:28:03.348246",
|
"sort_field": "modified",
|
||||||
"modified_by": "Administrator",
|
"sort_order": "DESC"
|
||||||
"module": "Accounts",
|
|
||||||
"name": "Party Account",
|
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"permissions": [],
|
|
||||||
"quick_entry": 1,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"sort_field": "modified",
|
|
||||||
"sort_order": "DESC",
|
|
||||||
"track_seen": 0
|
|
||||||
}
|
}
|
@ -31,10 +31,10 @@ class TestPaymentOrder(unittest.TestCase):
|
|||||||
|
|
||||||
doc = create_payment_order_against_payment_entry(payment_entry, "Payment Entry")
|
doc = create_payment_order_against_payment_entry(payment_entry, "Payment Entry")
|
||||||
reference_doc = doc.get("references")[0]
|
reference_doc = doc.get("references")[0]
|
||||||
self.assertEquals(reference_doc.reference_name, payment_entry.name)
|
self.assertEqual(reference_doc.reference_name, payment_entry.name)
|
||||||
self.assertEquals(reference_doc.reference_doctype, "Payment Entry")
|
self.assertEqual(reference_doc.reference_doctype, "Payment Entry")
|
||||||
self.assertEquals(reference_doc.supplier, "_Test Supplier")
|
self.assertEqual(reference_doc.supplier, "_Test Supplier")
|
||||||
self.assertEquals(reference_doc.amount, 250)
|
self.assertEqual(reference_doc.amount, 250)
|
||||||
|
|
||||||
def create_payment_order_against_payment_entry(ref_doc, order_type):
|
def create_payment_order_against_payment_entry(ref_doc, order_type):
|
||||||
payment_order = frappe.get_doc(dict(
|
payment_order = frappe.get_doc(dict(
|
||||||
|
@ -114,7 +114,7 @@ class PaymentReconciliation(Document):
|
|||||||
'party_type': self.party_type,
|
'party_type': self.party_type,
|
||||||
'voucher_type': voucher_type,
|
'voucher_type': voucher_type,
|
||||||
'account': self.receivable_payable_account
|
'account': self.receivable_payable_account
|
||||||
}, as_dict=1, debug=1)
|
}, as_dict=1)
|
||||||
|
|
||||||
def add_payment_entries(self, entries):
|
def add_payment_entries(self, entries):
|
||||||
self.set('payments', [])
|
self.set('payments', [])
|
||||||
|
@ -461,7 +461,17 @@ def get_stock_availability(item_code, warehouse):
|
|||||||
order by posting_date desc, posting_time desc
|
order by posting_date desc, posting_time desc
|
||||||
limit 1""", (item_code, warehouse), as_dict=1)
|
limit 1""", (item_code, warehouse), as_dict=1)
|
||||||
|
|
||||||
pos_sales_qty = frappe.db.sql("""select sum(p_item.qty) as qty
|
pos_sales_qty = get_pos_reserved_qty(item_code, warehouse)
|
||||||
|
|
||||||
|
sle_qty = latest_sle[0].qty_after_transaction or 0 if latest_sle else 0
|
||||||
|
|
||||||
|
if sle_qty and pos_sales_qty:
|
||||||
|
return sle_qty - pos_sales_qty
|
||||||
|
else:
|
||||||
|
return sle_qty
|
||||||
|
|
||||||
|
def get_pos_reserved_qty(item_code, warehouse):
|
||||||
|
reserved_qty = frappe.db.sql("""select sum(p_item.qty) as qty
|
||||||
from `tabPOS Invoice` p, `tabPOS Invoice Item` p_item
|
from `tabPOS Invoice` p, `tabPOS Invoice Item` p_item
|
||||||
where p.name = p_item.parent
|
where p.name = p_item.parent
|
||||||
and p.consolidated_invoice is NULL
|
and p.consolidated_invoice is NULL
|
||||||
@ -470,14 +480,8 @@ def get_stock_availability(item_code, warehouse):
|
|||||||
and p_item.item_code = %s
|
and p_item.item_code = %s
|
||||||
and p_item.warehouse = %s
|
and p_item.warehouse = %s
|
||||||
""", (item_code, warehouse), as_dict=1)
|
""", (item_code, warehouse), as_dict=1)
|
||||||
|
|
||||||
sle_qty = latest_sle[0].qty_after_transaction or 0 if latest_sle else 0
|
return reserved_qty[0].qty or 0 if reserved_qty else 0
|
||||||
pos_sales_qty = pos_sales_qty[0].qty or 0 if pos_sales_qty else 0
|
|
||||||
|
|
||||||
if sle_qty and pos_sales_qty:
|
|
||||||
return sle_qty - pos_sales_qty
|
|
||||||
else:
|
|
||||||
return sle_qty
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def make_sales_return(source_name, target_doc=None):
|
def make_sales_return(source_name, target_doc=None):
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"creation": "2021-04-19 14:56:06.652327",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"field",
|
||||||
|
"fieldname"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "fieldname",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Fieldname"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "field",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Field"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"istable": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2021-04-21 11:12:54.632093",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Accounts",
|
||||||
|
"name": "POS Search Fields",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [],
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"track_changes": 1
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
class POSSearchFields(Document):
|
||||||
|
pass
|
@ -1,9 +1,17 @@
|
|||||||
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
// For license information, please see license.txt
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
let search_fields_datatypes = ['Data', 'Link', 'Dynamic Link', 'Long Text', 'Select', 'Small Text', 'Text', 'Text Editor'];
|
||||||
|
let do_not_include_fields = ["naming_series", "item_code", "item_name", "stock_uom", "hub_sync_id", "asset_naming_series",
|
||||||
|
"default_material_request_type", "valuation_method", "warranty_period", "weight_uom", "batch_number_series",
|
||||||
|
"serial_no_series", "purchase_uom", "customs_tariff_number", "sales_uom", "deferred_revenue_account",
|
||||||
|
"deferred_expense_account", "quality_inspection_template", "route", "slideshow", "website_image_alt", "thumbnail",
|
||||||
|
"web_long_description", "hub_sync_id"]
|
||||||
|
|
||||||
frappe.ui.form.on('POS Settings', {
|
frappe.ui.form.on('POS Settings', {
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
frm.trigger("get_invoice_fields");
|
frm.trigger("get_invoice_fields");
|
||||||
|
frm.trigger("add_search_options");
|
||||||
},
|
},
|
||||||
|
|
||||||
get_invoice_fields: function(frm) {
|
get_invoice_fields: function(frm) {
|
||||||
@ -21,6 +29,38 @@ frappe.ui.form.on('POS Settings', {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
add_search_options: function(frm) {
|
||||||
|
frappe.model.with_doctype("Item", () => {
|
||||||
|
var fields = $.map(frappe.get_doc("DocType", "Item").fields, function(d) {
|
||||||
|
if (search_fields_datatypes.includes(d.fieldtype) && !(do_not_include_fields.includes(d.fieldname))) {
|
||||||
|
return [d.label];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fields.unshift('');
|
||||||
|
frm.fields_dict.pos_search_fields.grid.update_docfield_property('field', 'options', fields);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
frappe.ui.form.on("POS Search Fields", {
|
||||||
|
field: function(frm, doctype, name) {
|
||||||
|
var doc = frappe.get_doc(doctype, name);
|
||||||
|
var df = $.map(frappe.get_doc("DocType", "Item").fields, function(d) {
|
||||||
|
if (doc.field == d.label && search_fields_datatypes.includes(d.fieldtype)) {
|
||||||
|
return d;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})[0];
|
||||||
|
|
||||||
|
doc.fieldname = df.fieldname;
|
||||||
|
frm.refresh_field("fields");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -5,7 +5,8 @@
|
|||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"invoice_fields"
|
"invoice_fields",
|
||||||
|
"pos_search_fields"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -13,11 +14,17 @@
|
|||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"label": "POS Field",
|
"label": "POS Field",
|
||||||
"options": "POS Field"
|
"options": "POS Field"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "pos_search_fields",
|
||||||
|
"fieldtype": "Table",
|
||||||
|
"label": "POS Search Fields",
|
||||||
|
"options": "POS Search Fields"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-06-01 15:46:41.478928",
|
"modified": "2021-04-19 14:56:24.465218",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "POS Settings",
|
"name": "POS Settings",
|
||||||
|
@ -99,7 +99,7 @@ class TestPricingRule(unittest.TestCase):
|
|||||||
|
|
||||||
args.item_code = "_Test Item 2"
|
args.item_code = "_Test Item 2"
|
||||||
details = get_item_details(args)
|
details = get_item_details(args)
|
||||||
self.assertEquals(details.get("discount_percentage"), 15)
|
self.assertEqual(details.get("discount_percentage"), 15)
|
||||||
|
|
||||||
def test_pricing_rule_for_margin(self):
|
def test_pricing_rule_for_margin(self):
|
||||||
from erpnext.stock.get_item_details import get_item_details
|
from erpnext.stock.get_item_details import get_item_details
|
||||||
@ -145,8 +145,8 @@ class TestPricingRule(unittest.TestCase):
|
|||||||
"name": None
|
"name": None
|
||||||
})
|
})
|
||||||
details = get_item_details(args)
|
details = get_item_details(args)
|
||||||
self.assertEquals(details.get("margin_type"), "Percentage")
|
self.assertEqual(details.get("margin_type"), "Percentage")
|
||||||
self.assertEquals(details.get("margin_rate_or_amount"), 10)
|
self.assertEqual(details.get("margin_rate_or_amount"), 10)
|
||||||
|
|
||||||
def test_mixed_conditions_for_item_group(self):
|
def test_mixed_conditions_for_item_group(self):
|
||||||
for item in ["Mixed Cond Item 1", "Mixed Cond Item 2"]:
|
for item in ["Mixed Cond Item 1", "Mixed Cond Item 2"]:
|
||||||
@ -192,7 +192,7 @@ class TestPricingRule(unittest.TestCase):
|
|||||||
"name": None
|
"name": None
|
||||||
})
|
})
|
||||||
details = get_item_details(args)
|
details = get_item_details(args)
|
||||||
self.assertEquals(details.get("discount_percentage"), 10)
|
self.assertEqual(details.get("discount_percentage"), 10)
|
||||||
|
|
||||||
def test_pricing_rule_for_variants(self):
|
def test_pricing_rule_for_variants(self):
|
||||||
from erpnext.stock.get_item_details import get_item_details
|
from erpnext.stock.get_item_details import get_item_details
|
||||||
@ -322,11 +322,11 @@ class TestPricingRule(unittest.TestCase):
|
|||||||
si.insert(ignore_permissions=True)
|
si.insert(ignore_permissions=True)
|
||||||
|
|
||||||
item = si.items[0]
|
item = si.items[0]
|
||||||
self.assertEquals(item.margin_rate_or_amount, 10)
|
self.assertEqual(item.margin_rate_or_amount, 10)
|
||||||
self.assertEquals(item.rate_with_margin, 1100)
|
self.assertEqual(item.rate_with_margin, 1100)
|
||||||
self.assertEqual(item.discount_percentage, 10)
|
self.assertEqual(item.discount_percentage, 10)
|
||||||
self.assertEquals(item.discount_amount, 110)
|
self.assertEqual(item.discount_amount, 110)
|
||||||
self.assertEquals(item.rate, 990)
|
self.assertEqual(item.rate, 990)
|
||||||
|
|
||||||
def test_pricing_rule_with_margin_and_discount_amount(self):
|
def test_pricing_rule_with_margin_and_discount_amount(self):
|
||||||
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
|
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
|
||||||
@ -338,10 +338,10 @@ class TestPricingRule(unittest.TestCase):
|
|||||||
si.insert(ignore_permissions=True)
|
si.insert(ignore_permissions=True)
|
||||||
|
|
||||||
item = si.items[0]
|
item = si.items[0]
|
||||||
self.assertEquals(item.margin_rate_or_amount, 10)
|
self.assertEqual(item.margin_rate_or_amount, 10)
|
||||||
self.assertEquals(item.rate_with_margin, 1100)
|
self.assertEqual(item.rate_with_margin, 1100)
|
||||||
self.assertEquals(item.discount_amount, 110)
|
self.assertEqual(item.discount_amount, 110)
|
||||||
self.assertEquals(item.rate, 990)
|
self.assertEqual(item.rate, 990)
|
||||||
|
|
||||||
def test_pricing_rule_for_product_discount_on_same_item(self):
|
def test_pricing_rule_for_product_discount_on_same_item(self):
|
||||||
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
|
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
|
||||||
@ -458,21 +458,21 @@ class TestPricingRule(unittest.TestCase):
|
|||||||
si.items[0].price_list_rate = 1000
|
si.items[0].price_list_rate = 1000
|
||||||
si.submit()
|
si.submit()
|
||||||
item = si.items[0]
|
item = si.items[0]
|
||||||
self.assertEquals(item.rate, 100)
|
self.assertEqual(item.rate, 100)
|
||||||
|
|
||||||
# Correct Customer and Incorrect is_return value
|
# Correct Customer and Incorrect is_return value
|
||||||
si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", is_return=1, qty=-1)
|
si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", is_return=1, qty=-1)
|
||||||
si.items[0].price_list_rate = 1000
|
si.items[0].price_list_rate = 1000
|
||||||
si.submit()
|
si.submit()
|
||||||
item = si.items[0]
|
item = si.items[0]
|
||||||
self.assertEquals(item.rate, 100)
|
self.assertEqual(item.rate, 100)
|
||||||
|
|
||||||
# Correct Customer and correct is_return value
|
# Correct Customer and correct is_return value
|
||||||
si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", is_return=0)
|
si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", is_return=0)
|
||||||
si.items[0].price_list_rate = 1000
|
si.items[0].price_list_rate = 1000
|
||||||
si.submit()
|
si.submit()
|
||||||
item = si.items[0]
|
item = si.items[0]
|
||||||
self.assertEquals(item.rate, 900)
|
self.assertEqual(item.rate, 900)
|
||||||
|
|
||||||
def test_multiple_pricing_rules(self):
|
def test_multiple_pricing_rules(self):
|
||||||
make_pricing_rule(discount_percentage=20, selling=1, priority=1, apply_multiple_pricing_rules=1,
|
make_pricing_rule(discount_percentage=20, selling=1, priority=1, apply_multiple_pricing_rules=1,
|
||||||
@ -545,11 +545,11 @@ class TestPricingRule(unittest.TestCase):
|
|||||||
apply_on="Transaction", free_item="Water Flask 1", free_qty=1, free_item_rate=10)
|
apply_on="Transaction", free_item="Water Flask 1", free_qty=1, free_item_rate=10)
|
||||||
|
|
||||||
si = create_sales_invoice(qty=5, do_not_submit=True)
|
si = create_sales_invoice(qty=5, do_not_submit=True)
|
||||||
self.assertEquals(len(si.items), 2)
|
self.assertEqual(len(si.items), 2)
|
||||||
self.assertEquals(si.items[1].rate, 10)
|
self.assertEqual(si.items[1].rate, 10)
|
||||||
|
|
||||||
si1 = create_sales_invoice(qty=2, do_not_submit=True)
|
si1 = create_sales_invoice(qty=2, do_not_submit=True)
|
||||||
self.assertEquals(len(si1.items), 1)
|
self.assertEqual(len(si1.items), 1)
|
||||||
|
|
||||||
for doc in [si, si1]:
|
for doc in [si, si1]:
|
||||||
doc.delete()
|
doc.delete()
|
||||||
|
@ -514,6 +514,28 @@ frappe.ui.form.on("Purchase Invoice", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
refresh: function(frm) {
|
||||||
|
frm.events.add_custom_buttons(frm);
|
||||||
|
},
|
||||||
|
|
||||||
|
add_custom_buttons: function(frm) {
|
||||||
|
if (frm.doc.per_received < 100) {
|
||||||
|
frm.add_custom_button(__('Purchase Receipt'), () => {
|
||||||
|
frm.events.make_purchase_receipt(frm);
|
||||||
|
}, __('Create'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frm.doc.docstatus == 1 && frm.doc.per_received > 0) {
|
||||||
|
frm.add_custom_button(__('Purchase Receipt'), () => {
|
||||||
|
frappe.route_options = {
|
||||||
|
'purchase_invoice': frm.doc.name
|
||||||
|
}
|
||||||
|
|
||||||
|
frappe.set_route("List", "Purchase Receipt", "List")
|
||||||
|
}, __('View'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
if(frm.doc.__onload && frm.is_new()) {
|
if(frm.doc.__onload && frm.is_new()) {
|
||||||
if(frm.doc.supplier) {
|
if(frm.doc.supplier) {
|
||||||
@ -539,5 +561,13 @@ frappe.ui.form.on("Purchase Invoice", {
|
|||||||
update_stock: function(frm) {
|
update_stock: function(frm) {
|
||||||
hide_fields(frm.doc);
|
hide_fields(frm.doc);
|
||||||
frm.fields_dict.items.grid.toggle_reqd("item_code", frm.doc.update_stock? true: false);
|
frm.fields_dict.items.grid.toggle_reqd("item_code", frm.doc.update_stock? true: false);
|
||||||
|
},
|
||||||
|
|
||||||
|
make_purchase_receipt: function(frm) {
|
||||||
|
frappe.model.open_mapped_doc({
|
||||||
|
method: "erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_purchase_receipt",
|
||||||
|
frm: frm,
|
||||||
|
freeze_message: __("Creating Purchase Receipt ...")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -163,7 +163,8 @@
|
|||||||
"to_date",
|
"to_date",
|
||||||
"column_break_114",
|
"column_break_114",
|
||||||
"auto_repeat",
|
"auto_repeat",
|
||||||
"update_auto_repeat_reference"
|
"update_auto_repeat_reference",
|
||||||
|
"per_received"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -1364,6 +1365,15 @@
|
|||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_width": "50px",
|
"print_width": "50px",
|
||||||
"width": "50px"
|
"width": "50px"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "per_received",
|
||||||
|
"fieldtype": "Percent",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Per Received",
|
||||||
|
"no_copy": 1,
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-file-text",
|
"icon": "fa fa-file-text",
|
||||||
|
@ -1207,3 +1207,41 @@ def make_inter_company_sales_invoice(source_name, target_doc=None):
|
|||||||
|
|
||||||
def on_doctype_update():
|
def on_doctype_update():
|
||||||
frappe.db.add_index("Purchase Invoice", ["supplier", "is_return", "return_against"])
|
frappe.db.add_index("Purchase Invoice", ["supplier", "is_return", "return_against"])
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def make_purchase_receipt(source_name, target_doc=None):
|
||||||
|
def update_item(obj, target, source_parent):
|
||||||
|
target.qty = flt(obj.qty) - flt(obj.received_qty)
|
||||||
|
target.received_qty = flt(obj.qty) - flt(obj.received_qty)
|
||||||
|
target.stock_qty = (flt(obj.qty) - flt(obj.received_qty)) * flt(obj.conversion_factor)
|
||||||
|
target.amount = (flt(obj.qty) - flt(obj.received_qty)) * flt(obj.rate)
|
||||||
|
target.base_amount = (flt(obj.qty) - flt(obj.received_qty)) * \
|
||||||
|
flt(obj.rate) * flt(source_parent.conversion_rate)
|
||||||
|
|
||||||
|
doc = get_mapped_doc("Purchase Invoice", source_name, {
|
||||||
|
"Purchase Invoice": {
|
||||||
|
"doctype": "Purchase Receipt",
|
||||||
|
"validation": {
|
||||||
|
"docstatus": ["=", 1],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Purchase Invoice Item": {
|
||||||
|
"doctype": "Purchase Receipt Item",
|
||||||
|
"field_map": {
|
||||||
|
"name": "purchase_invoice_item",
|
||||||
|
"parent": "purchase_invoice",
|
||||||
|
"bom": "bom",
|
||||||
|
"purchase_order": "purchase_order",
|
||||||
|
"po_detail": "purchase_order_item",
|
||||||
|
"material_request": "material_request",
|
||||||
|
"material_request_item": "material_request_item"
|
||||||
|
},
|
||||||
|
"postprocess": update_item,
|
||||||
|
"condition": lambda doc: abs(doc.received_qty) < abs(doc.qty)
|
||||||
|
},
|
||||||
|
"Purchase Taxes and Charges": {
|
||||||
|
"doctype": "Purchase Taxes and Charges"
|
||||||
|
}
|
||||||
|
}, target_doc)
|
||||||
|
|
||||||
|
return doc
|
||||||
|
@ -607,6 +607,7 @@
|
|||||||
"oldfieldname": "purchase_order",
|
"oldfieldname": "purchase_order",
|
||||||
"oldfieldtype": "Link",
|
"oldfieldtype": "Link",
|
||||||
"options": "Purchase Order",
|
"options": "Purchase Order",
|
||||||
|
"print_hide": 1,
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
"search_index": 1
|
"search_index": 1
|
||||||
},
|
},
|
||||||
@ -853,7 +854,7 @@
|
|||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-02-23 00:59:52.614805",
|
"modified": "2021-03-30 09:02:39.256602",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Purchase Invoice Item",
|
"name": "Purchase Invoice Item",
|
||||||
|
@ -356,11 +356,11 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
|||||||
},
|
},
|
||||||
|
|
||||||
items_on_form_rendered: function() {
|
items_on_form_rendered: function() {
|
||||||
erpnext.setup_serial_no();
|
erpnext.setup_serial_or_batch_no();
|
||||||
},
|
},
|
||||||
|
|
||||||
packed_items_on_form_rendered: function(doc, grid_row) {
|
packed_items_on_form_rendered: function(doc, grid_row) {
|
||||||
erpnext.setup_serial_no();
|
erpnext.setup_serial_or_batch_no();
|
||||||
},
|
},
|
||||||
|
|
||||||
make_sales_return: function() {
|
make_sales_return: function() {
|
||||||
|
@ -1111,7 +1111,7 @@ class SalesInvoice(SellingController):
|
|||||||
if not item.serial_no:
|
if not item.serial_no:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for serial_no in item.serial_no.split("\n"):
|
for serial_no in get_serial_nos(item.serial_no):
|
||||||
if serial_no and frappe.db.get_value('Serial No', serial_no, 'item_code') == item.item_code:
|
if serial_no and frappe.db.get_value('Serial No', serial_no, 'item_code') == item.item_code:
|
||||||
frappe.db.set_value('Serial No', serial_no, 'sales_invoice', invoice)
|
frappe.db.set_value('Serial No', serial_no, 'sales_invoice', invoice)
|
||||||
|
|
||||||
@ -1755,15 +1755,10 @@ def update_pr_items(doc, sales_item_map, purchase_item_map, parent_child_map, wa
|
|||||||
item.purchase_order = parent_child_map.get(sales_item_map.get(item.delivery_note_item))
|
item.purchase_order = parent_child_map.get(sales_item_map.get(item.delivery_note_item))
|
||||||
|
|
||||||
def get_delivery_note_details(internal_reference):
|
def get_delivery_note_details(internal_reference):
|
||||||
so_item_map = {}
|
|
||||||
|
|
||||||
si_item_details = frappe.get_all('Delivery Note Item', fields=['name', 'so_detail'],
|
si_item_details = frappe.get_all('Delivery Note Item', fields=['name', 'so_detail'],
|
||||||
filters={'parent': internal_reference})
|
filters={'parent': internal_reference})
|
||||||
|
|
||||||
for d in si_item_details:
|
return {d.name: d.so_detail for d in si_item_details if d.so_detail}
|
||||||
so_item_map.setdefault(d.name, d.so_detail)
|
|
||||||
|
|
||||||
return so_item_map
|
|
||||||
|
|
||||||
def get_sales_invoice_details(internal_reference):
|
def get_sales_invoice_details(internal_reference):
|
||||||
dn_item_map = {}
|
dn_item_map = {}
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
"additional_discount_percentage",
|
"additional_discount_percentage",
|
||||||
"additional_discount_amount",
|
"additional_discount_amount",
|
||||||
"sb_3",
|
"sb_3",
|
||||||
|
"submit_invoice",
|
||||||
"invoices",
|
"invoices",
|
||||||
"accounting_dimensions_section",
|
"accounting_dimensions_section",
|
||||||
"cost_center",
|
"cost_center",
|
||||||
@ -45,9 +46,7 @@
|
|||||||
{
|
{
|
||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
"fieldname": "cb_1",
|
"fieldname": "cb_1",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "status",
|
"fieldname": "status",
|
||||||
@ -55,97 +54,73 @@
|
|||||||
"label": "Status",
|
"label": "Status",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "\nTrialling\nActive\nPast Due Date\nCancelled\nUnpaid\nCompleted",
|
"options": "\nTrialling\nActive\nPast Due Date\nCancelled\nUnpaid\nCompleted",
|
||||||
"read_only": 1,
|
"read_only": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "subscription_period",
|
"fieldname": "subscription_period",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Subscription Period",
|
"label": "Subscription Period"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "cancelation_date",
|
"fieldname": "cancelation_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"label": "Cancelation Date",
|
"label": "Cancelation Date",
|
||||||
"read_only": 1,
|
"read_only": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
"fieldname": "trial_period_start",
|
"fieldname": "trial_period_start",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"label": "Trial Period Start Date",
|
"label": "Trial Period Start Date",
|
||||||
"set_only_once": 1,
|
"set_only_once": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:doc.trial_period_start",
|
"depends_on": "eval:doc.trial_period_start",
|
||||||
"fieldname": "trial_period_end",
|
"fieldname": "trial_period_end",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"label": "Trial Period End Date",
|
"label": "Trial Period End Date",
|
||||||
"set_only_once": 1,
|
"set_only_once": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_11",
|
"fieldname": "column_break_11",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "current_invoice_start",
|
"fieldname": "current_invoice_start",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"label": "Current Invoice Start Date",
|
"label": "Current Invoice Start Date",
|
||||||
"read_only": 1,
|
"read_only": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "current_invoice_end",
|
"fieldname": "current_invoice_end",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"label": "Current Invoice End Date",
|
"label": "Current Invoice End Date",
|
||||||
"read_only": 1,
|
"read_only": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"description": "Number of days that the subscriber has to pay invoices generated by this subscription",
|
"description": "Number of days that the subscriber has to pay invoices generated by this subscription",
|
||||||
"fieldname": "days_until_due",
|
"fieldname": "days_until_due",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"label": "Days Until Due",
|
"label": "Days Until Due"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"fieldname": "cancel_at_period_end",
|
"fieldname": "cancel_at_period_end",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Cancel At End Of Period",
|
"label": "Cancel At End Of Period"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"fieldname": "generate_invoice_at_period_start",
|
"fieldname": "generate_invoice_at_period_start",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Generate Invoice At Beginning Of Period",
|
"label": "Generate Invoice At Beginning Of Period"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
"fieldname": "sb_4",
|
"fieldname": "sb_4",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Plans",
|
"label": "Plans"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
@ -153,84 +128,62 @@
|
|||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"label": "Plans",
|
"label": "Plans",
|
||||||
"options": "Subscription Plan Detail",
|
"options": "Subscription Plan Detail",
|
||||||
"reqd": 1,
|
"reqd": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:['Customer', 'Supplier'].includes(doc.party_type)",
|
"depends_on": "eval:['Customer', 'Supplier'].includes(doc.party_type)",
|
||||||
"fieldname": "sb_1",
|
"fieldname": "sb_1",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Taxes",
|
"label": "Taxes"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "sb_2",
|
"fieldname": "sb_2",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Discounts",
|
"label": "Discounts"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "apply_additional_discount",
|
"fieldname": "apply_additional_discount",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"label": "Apply Additional Discount On",
|
"label": "Apply Additional Discount On",
|
||||||
"options": "\nGrand Total\nNet Total",
|
"options": "\nGrand Total\nNet Total"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "cb_2",
|
"fieldname": "cb_2",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "additional_discount_percentage",
|
"fieldname": "additional_discount_percentage",
|
||||||
"fieldtype": "Percent",
|
"fieldtype": "Percent",
|
||||||
"label": "Additional DIscount Percentage",
|
"label": "Additional DIscount Percentage"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"fieldname": "additional_discount_amount",
|
"fieldname": "additional_discount_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Additional DIscount Amount",
|
"label": "Additional DIscount Amount"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:doc.invoices",
|
"depends_on": "eval:doc.invoices",
|
||||||
"fieldname": "sb_3",
|
"fieldname": "sb_3",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Invoices",
|
"label": "Invoices"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"fieldname": "invoices",
|
"fieldname": "invoices",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"label": "Invoices",
|
"label": "Invoices",
|
||||||
"options": "Subscription Invoice",
|
"options": "Subscription Invoice"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"fieldname": "accounting_dimensions_section",
|
"fieldname": "accounting_dimensions_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Accounting Dimensions",
|
"label": "Accounting Dimensions"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "dimension_col_break",
|
"fieldname": "dimension_col_break",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "party_type",
|
"fieldname": "party_type",
|
||||||
@ -238,9 +191,7 @@
|
|||||||
"label": "Party Type",
|
"label": "Party Type",
|
||||||
"options": "DocType",
|
"options": "DocType",
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"set_only_once": 1,
|
"set_only_once": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "party",
|
"fieldname": "party",
|
||||||
@ -249,27 +200,21 @@
|
|||||||
"label": "Party",
|
"label": "Party",
|
||||||
"options": "party_type",
|
"options": "party_type",
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"set_only_once": 1,
|
"set_only_once": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:doc.party_type === 'Customer'",
|
"depends_on": "eval:doc.party_type === 'Customer'",
|
||||||
"fieldname": "sales_tax_template",
|
"fieldname": "sales_tax_template",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Sales Taxes and Charges Template",
|
"label": "Sales Taxes and Charges Template",
|
||||||
"options": "Sales Taxes and Charges Template",
|
"options": "Sales Taxes and Charges Template"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:doc.party_type === 'Supplier'",
|
"depends_on": "eval:doc.party_type === 'Supplier'",
|
||||||
"fieldname": "purchase_tax_template",
|
"fieldname": "purchase_tax_template",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Purchase Taxes and Charges Template",
|
"label": "Purchase Taxes and Charges Template",
|
||||||
"options": "Purchase Taxes and Charges Template",
|
"options": "Purchase Taxes and Charges Template"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
@ -277,55 +222,49 @@
|
|||||||
"fieldname": "follow_calendar_months",
|
"fieldname": "follow_calendar_months",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Follow Calendar Months",
|
"label": "Follow Calendar Months",
|
||||||
"set_only_once": 1,
|
"set_only_once": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"description": "New invoices will be generated as per schedule even if current invoices are unpaid or past due date",
|
"description": "New invoices will be generated as per schedule even if current invoices are unpaid or past due date",
|
||||||
"fieldname": "generate_new_invoices_past_due_date",
|
"fieldname": "generate_new_invoices_past_due_date",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Generate New Invoices Past Due Date",
|
"label": "Generate New Invoices Past Due Date"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "end_date",
|
"fieldname": "end_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"label": "Subscription End Date",
|
"label": "Subscription End Date",
|
||||||
"set_only_once": 1,
|
"set_only_once": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "start_date",
|
"fieldname": "start_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"label": "Subscription Start Date",
|
"label": "Subscription Start Date",
|
||||||
"set_only_once": 1,
|
"set_only_once": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "cost_center",
|
"fieldname": "cost_center",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Cost Center",
|
"label": "Cost Center",
|
||||||
"options": "Cost Center",
|
"options": "Cost Center"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "company",
|
"fieldname": "company",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Company",
|
"label": "Company",
|
||||||
"options": "Company",
|
"options": "Company"
|
||||||
"show_days": 1,
|
},
|
||||||
"show_seconds": 1
|
{
|
||||||
|
"default": "1",
|
||||||
|
"fieldname": "submit_invoice",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Submit Invoice Automatically"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-02-09 15:44:20.024789",
|
"modified": "2021-04-19 15:24:27.550797",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Subscription",
|
"name": "Subscription",
|
||||||
|
@ -276,7 +276,7 @@ class Subscription(Document):
|
|||||||
frappe.throw(_('Subscription End Date is mandatory to follow calendar months'))
|
frappe.throw(_('Subscription End Date is mandatory to follow calendar months'))
|
||||||
|
|
||||||
if billing_info[0]['billing_interval'] != 'Month':
|
if billing_info[0]['billing_interval'] != 'Month':
|
||||||
frappe.throw('Billing Interval in Subscription Plan must be Month to follow calendar months')
|
frappe.throw(_('Billing Interval in Subscription Plan must be Month to follow calendar months'))
|
||||||
|
|
||||||
def after_insert(self):
|
def after_insert(self):
|
||||||
# todo: deal with users who collect prepayments. Maybe a new Subscription Invoice doctype?
|
# todo: deal with users who collect prepayments. Maybe a new Subscription Invoice doctype?
|
||||||
@ -383,7 +383,9 @@ class Subscription(Document):
|
|||||||
|
|
||||||
invoice.flags.ignore_mandatory = True
|
invoice.flags.ignore_mandatory = True
|
||||||
invoice.save()
|
invoice.save()
|
||||||
invoice.submit()
|
|
||||||
|
if self.submit_invoice:
|
||||||
|
invoice.submit()
|
||||||
|
|
||||||
return invoice
|
return invoice
|
||||||
|
|
||||||
|
@ -21,7 +21,10 @@ def get_party_details(inv):
|
|||||||
else:
|
else:
|
||||||
party_type = 'Supplier'
|
party_type = 'Supplier'
|
||||||
party = inv.supplier
|
party = inv.supplier
|
||||||
|
|
||||||
|
if not party:
|
||||||
|
frappe.throw(_("Please select {0} first").format(party_type))
|
||||||
|
|
||||||
return party_type, party
|
return party_type, party
|
||||||
|
|
||||||
def get_party_tax_withholding_details(inv, tax_withholding_category=None):
|
def get_party_tax_withholding_details(inv, tax_withholding_category=None):
|
||||||
@ -324,7 +327,7 @@ def get_tds_amount_from_ldc(ldc, parties, fiscal_year, pan_no, tax_details, post
|
|||||||
net_total, ldc.certificate_limit
|
net_total, ldc.certificate_limit
|
||||||
):
|
):
|
||||||
tds_amount = get_ltds_amount(net_total, limit_consumed, ldc.certificate_limit, ldc.rate, tax_details)
|
tds_amount = get_ltds_amount(net_total, limit_consumed, ldc.certificate_limit, ldc.rate, tax_details)
|
||||||
|
|
||||||
return tds_amount
|
return tds_amount
|
||||||
|
|
||||||
def get_debit_note_amount(suppliers, fiscal_year_details, company=None):
|
def get_debit_note_amount(suppliers, fiscal_year_details, company=None):
|
||||||
|
@ -171,7 +171,7 @@ def round_off_debit_credit(gl_map):
|
|||||||
else:
|
else:
|
||||||
allowance = .5
|
allowance = .5
|
||||||
|
|
||||||
if abs(debit_credit_diff) >= allowance:
|
if abs(debit_credit_diff) > allowance:
|
||||||
frappe.throw(_("Debit and Credit not equal for {0} #{1}. Difference is {2}.")
|
frappe.throw(_("Debit and Credit not equal for {0} #{1}. Difference is {2}.")
|
||||||
.format(gl_map[0].voucher_type, gl_map[0].voucher_no, debit_credit_diff))
|
.format(gl_map[0].voucher_type, gl_map[0].voucher_no, debit_credit_diff))
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"attach_print": 0,
|
"attach_print": 0,
|
||||||
|
"channel": "Email",
|
||||||
"condition": "doc.auto_created",
|
"condition": "doc.auto_created",
|
||||||
"creation": "2018-04-25 14:19:05.440361",
|
"creation": "2018-04-25 14:19:05.440361",
|
||||||
"days_in_advance": 0,
|
"days_in_advance": 0,
|
||||||
|
@ -364,7 +364,7 @@ class ReceivablePayableReport(object):
|
|||||||
payment_terms_details = frappe.db.sql("""
|
payment_terms_details = frappe.db.sql("""
|
||||||
select
|
select
|
||||||
si.name, si.party_account_currency, si.currency, si.conversion_rate,
|
si.name, si.party_account_currency, si.currency, si.conversion_rate,
|
||||||
ps.due_date, ps.payment_amount, ps.description, ps.paid_amount, ps.discounted_amount
|
ps.due_date, ps.payment_term, ps.payment_amount, ps.description, ps.paid_amount, ps.discounted_amount
|
||||||
from `tab{0}` si, `tabPayment Schedule` ps
|
from `tab{0}` si, `tabPayment Schedule` ps
|
||||||
where
|
where
|
||||||
si.name = ps.parent and
|
si.name = ps.parent and
|
||||||
@ -394,7 +394,7 @@ class ReceivablePayableReport(object):
|
|||||||
"due_date": d.due_date,
|
"due_date": d.due_date,
|
||||||
"invoiced": invoiced,
|
"invoiced": invoiced,
|
||||||
"invoice_grand_total": row.invoiced,
|
"invoice_grand_total": row.invoiced,
|
||||||
"payment_term": d.description,
|
"payment_term": d.description or d.payment_term,
|
||||||
"paid": d.paid_amount + d.discounted_amount,
|
"paid": d.paid_amount + d.discounted_amount,
|
||||||
"credit_note": 0.0,
|
"credit_note": 0.0,
|
||||||
"outstanding": invoiced - d.paid_amount - d.discounted_amount
|
"outstanding": invoiced - d.paid_amount - d.discounted_amount
|
||||||
|
@ -5,7 +5,8 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import flt, cint
|
from frappe.utils import flt, cint
|
||||||
from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
|
from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data,
|
||||||
|
get_filtered_list_for_consolidated_report)
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
|
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
|
||||||
@ -132,6 +133,10 @@ def get_report_summary(period_list, asset, liability, equity, provisional_profit
|
|||||||
if filters.get('accumulated_values'):
|
if filters.get('accumulated_values'):
|
||||||
period_list = [period_list[-1]]
|
period_list = [period_list[-1]]
|
||||||
|
|
||||||
|
# from consolidated financial statement
|
||||||
|
if filters.get('accumulated_in_group_company'):
|
||||||
|
period_list = get_filtered_list_for_consolidated_report(period_list)
|
||||||
|
|
||||||
for period in period_list:
|
for period in period_list:
|
||||||
key = period if consolidated else period.key
|
key = period if consolidated else period.key
|
||||||
if asset:
|
if asset:
|
||||||
|
@ -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['Billed Items To Be Received'] = {
|
||||||
|
'filters': [
|
||||||
|
{
|
||||||
|
'label': __('Company'),
|
||||||
|
'fieldname': 'company',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Company',
|
||||||
|
'reqd': 1,
|
||||||
|
'default': frappe.defaults.get_default('Company')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': __('As on Date'),
|
||||||
|
'fieldname': 'posting_date',
|
||||||
|
'fieldtype': 'Date',
|
||||||
|
'reqd': 1,
|
||||||
|
'default': get_today()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': __('Purchase Invoice'),
|
||||||
|
'fieldname': 'purchase_invoice',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Purchase Invoice'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"add_total_row": 0,
|
||||||
|
"columns": [],
|
||||||
|
"creation": "2021-03-30 09:35:38.683028",
|
||||||
|
"disable_prepared_report": 0,
|
||||||
|
"disabled": 0,
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Report",
|
||||||
|
"filters": [],
|
||||||
|
"idx": 0,
|
||||||
|
"is_standard": "Yes",
|
||||||
|
"modified": "2021-03-31 08:48:30.944429",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Accounts",
|
||||||
|
"name": "Billed Items To Be Received",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"prepared_report": 0,
|
||||||
|
"query": "",
|
||||||
|
"ref_doctype": "Purchase Invoice",
|
||||||
|
"report_name": "Billed Items To Be Received",
|
||||||
|
"report_type": "Script Report",
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "Accounts User"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Purchase User"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Accounts Manager"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Auditor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Stock User"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,107 @@
|
|||||||
|
# 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 _
|
||||||
|
|
||||||
|
def execute(filters=None):
|
||||||
|
data = get_data(filters) or []
|
||||||
|
columns = get_columns()
|
||||||
|
|
||||||
|
return columns, data
|
||||||
|
|
||||||
|
def get_data(report_filters):
|
||||||
|
filters = get_report_filters(report_filters)
|
||||||
|
fields = get_report_fields()
|
||||||
|
|
||||||
|
return frappe.get_all('Purchase Invoice',
|
||||||
|
fields= fields, filters=filters)
|
||||||
|
|
||||||
|
def get_report_filters(report_filters):
|
||||||
|
filters = [['Purchase Invoice','company','=',report_filters.get('company')],
|
||||||
|
['Purchase Invoice','posting_date','<=',report_filters.get('posting_date')], ['Purchase Invoice','docstatus','=',1],
|
||||||
|
['Purchase Invoice','per_received','<',100], ['Purchase Invoice','update_stock','=',0]]
|
||||||
|
|
||||||
|
if report_filters.get('purchase_invoice'):
|
||||||
|
filters.append(['Purchase Invoice','per_received','in',[report_filters.get('purchase_invoice')]])
|
||||||
|
|
||||||
|
return filters
|
||||||
|
|
||||||
|
def get_report_fields():
|
||||||
|
fields = []
|
||||||
|
for p_field in ['name', 'supplier', 'company', 'posting_date', 'currency']:
|
||||||
|
fields.append('`tabPurchase Invoice`.`{}`'.format(p_field))
|
||||||
|
|
||||||
|
for c_field in ['item_code', 'item_name', 'uom', 'qty', 'received_qty', 'rate', 'amount']:
|
||||||
|
fields.append('`tabPurchase Invoice Item`.`{}`'.format(c_field))
|
||||||
|
|
||||||
|
return fields
|
||||||
|
|
||||||
|
def get_columns():
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
'label': _('Purchase Invoice'),
|
||||||
|
'fieldname': 'name',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Purchase Invoice',
|
||||||
|
'width': 170
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Supplier'),
|
||||||
|
'fieldname': 'supplier',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Supplier',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Posting Date'),
|
||||||
|
'fieldname': 'posting_date',
|
||||||
|
'fieldtype': 'Date',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Item Code'),
|
||||||
|
'fieldname': 'item_code',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Item',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Item Name'),
|
||||||
|
'fieldname': 'item_name',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('UOM'),
|
||||||
|
'fieldname': 'uom',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'UOM',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Invoiced Qty'),
|
||||||
|
'fieldname': 'qty',
|
||||||
|
'fieldtype': 'Float',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Received Qty'),
|
||||||
|
'fieldname': 'received_qty',
|
||||||
|
'fieldtype': 'Float',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Rate'),
|
||||||
|
'fieldname': 'rate',
|
||||||
|
'fieldtype': 'Currency',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Amount'),
|
||||||
|
'fieldname': 'amount',
|
||||||
|
'fieldtype': 'Currency',
|
||||||
|
'width': 100
|
||||||
|
}
|
||||||
|
]
|
@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import cint, cstr
|
from frappe.utils import cint, cstr
|
||||||
from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
|
from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data, get_filtered_list_for_consolidated_report)
|
||||||
from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import get_net_profit_loss
|
from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import get_net_profit_loss
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
@ -67,9 +67,9 @@ def execute(filters=None):
|
|||||||
section_data.append(account_data)
|
section_data.append(account_data)
|
||||||
|
|
||||||
add_total_row_account(data, section_data, cash_flow_account['section_footer'],
|
add_total_row_account(data, section_data, cash_flow_account['section_footer'],
|
||||||
period_list, company_currency, summary_data)
|
period_list, company_currency, summary_data, filters)
|
||||||
|
|
||||||
add_total_row_account(data, data, _("Net Change in Cash"), period_list, company_currency, summary_data)
|
add_total_row_account(data, data, _("Net Change in Cash"), period_list, company_currency, summary_data, filters)
|
||||||
columns = get_columns(filters.periodicity, period_list, filters.accumulated_values, filters.company)
|
columns = get_columns(filters.periodicity, period_list, filters.accumulated_values, filters.company)
|
||||||
|
|
||||||
chart = get_chart_data(columns, data)
|
chart = get_chart_data(columns, data)
|
||||||
@ -162,18 +162,26 @@ def get_start_date(period, accumulated_values, company):
|
|||||||
|
|
||||||
return start_date
|
return start_date
|
||||||
|
|
||||||
def add_total_row_account(out, data, label, period_list, currency, summary_data, consolidated = False):
|
def add_total_row_account(out, data, label, period_list, currency, summary_data, filters, consolidated=False):
|
||||||
total_row = {
|
total_row = {
|
||||||
"account_name": "'" + _("{0}").format(label) + "'",
|
"account_name": "'" + _("{0}").format(label) + "'",
|
||||||
"account": "'" + _("{0}").format(label) + "'",
|
"account": "'" + _("{0}").format(label) + "'",
|
||||||
"currency": currency
|
"currency": currency
|
||||||
}
|
}
|
||||||
|
|
||||||
|
summary_data[label] = 0
|
||||||
|
|
||||||
|
# from consolidated financial statement
|
||||||
|
if filters.get('accumulated_in_group_company'):
|
||||||
|
period_list = get_filtered_list_for_consolidated_report(filters, period_list)
|
||||||
|
|
||||||
for row in data:
|
for row in data:
|
||||||
if row.get("parent_account"):
|
if row.get("parent_account"):
|
||||||
for period in period_list:
|
for period in period_list:
|
||||||
key = period if consolidated else period['key']
|
key = period if consolidated else period['key']
|
||||||
total_row.setdefault(key, 0.0)
|
total_row.setdefault(key, 0.0)
|
||||||
total_row[key] += row.get(key, 0.0)
|
total_row[key] += row.get(key, 0.0)
|
||||||
|
summary_data[label] += row.get(key)
|
||||||
|
|
||||||
total_row.setdefault("total", 0.0)
|
total_row.setdefault("total", 0.0)
|
||||||
total_row["total"] += row["total"]
|
total_row["total"] += row["total"]
|
||||||
@ -181,7 +189,6 @@ def add_total_row_account(out, data, label, period_list, currency, summary_data,
|
|||||||
out.append(total_row)
|
out.append(total_row)
|
||||||
out.append({})
|
out.append({})
|
||||||
|
|
||||||
summary_data[label] = total_row["total"]
|
|
||||||
|
|
||||||
def get_report_summary(summary_data, currency):
|
def get_report_summary(summary_data, currency):
|
||||||
report_summary = []
|
report_summary = []
|
||||||
|
@ -2,118 +2,128 @@
|
|||||||
// For license information, please see license.txt
|
// For license information, please see license.txt
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
||||||
frappe.query_reports["Consolidated Financial Statement"] = {
|
frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
||||||
"filters": [
|
frappe.query_reports["Consolidated Financial Statement"] = {
|
||||||
{
|
"filters": [
|
||||||
"fieldname":"company",
|
{
|
||||||
"label": __("Company"),
|
"fieldname":"company",
|
||||||
"fieldtype": "Link",
|
"label": __("Company"),
|
||||||
"options": "Company",
|
"fieldtype": "Link",
|
||||||
"default": frappe.defaults.get_user_default("Company"),
|
"options": "Company",
|
||||||
"reqd": 1
|
"default": frappe.defaults.get_user_default("Company"),
|
||||||
},
|
"reqd": 1
|
||||||
{
|
},
|
||||||
"fieldname":"filter_based_on",
|
{
|
||||||
"label": __("Filter Based On"),
|
"fieldname":"filter_based_on",
|
||||||
"fieldtype": "Select",
|
"label": __("Filter Based On"),
|
||||||
"options": ["Fiscal Year", "Date Range"],
|
"fieldtype": "Select",
|
||||||
"default": ["Fiscal Year"],
|
"options": ["Fiscal Year", "Date Range"],
|
||||||
"reqd": 1,
|
"default": ["Fiscal Year"],
|
||||||
on_change: function() {
|
"reqd": 1,
|
||||||
let filter_based_on = frappe.query_report.get_filter_value('filter_based_on');
|
on_change: function() {
|
||||||
frappe.query_report.toggle_filter_display('from_fiscal_year', filter_based_on === 'Date Range');
|
let filter_based_on = frappe.query_report.get_filter_value('filter_based_on');
|
||||||
frappe.query_report.toggle_filter_display('to_fiscal_year', filter_based_on === 'Date Range');
|
frappe.query_report.toggle_filter_display('from_fiscal_year', filter_based_on === 'Date Range');
|
||||||
frappe.query_report.toggle_filter_display('period_start_date', filter_based_on === 'Fiscal Year');
|
frappe.query_report.toggle_filter_display('to_fiscal_year', filter_based_on === 'Date Range');
|
||||||
frappe.query_report.toggle_filter_display('period_end_date', filter_based_on === 'Fiscal Year');
|
frappe.query_report.toggle_filter_display('period_start_date', filter_based_on === 'Fiscal Year');
|
||||||
|
frappe.query_report.toggle_filter_display('period_end_date', filter_based_on === 'Fiscal Year');
|
||||||
|
|
||||||
frappe.query_report.refresh();
|
frappe.query_report.refresh();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"period_start_date",
|
||||||
|
"label": __("Start Date"),
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"hidden": 1,
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"period_end_date",
|
||||||
|
"label": __("End Date"),
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"hidden": 1,
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"from_fiscal_year",
|
||||||
|
"label": __("Start Year"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Fiscal Year",
|
||||||
|
"default": frappe.defaults.get_user_default("fiscal_year"),
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"to_fiscal_year",
|
||||||
|
"label": __("End Year"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Fiscal Year",
|
||||||
|
"default": frappe.defaults.get_user_default("fiscal_year"),
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"finance_book",
|
||||||
|
"label": __("Finance Book"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Finance Book"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"report",
|
||||||
|
"label": __("Report"),
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"options": ["Profit and Loss Statement", "Balance Sheet", "Cash Flow"],
|
||||||
|
"default": "Balance Sheet",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "presentation_currency",
|
||||||
|
"label": __("Currency"),
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"options": erpnext.get_presentation_currency_list(),
|
||||||
|
"default": frappe.defaults.get_user_default("Currency")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"accumulated_in_group_company",
|
||||||
|
"label": __("Accumulated Values in Group Company"),
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "include_default_book_entries",
|
||||||
|
"label": __("Include Default Book Entries"),
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"default": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"formatter": function(value, row, column, data, default_formatter) {
|
||||||
|
if (data && column.fieldname=="account") {
|
||||||
|
value = data.account_name || value;
|
||||||
|
|
||||||
|
column.link_onclick =
|
||||||
|
"erpnext.financial_statements.open_general_ledger(" + JSON.stringify(data) + ")";
|
||||||
|
column.is_tree = true;
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname":"period_start_date",
|
|
||||||
"label": __("Start Date"),
|
|
||||||
"fieldtype": "Date",
|
|
||||||
"hidden": 1,
|
|
||||||
"reqd": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname":"period_end_date",
|
|
||||||
"label": __("End Date"),
|
|
||||||
"fieldtype": "Date",
|
|
||||||
"hidden": 1,
|
|
||||||
"reqd": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname":"from_fiscal_year",
|
|
||||||
"label": __("Start Year"),
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"options": "Fiscal Year",
|
|
||||||
"default": frappe.defaults.get_user_default("fiscal_year"),
|
|
||||||
"reqd": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname":"to_fiscal_year",
|
|
||||||
"label": __("End Year"),
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"options": "Fiscal Year",
|
|
||||||
"default": frappe.defaults.get_user_default("fiscal_year"),
|
|
||||||
"reqd": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname":"finance_book",
|
|
||||||
"label": __("Finance Book"),
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"options": "Finance Book"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname":"report",
|
|
||||||
"label": __("Report"),
|
|
||||||
"fieldtype": "Select",
|
|
||||||
"options": ["Profit and Loss Statement", "Balance Sheet", "Cash Flow"],
|
|
||||||
"default": "Balance Sheet",
|
|
||||||
"reqd": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname": "presentation_currency",
|
|
||||||
"label": __("Currency"),
|
|
||||||
"fieldtype": "Select",
|
|
||||||
"options": erpnext.get_presentation_currency_list(),
|
|
||||||
"default": frappe.defaults.get_user_default("Currency")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname":"accumulated_in_group_company",
|
|
||||||
"label": __("Accumulated Values in Group Company"),
|
|
||||||
"fieldtype": "Check",
|
|
||||||
"default": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname": "include_default_book_entries",
|
|
||||||
"label": __("Include Default Book Entries"),
|
|
||||||
"fieldtype": "Check",
|
|
||||||
"default": 1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"formatter": function(value, row, column, data, default_formatter) {
|
|
||||||
value = default_formatter(value, row, column, data);
|
|
||||||
|
|
||||||
if (!data.parent_account) {
|
value = default_formatter(value, row, column, data);
|
||||||
value = $(`<span>${value}</span>`);
|
|
||||||
|
|
||||||
var $value = $(value).css("font-weight", "bold");
|
if (!data.parent_account) {
|
||||||
|
value = $(`<span>${value}</span>`);
|
||||||
|
|
||||||
value = $value.wrap("<p></p>").parent().html();
|
var $value = $(value).css("font-weight", "bold");
|
||||||
}
|
|
||||||
return value;
|
|
||||||
},
|
|
||||||
onload: function() {
|
|
||||||
let fiscal_year = frappe.defaults.get_user_default("fiscal_year")
|
|
||||||
|
|
||||||
frappe.model.with_doc("Fiscal Year", fiscal_year, function(r) {
|
value = $value.wrap("<p></p>").parent().html();
|
||||||
var fy = frappe.model.get_doc("Fiscal Year", fiscal_year);
|
}
|
||||||
frappe.query_report.set_filter_value({
|
return value;
|
||||||
period_start_date: fy.year_start_date,
|
},
|
||||||
period_end_date: fy.year_end_date
|
onload: function() {
|
||||||
|
let fiscal_year = frappe.defaults.get_user_default("fiscal_year")
|
||||||
|
|
||||||
|
frappe.model.with_doc("Fiscal Year", fiscal_year, function(r) {
|
||||||
|
var fy = frappe.model.get_doc("Fiscal Year", fiscal_year);
|
||||||
|
frappe.query_report.set_filter_value({
|
||||||
|
period_start_date: fy.year_start_date,
|
||||||
|
period_end_date: fy.year_end_date
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
@ -94,7 +94,7 @@ def get_profit_loss_data(fiscal_year, companies, columns, filters):
|
|||||||
|
|
||||||
chart = get_pl_chart_data(filters, columns, income, expense, net_profit_loss)
|
chart = get_pl_chart_data(filters, columns, income, expense, net_profit_loss)
|
||||||
|
|
||||||
report_summary = get_pl_summary(companies, '', income, expense, net_profit_loss, company_currency, True)
|
report_summary = get_pl_summary(companies, '', income, expense, net_profit_loss, company_currency, filters, True)
|
||||||
|
|
||||||
return data, None, chart, report_summary
|
return data, None, chart, report_summary
|
||||||
|
|
||||||
@ -149,9 +149,9 @@ def get_cash_flow_data(fiscal_year, companies, filters):
|
|||||||
section_data.append(account_data)
|
section_data.append(account_data)
|
||||||
|
|
||||||
add_total_row_account(data, section_data, cash_flow_account['section_footer'],
|
add_total_row_account(data, section_data, cash_flow_account['section_footer'],
|
||||||
companies, company_currency, summary_data, True)
|
companies, company_currency, summary_data, filters, True)
|
||||||
|
|
||||||
add_total_row_account(data, data, _("Net Change in Cash"), companies, company_currency, summary_data, True)
|
add_total_row_account(data, data, _("Net Change in Cash"), companies, company_currency, summary_data, filters, True)
|
||||||
|
|
||||||
report_summary = get_cash_flow_summary(summary_data, company_currency)
|
report_summary = get_cash_flow_summary(summary_data, company_currency)
|
||||||
|
|
||||||
@ -329,8 +329,9 @@ def prepare_data(accounts, start_date, end_date, balance_must_be, companies, com
|
|||||||
has_value = False
|
has_value = False
|
||||||
total = 0
|
total = 0
|
||||||
row = frappe._dict({
|
row = frappe._dict({
|
||||||
"account_name": _(d.account_name),
|
"account_name": ('%s - %s' %(_(d.account_number), _(d.account_name))
|
||||||
"account": _(d.account_name),
|
if d.account_number else _(d.account_name)),
|
||||||
|
"account": _(d.name),
|
||||||
"parent_account": _(d.parent_account),
|
"parent_account": _(d.parent_account),
|
||||||
"indent": flt(d.indent),
|
"indent": flt(d.indent),
|
||||||
"year_start_date": start_date,
|
"year_start_date": start_date,
|
||||||
|
@ -119,10 +119,10 @@ def validate_fiscal_year(fiscal_year, from_fiscal_year, to_fiscal_year):
|
|||||||
|
|
||||||
def validate_dates(from_date, to_date):
|
def validate_dates(from_date, to_date):
|
||||||
if not from_date or not to_date:
|
if not from_date or not to_date:
|
||||||
frappe.throw("From Date and To Date are mandatory")
|
frappe.throw(_("From Date and To Date are mandatory"))
|
||||||
|
|
||||||
if to_date < from_date:
|
if to_date < from_date:
|
||||||
frappe.throw("To Date cannot be less than From Date")
|
frappe.throw(_("To Date cannot be less than From Date"))
|
||||||
|
|
||||||
def get_months(start_date, end_date):
|
def get_months(start_date, end_date):
|
||||||
diff = (12 * end_date.year + end_date.month) - (12 * start_date.year + start_date.month)
|
diff = (12 * end_date.year + end_date.month) - (12 * start_date.year + start_date.month)
|
||||||
@ -522,4 +522,12 @@ def get_columns(periodicity, period_list, accumulated_values=1, company=None):
|
|||||||
"width": 150
|
"width": 150
|
||||||
})
|
})
|
||||||
|
|
||||||
return columns
|
return columns
|
||||||
|
|
||||||
|
def get_filtered_list_for_consolidated_report(filters, period_list):
|
||||||
|
filtered_summary_list = []
|
||||||
|
for period in period_list:
|
||||||
|
if period == filters.get('company'):
|
||||||
|
filtered_summary_list.append(period)
|
||||||
|
|
||||||
|
return filtered_summary_list
|
||||||
|
@ -116,22 +116,19 @@ def validate_filters(filters):
|
|||||||
frappe.throw(_("Can not filter based on Payment Method, if grouped by Payment Method"))
|
frappe.throw(_("Can not filter based on Payment Method, if grouped by Payment Method"))
|
||||||
|
|
||||||
def get_conditions(filters):
|
def get_conditions(filters):
|
||||||
conditions = "company = %(company)s AND posting_date >= %(from_date)s AND posting_date <= %(to_date)s".format(
|
conditions = "company = %(company)s AND posting_date >= %(from_date)s AND posting_date <= %(to_date)s"
|
||||||
company=filters.get("company"),
|
|
||||||
from_date=filters.get("from_date"),
|
|
||||||
to_date=filters.get("to_date"))
|
|
||||||
|
|
||||||
if filters.get("pos_profile"):
|
if filters.get("pos_profile"):
|
||||||
conditions += " AND pos_profile = %(pos_profile)s".format(pos_profile=filters.get("pos_profile"))
|
conditions += " AND pos_profile = %(pos_profile)s"
|
||||||
|
|
||||||
if filters.get("owner"):
|
if filters.get("owner"):
|
||||||
conditions += " AND owner = %(owner)s".format(owner=filters.get("owner"))
|
conditions += " AND owner = %(owner)s"
|
||||||
|
|
||||||
if filters.get("customer"):
|
if filters.get("customer"):
|
||||||
conditions += " AND customer = %(customer)s".format(customer=filters.get("customer"))
|
conditions += " AND customer = %(customer)s"
|
||||||
|
|
||||||
if filters.get("is_return"):
|
if filters.get("is_return"):
|
||||||
conditions += " AND is_return = %(is_return)s".format(is_return=filters.get("is_return"))
|
conditions += " AND is_return = %(is_return)s"
|
||||||
|
|
||||||
if filters.get("mode_of_payment"):
|
if filters.get("mode_of_payment"):
|
||||||
conditions += """
|
conditions += """
|
||||||
|
@ -5,7 +5,8 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import flt
|
from frappe.utils import flt
|
||||||
from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
|
from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data,
|
||||||
|
get_filtered_list_for_consolidated_report)
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
|
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
|
||||||
@ -33,13 +34,17 @@ def execute(filters=None):
|
|||||||
chart = get_chart_data(filters, columns, income, expense, net_profit_loss)
|
chart = get_chart_data(filters, columns, income, expense, net_profit_loss)
|
||||||
|
|
||||||
currency = filters.presentation_currency or frappe.get_cached_value('Company', filters.company, "default_currency")
|
currency = filters.presentation_currency or frappe.get_cached_value('Company', filters.company, "default_currency")
|
||||||
report_summary = get_report_summary(period_list, filters.periodicity, income, expense, net_profit_loss, currency)
|
report_summary = get_report_summary(period_list, filters.periodicity, income, expense, net_profit_loss, currency, filters)
|
||||||
|
|
||||||
return columns, data, None, chart, report_summary
|
return columns, data, None, chart, report_summary
|
||||||
|
|
||||||
def get_report_summary(period_list, periodicity, income, expense, net_profit_loss, currency, consolidated=False):
|
def get_report_summary(period_list, periodicity, income, expense, net_profit_loss, currency, filters, consolidated=False):
|
||||||
net_income, net_expense, net_profit = 0.0, 0.0, 0.0
|
net_income, net_expense, net_profit = 0.0, 0.0, 0.0
|
||||||
|
|
||||||
|
# from consolidated financial statement
|
||||||
|
if filters.get('accumulated_in_group_company'):
|
||||||
|
period_list = get_filtered_list_for_consolidated_report(filters, period_list)
|
||||||
|
|
||||||
for period in period_list:
|
for period in period_list:
|
||||||
key = period if consolidated else period.key
|
key = period if consolidated else period.key
|
||||||
if income:
|
if income:
|
||||||
|
@ -195,8 +195,7 @@ class Asset(AccountsController):
|
|||||||
# If depreciation is already completed (for double declining balance)
|
# If depreciation is already completed (for double declining balance)
|
||||||
if skip_row: continue
|
if skip_row: continue
|
||||||
|
|
||||||
depreciation_amount = self.get_depreciation_amount(value_after_depreciation,
|
depreciation_amount = get_depreciation_amount(self, value_after_depreciation, d)
|
||||||
d.total_number_of_depreciations, d)
|
|
||||||
|
|
||||||
if not has_pro_rata or n < cint(number_of_pending_depreciations) - 1:
|
if not has_pro_rata or n < cint(number_of_pending_depreciations) - 1:
|
||||||
schedule_date = add_months(d.depreciation_start_date,
|
schedule_date = add_months(d.depreciation_start_date,
|
||||||
@ -208,7 +207,7 @@ class Asset(AccountsController):
|
|||||||
|
|
||||||
# For first row
|
# For first row
|
||||||
if has_pro_rata and n==0:
|
if has_pro_rata and n==0:
|
||||||
depreciation_amount, days, months = get_pro_rata_amt(d, depreciation_amount,
|
depreciation_amount, days, months = self.get_pro_rata_amt(d, depreciation_amount,
|
||||||
self.available_for_use_date, d.depreciation_start_date)
|
self.available_for_use_date, d.depreciation_start_date)
|
||||||
|
|
||||||
# For first depr schedule date will be the start date
|
# For first depr schedule date will be the start date
|
||||||
@ -220,7 +219,7 @@ class Asset(AccountsController):
|
|||||||
to_date = add_months(self.available_for_use_date,
|
to_date = add_months(self.available_for_use_date,
|
||||||
n * cint(d.frequency_of_depreciation))
|
n * cint(d.frequency_of_depreciation))
|
||||||
|
|
||||||
depreciation_amount, days, months = get_pro_rata_amt(d,
|
depreciation_amount, days, months = self.get_pro_rata_amt(d,
|
||||||
depreciation_amount, schedule_date, to_date)
|
depreciation_amount, schedule_date, to_date)
|
||||||
|
|
||||||
monthly_schedule_date = add_months(schedule_date, 1)
|
monthly_schedule_date = add_months(schedule_date, 1)
|
||||||
@ -365,24 +364,6 @@ class Asset(AccountsController):
|
|||||||
def get_value_after_depreciation(self, idx):
|
def get_value_after_depreciation(self, idx):
|
||||||
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):
|
|
||||||
precision = self.precision("gross_purchase_amount")
|
|
||||||
|
|
||||||
if row.depreciation_method in ("Straight Line", "Manual"):
|
|
||||||
depreciation_left = (cint(row.total_number_of_depreciations) - cint(self.number_of_depreciations_booked))
|
|
||||||
|
|
||||||
if not depreciation_left:
|
|
||||||
frappe.msgprint(_("All the depreciations has been booked"))
|
|
||||||
depreciation_amount = flt(row.expected_value_after_useful_life)
|
|
||||||
return depreciation_amount
|
|
||||||
|
|
||||||
depreciation_amount = (flt(row.value_after_depreciation) -
|
|
||||||
flt(row.expected_value_after_useful_life)) / depreciation_left
|
|
||||||
else:
|
|
||||||
depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100), precision)
|
|
||||||
|
|
||||||
return depreciation_amount
|
|
||||||
|
|
||||||
def validate_expected_value_after_useful_life(self):
|
def validate_expected_value_after_useful_life(self):
|
||||||
for row in self.get('finance_books'):
|
for row in self.get('finance_books'):
|
||||||
accumulated_depreciation_after_full_schedule = [d.accumulated_depreciation_amount
|
accumulated_depreciation_after_full_schedule = [d.accumulated_depreciation_amount
|
||||||
@ -575,6 +556,13 @@ class Asset(AccountsController):
|
|||||||
|
|
||||||
return 100 * (1 - flt(depreciation_rate, float_precision))
|
return 100 * (1 - flt(depreciation_rate, float_precision))
|
||||||
|
|
||||||
|
def get_pro_rata_amt(self, row, depreciation_amount, from_date, to_date):
|
||||||
|
days = date_diff(to_date, from_date)
|
||||||
|
months = month_diff(to_date, from_date)
|
||||||
|
total_days = get_total_days(to_date, row.frequency_of_depreciation)
|
||||||
|
|
||||||
|
return (depreciation_amount * flt(days)) / flt(total_days), days, months
|
||||||
|
|
||||||
def update_maintenance_status():
|
def update_maintenance_status():
|
||||||
assets = frappe.get_all(
|
assets = frappe.get_all(
|
||||||
"Asset", filters={"docstatus": 1, "maintenance_required": 1}
|
"Asset", filters={"docstatus": 1, "maintenance_required": 1}
|
||||||
@ -758,15 +746,20 @@ def make_asset_movement(assets, purpose=None):
|
|||||||
def is_cwip_accounting_enabled(asset_category):
|
def is_cwip_accounting_enabled(asset_category):
|
||||||
return cint(frappe.db.get_value("Asset Category", asset_category, "enable_cwip_accounting"))
|
return cint(frappe.db.get_value("Asset Category", asset_category, "enable_cwip_accounting"))
|
||||||
|
|
||||||
def get_pro_rata_amt(row, depreciation_amount, from_date, to_date):
|
|
||||||
days = date_diff(to_date, from_date)
|
|
||||||
months = month_diff(to_date, from_date)
|
|
||||||
total_days = get_total_days(to_date, row.frequency_of_depreciation)
|
|
||||||
|
|
||||||
return (depreciation_amount * flt(days)) / flt(total_days), days, months
|
|
||||||
|
|
||||||
def get_total_days(date, frequency):
|
def get_total_days(date, frequency):
|
||||||
period_start_date = add_months(date,
|
period_start_date = add_months(date,
|
||||||
cint(frequency) * -1)
|
cint(frequency) * -1)
|
||||||
|
|
||||||
return date_diff(date, period_start_date)
|
return date_diff(date, period_start_date)
|
||||||
|
|
||||||
|
@erpnext.allow_regional
|
||||||
|
def get_depreciation_amount(asset, depreciable_value, row):
|
||||||
|
depreciation_left = flt(row.total_number_of_depreciations) - flt(asset.number_of_depreciations_booked)
|
||||||
|
|
||||||
|
if row.depreciation_method in ("Straight Line", "Manual"):
|
||||||
|
depreciation_amount = (flt(row.value_after_depreciation) -
|
||||||
|
flt(row.expected_value_after_useful_life)) / depreciation_left
|
||||||
|
else:
|
||||||
|
depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100))
|
||||||
|
|
||||||
|
return depreciation_amount
|
@ -78,7 +78,7 @@ class TestAsset(unittest.TestCase):
|
|||||||
})
|
})
|
||||||
|
|
||||||
doc.set_missing_values()
|
doc.set_missing_values()
|
||||||
self.assertEquals(doc.items[0].is_fixed_asset, 1)
|
self.assertEqual(doc.items[0].is_fixed_asset, 1)
|
||||||
|
|
||||||
def test_schedule_for_straight_line_method(self):
|
def test_schedule_for_straight_line_method(self):
|
||||||
pr = make_purchase_receipt(item_code="Macbook Pro",
|
pr = make_purchase_receipt(item_code="Macbook Pro",
|
||||||
@ -565,7 +565,7 @@ class TestAsset(unittest.TestCase):
|
|||||||
|
|
||||||
doc = make_invoice(pr.name)
|
doc = make_invoice(pr.name)
|
||||||
|
|
||||||
self.assertEquals('Asset Received But Not Billed - _TC', doc.items[0].expense_account)
|
self.assertEqual('Asset Received But Not Billed - _TC', doc.items[0].expense_account)
|
||||||
|
|
||||||
def test_asset_cwip_toggling_cases(self):
|
def test_asset_cwip_toggling_cases(self):
|
||||||
cwip = frappe.db.get_value("Asset Category", "Computers", "enable_cwip_accounting")
|
cwip = frappe.db.get_value("Asset Category", "Computers", "enable_cwip_accounting")
|
||||||
@ -635,6 +635,45 @@ class TestAsset(unittest.TestCase):
|
|||||||
frappe.db.set_value("Asset Category Account", name, "capital_work_in_progress_account", cwip_acc)
|
frappe.db.set_value("Asset Category Account", name, "capital_work_in_progress_account", cwip_acc)
|
||||||
frappe.db.get_value("Company", "_Test Company", "capital_work_in_progress_account", cwip_acc)
|
frappe.db.get_value("Company", "_Test Company", "capital_work_in_progress_account", cwip_acc)
|
||||||
|
|
||||||
|
def test_discounted_wdv_depreciation_rate_for_indian_region(self):
|
||||||
|
# set indian company
|
||||||
|
company_flag = frappe.flags.company
|
||||||
|
frappe.flags.company = "_Test Company"
|
||||||
|
|
||||||
|
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-12'
|
||||||
|
asset.purchase_date = '2030-01-01'
|
||||||
|
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", 1106.85, 1106.85],
|
||||||
|
["2031-12-31", 3446.58, 4553.43],
|
||||||
|
["2032-12-31", 1723.29, 6276.72],
|
||||||
|
["2033-06-12", 723.28, 7000.00]
|
||||||
|
]
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
# reset indian company
|
||||||
|
frappe.flags.company = company_flag
|
||||||
|
|
||||||
def create_asset_data():
|
def create_asset_data():
|
||||||
if not frappe.db.exists("Asset Category", "Computers"):
|
if not frappe.db.exists("Asset Category", "Computers"):
|
||||||
create_asset_category()
|
create_asset_category()
|
||||||
|
@ -187,7 +187,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
update_child_qty_rate('Purchase Order', trans_item, po.name)
|
update_child_qty_rate('Purchase Order', trans_item, po.name)
|
||||||
|
|
||||||
po.reload()
|
po.reload()
|
||||||
self.assertEquals(len(po.get('items')), 2)
|
self.assertEqual(len(po.get('items')), 2)
|
||||||
self.assertEqual(po.status, 'To Receive and Bill')
|
self.assertEqual(po.status, 'To Receive and Bill')
|
||||||
# ordered qty should increase on row addition
|
# ordered qty should increase on row addition
|
||||||
self.assertEqual(get_ordered_qty(), existing_ordered_qty + 7)
|
self.assertEqual(get_ordered_qty(), existing_ordered_qty + 7)
|
||||||
@ -234,7 +234,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
update_child_qty_rate('Purchase Order', trans_item, po.name)
|
update_child_qty_rate('Purchase Order', trans_item, po.name)
|
||||||
|
|
||||||
po.reload()
|
po.reload()
|
||||||
self.assertEquals(len(po.get('items')), 1)
|
self.assertEqual(len(po.get('items')), 1)
|
||||||
self.assertEqual(po.status, 'To Receive and Bill')
|
self.assertEqual(po.status, 'To Receive and Bill')
|
||||||
|
|
||||||
# ordered qty should decrease (back to initial) on row deletion
|
# ordered qty should decrease (back to initial) on row deletion
|
||||||
@ -435,6 +435,35 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
po.load_from_db()
|
po.load_from_db()
|
||||||
self.assertEqual(po.get("items")[0].received_qty, 5)
|
self.assertEqual(po.get("items")[0].received_qty, 5)
|
||||||
|
|
||||||
|
def test_purchase_order_invoice_receipt_workflow(self):
|
||||||
|
from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import make_purchase_receipt
|
||||||
|
|
||||||
|
po = create_purchase_order()
|
||||||
|
pi = make_pi_from_po(po.name)
|
||||||
|
|
||||||
|
pi.submit()
|
||||||
|
|
||||||
|
pr = make_purchase_receipt(pi.name)
|
||||||
|
pr.submit()
|
||||||
|
|
||||||
|
pi.load_from_db()
|
||||||
|
|
||||||
|
self.assertEqual(pi.per_received, 100.00)
|
||||||
|
self.assertEqual(pi.items[0].qty, pi.items[0].received_qty)
|
||||||
|
|
||||||
|
po.load_from_db()
|
||||||
|
|
||||||
|
self.assertEqual(po.per_received, 100.00)
|
||||||
|
self.assertEqual(po.per_billed, 100.00)
|
||||||
|
|
||||||
|
pr.cancel()
|
||||||
|
|
||||||
|
pi.load_from_db()
|
||||||
|
pi.cancel()
|
||||||
|
|
||||||
|
po.load_from_db()
|
||||||
|
po.cancel()
|
||||||
|
|
||||||
def test_make_purchase_invoice(self):
|
def test_make_purchase_invoice(self):
|
||||||
po = create_purchase_order(do_not_submit=True)
|
po = create_purchase_order(do_not_submit=True)
|
||||||
|
|
||||||
@ -645,8 +674,8 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
||||||
fieldname=["reserved_qty_for_sub_contract", "projected_qty"], as_dict=1)
|
fieldname=["reserved_qty_for_sub_contract", "projected_qty"], as_dict=1)
|
||||||
|
|
||||||
self.assertEquals(bin2.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract + 10)
|
self.assertEqual(bin2.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract + 10)
|
||||||
self.assertEquals(bin2.projected_qty, bin1.projected_qty - 10)
|
self.assertEqual(bin2.projected_qty, bin1.projected_qty - 10)
|
||||||
|
|
||||||
# Create stock transfer
|
# Create stock transfer
|
||||||
rm_item = [{"item_code":"_Test FG Item","rm_item_code":"_Test Item","item_name":"_Test Item",
|
rm_item = [{"item_code":"_Test FG Item","rm_item_code":"_Test Item","item_name":"_Test Item",
|
||||||
@ -661,7 +690,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
||||||
fieldname="reserved_qty_for_sub_contract", as_dict=1)
|
fieldname="reserved_qty_for_sub_contract", as_dict=1)
|
||||||
|
|
||||||
self.assertEquals(bin3.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
|
self.assertEqual(bin3.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
|
||||||
|
|
||||||
# close PO
|
# close PO
|
||||||
po.update_status("Closed")
|
po.update_status("Closed")
|
||||||
@ -669,7 +698,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
||||||
fieldname="reserved_qty_for_sub_contract", as_dict=1)
|
fieldname="reserved_qty_for_sub_contract", as_dict=1)
|
||||||
|
|
||||||
self.assertEquals(bin4.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
|
self.assertEqual(bin4.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
|
||||||
|
|
||||||
# Re-open PO
|
# Re-open PO
|
||||||
po.update_status("Submitted")
|
po.update_status("Submitted")
|
||||||
@ -677,7 +706,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
||||||
fieldname="reserved_qty_for_sub_contract", as_dict=1)
|
fieldname="reserved_qty_for_sub_contract", as_dict=1)
|
||||||
|
|
||||||
self.assertEquals(bin5.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
|
self.assertEqual(bin5.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
|
||||||
|
|
||||||
make_stock_entry(target="_Test Warehouse 1 - _TC", item_code="_Test Item",
|
make_stock_entry(target="_Test Warehouse 1 - _TC", item_code="_Test Item",
|
||||||
qty=40, basic_rate=100)
|
qty=40, basic_rate=100)
|
||||||
@ -694,7 +723,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
||||||
fieldname="reserved_qty_for_sub_contract", as_dict=1)
|
fieldname="reserved_qty_for_sub_contract", as_dict=1)
|
||||||
|
|
||||||
self.assertEquals(bin6.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
|
self.assertEqual(bin6.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
|
||||||
|
|
||||||
# Cancel PR
|
# Cancel PR
|
||||||
pr.cancel()
|
pr.cancel()
|
||||||
@ -702,7 +731,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
||||||
fieldname="reserved_qty_for_sub_contract", as_dict=1)
|
fieldname="reserved_qty_for_sub_contract", as_dict=1)
|
||||||
|
|
||||||
self.assertEquals(bin7.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
|
self.assertEqual(bin7.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
|
||||||
|
|
||||||
# Make Purchase Invoice
|
# Make Purchase Invoice
|
||||||
pi = make_pi_from_po(po.name)
|
pi = make_pi_from_po(po.name)
|
||||||
@ -714,7 +743,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
||||||
fieldname="reserved_qty_for_sub_contract", as_dict=1)
|
fieldname="reserved_qty_for_sub_contract", as_dict=1)
|
||||||
|
|
||||||
self.assertEquals(bin8.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
|
self.assertEqual(bin8.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
|
||||||
|
|
||||||
# Cancel PR
|
# Cancel PR
|
||||||
pi.cancel()
|
pi.cancel()
|
||||||
@ -722,7 +751,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
||||||
fieldname="reserved_qty_for_sub_contract", as_dict=1)
|
fieldname="reserved_qty_for_sub_contract", as_dict=1)
|
||||||
|
|
||||||
self.assertEquals(bin9.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
|
self.assertEqual(bin9.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
|
||||||
|
|
||||||
# Cancel Stock Entry
|
# Cancel Stock Entry
|
||||||
se.cancel()
|
se.cancel()
|
||||||
@ -730,7 +759,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
||||||
fieldname="reserved_qty_for_sub_contract", as_dict=1)
|
fieldname="reserved_qty_for_sub_contract", as_dict=1)
|
||||||
|
|
||||||
self.assertEquals(bin10.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract + 10)
|
self.assertEqual(bin10.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract + 10)
|
||||||
|
|
||||||
# Cancel PO
|
# Cancel PO
|
||||||
po.reload()
|
po.reload()
|
||||||
@ -739,7 +768,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
||||||
fieldname="reserved_qty_for_sub_contract", as_dict=1)
|
fieldname="reserved_qty_for_sub_contract", as_dict=1)
|
||||||
|
|
||||||
self.assertEquals(bin11.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
|
self.assertEqual(bin11.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
|
||||||
|
|
||||||
def test_exploded_items_in_subcontracted(self):
|
def test_exploded_items_in_subcontracted(self):
|
||||||
item_code = "_Test Subcontracted FG Item 1"
|
item_code = "_Test Subcontracted FG Item 1"
|
||||||
@ -753,7 +782,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
|
|
||||||
exploded_items = sorted([d.item_code for d in bom.exploded_items if not d.get('sourced_by_supplier')])
|
exploded_items = sorted([d.item_code for d in bom.exploded_items if not d.get('sourced_by_supplier')])
|
||||||
supplied_items = sorted([d.rm_item_code for d in po.supplied_items])
|
supplied_items = sorted([d.rm_item_code for d in po.supplied_items])
|
||||||
self.assertEquals(exploded_items, supplied_items)
|
self.assertEqual(exploded_items, supplied_items)
|
||||||
|
|
||||||
po1 = create_purchase_order(item_code=item_code, qty=1,
|
po1 = create_purchase_order(item_code=item_code, qty=1,
|
||||||
is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC", include_exploded_items=0)
|
is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC", include_exploded_items=0)
|
||||||
@ -761,7 +790,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
supplied_items1 = sorted([d.rm_item_code for d in po1.supplied_items])
|
supplied_items1 = sorted([d.rm_item_code for d in po1.supplied_items])
|
||||||
bom_items = sorted([d.item_code for d in bom.items if not d.get('sourced_by_supplier')])
|
bom_items = sorted([d.item_code for d in bom.items if not d.get('sourced_by_supplier')])
|
||||||
|
|
||||||
self.assertEquals(supplied_items1, bom_items)
|
self.assertEqual(supplied_items1, bom_items)
|
||||||
|
|
||||||
def test_backflush_based_on_stock_entry(self):
|
def test_backflush_based_on_stock_entry(self):
|
||||||
item_code = "_Test Subcontracted FG Item 1"
|
item_code = "_Test Subcontracted FG Item 1"
|
||||||
@ -811,8 +840,8 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
transferred_items = sorted([d.item_code for d in se.get('items') if se.purchase_order == po.name])
|
transferred_items = sorted([d.item_code for d in se.get('items') if se.purchase_order == po.name])
|
||||||
issued_items = sorted([d.rm_item_code for d in pr.get('supplied_items')])
|
issued_items = sorted([d.rm_item_code for d in pr.get('supplied_items')])
|
||||||
|
|
||||||
self.assertEquals(transferred_items, issued_items)
|
self.assertEqual(transferred_items, issued_items)
|
||||||
self.assertEquals(pr.get('items')[0].rm_supp_cost, 2000)
|
self.assertEqual(pr.get('items')[0].rm_supp_cost, 2000)
|
||||||
|
|
||||||
|
|
||||||
transferred_rm_map = frappe._dict()
|
transferred_rm_map = frappe._dict()
|
||||||
|
@ -838,9 +838,10 @@ class BuyingController(StockController):
|
|||||||
if not self.get("items"):
|
if not self.get("items"):
|
||||||
return
|
return
|
||||||
|
|
||||||
earliest_schedule_date = min([d.schedule_date for d in self.get("items")])
|
if any(d.schedule_date for d in self.get("items")):
|
||||||
if earliest_schedule_date:
|
# Select earliest schedule_date.
|
||||||
self.schedule_date = earliest_schedule_date
|
self.schedule_date = min(d.schedule_date for d in self.get("items")
|
||||||
|
if d.schedule_date is not None)
|
||||||
|
|
||||||
if self.schedule_date:
|
if self.schedule_date:
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
|
@ -292,11 +292,14 @@ def get_project_name(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
cond = """(`tabProject`.customer = %s or
|
cond = """(`tabProject`.customer = %s or
|
||||||
ifnull(`tabProject`.customer,"")="") and""" %(frappe.db.escape(filters.get("customer")))
|
ifnull(`tabProject`.customer,"")="") and""" %(frappe.db.escape(filters.get("customer")))
|
||||||
|
|
||||||
fields = get_fields("Project", ["name"])
|
fields = get_fields("Project", ["name", "project_name"])
|
||||||
|
searchfields = frappe.get_meta("Project").get_search_fields()
|
||||||
|
searchfields = " or ".join([field + " like %(txt)s" for field in searchfields])
|
||||||
|
|
||||||
return frappe.db.sql("""select {fields} from `tabProject`
|
return frappe.db.sql("""select {fields} from `tabProject`
|
||||||
where `tabProject`.status not in ("Completed", "Cancelled")
|
where
|
||||||
and {cond} `tabProject`.name like %(txt)s {match_cond}
|
`tabProject`.status not in ("Completed", "Cancelled")
|
||||||
|
and {cond} {match_cond} {scond}
|
||||||
order by
|
order by
|
||||||
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
|
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
|
||||||
idx desc,
|
idx desc,
|
||||||
@ -304,6 +307,7 @@ def get_project_name(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
limit {start}, {page_len}""".format(
|
limit {start}, {page_len}""".format(
|
||||||
fields=", ".join(['`tabProject`.{0}'.format(f) for f in fields]),
|
fields=", ".join(['`tabProject`.{0}'.format(f) for f in fields]),
|
||||||
cond=cond,
|
cond=cond,
|
||||||
|
scond=searchfields,
|
||||||
match_cond=get_match_cond(doctype),
|
match_cond=get_match_cond(doctype),
|
||||||
start=start,
|
start=start,
|
||||||
page_len=page_len), {
|
page_len=page_len), {
|
||||||
|
@ -100,6 +100,10 @@ status_map = {
|
|||||||
["Queued", "eval:self.status == 'Queued'"],
|
["Queued", "eval:self.status == 'Queued'"],
|
||||||
["Failed", "eval:self.status == 'Failed'"],
|
["Failed", "eval:self.status == 'Failed'"],
|
||||||
["Cancelled", "eval:self.docstatus == 2"],
|
["Cancelled", "eval:self.docstatus == 2"],
|
||||||
|
],
|
||||||
|
"Transaction Deletion Record": [
|
||||||
|
["Draft", None],
|
||||||
|
["Completed", "eval:self.docstatus == 1"],
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,13 +335,13 @@ def get_url(shopify_settings):
|
|||||||
|
|
||||||
if not last_order_id:
|
if not last_order_id:
|
||||||
if shopify_settings.sync_based_on == 'Date':
|
if shopify_settings.sync_based_on == 'Date':
|
||||||
url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&created_at_min={0}&since_id=0".format(
|
url = get_shopify_url("admin/api/2021-04/orders.json?limit=250&created_at_min={0}&since_id=0".format(
|
||||||
get_datetime(shopify_settings.from_date)), shopify_settings)
|
get_datetime(shopify_settings.from_date)), shopify_settings)
|
||||||
else:
|
else:
|
||||||
url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&since_id={0}".format(
|
url = get_shopify_url("admin/api/2021-04/orders.json?limit=250&since_id={0}".format(
|
||||||
shopify_settings.from_order_id), shopify_settings)
|
shopify_settings.from_order_id), shopify_settings)
|
||||||
else:
|
else:
|
||||||
url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&since_id={0}".format(last_order_id), shopify_settings)
|
url = get_shopify_url("admin/api/2021-04/orders.json?limit=250&since_id={0}".format(last_order_id), shopify_settings)
|
||||||
|
|
||||||
return url
|
return url
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ class TestMpesaSettings(unittest.TestCase):
|
|||||||
mode_of_payment = frappe.get_doc("Mode of Payment", "Mpesa-_Test")
|
mode_of_payment = frappe.get_doc("Mode of Payment", "Mpesa-_Test")
|
||||||
self.assertTrue(frappe.db.exists("Payment Gateway Account", {'payment_gateway': "Mpesa-_Test"}))
|
self.assertTrue(frappe.db.exists("Payment Gateway Account", {'payment_gateway': "Mpesa-_Test"}))
|
||||||
self.assertTrue(mode_of_payment.name)
|
self.assertTrue(mode_of_payment.name)
|
||||||
self.assertEquals(mode_of_payment.type, "Phone")
|
self.assertEqual(mode_of_payment.type, "Phone")
|
||||||
|
|
||||||
def test_processing_of_account_balance(self):
|
def test_processing_of_account_balance(self):
|
||||||
mpesa_doc = create_mpesa_settings(payment_gateway_name="_Account Balance")
|
mpesa_doc = create_mpesa_settings(payment_gateway_name="_Account Balance")
|
||||||
@ -31,11 +31,11 @@ class TestMpesaSettings(unittest.TestCase):
|
|||||||
|
|
||||||
# test integration request creation and successful update of the status on receiving callback response
|
# test integration request creation and successful update of the status on receiving callback response
|
||||||
self.assertTrue(integration_request)
|
self.assertTrue(integration_request)
|
||||||
self.assertEquals(integration_request.status, "Completed")
|
self.assertEqual(integration_request.status, "Completed")
|
||||||
|
|
||||||
# test formatting of account balance received as string to json with appropriate currency symbol
|
# test formatting of account balance received as string to json with appropriate currency symbol
|
||||||
mpesa_doc.reload()
|
mpesa_doc.reload()
|
||||||
self.assertEquals(mpesa_doc.account_balance, dumps({
|
self.assertEqual(mpesa_doc.account_balance, dumps({
|
||||||
"Working Account": {
|
"Working Account": {
|
||||||
"current_balance": "Sh 481,000.00",
|
"current_balance": "Sh 481,000.00",
|
||||||
"available_balance": "Sh 481,000.00",
|
"available_balance": "Sh 481,000.00",
|
||||||
@ -60,7 +60,7 @@ class TestMpesaSettings(unittest.TestCase):
|
|||||||
|
|
||||||
pr = pos_invoice.create_payment_request()
|
pr = pos_invoice.create_payment_request()
|
||||||
# test payment request creation
|
# test payment request creation
|
||||||
self.assertEquals(pr.payment_gateway, "Mpesa-Payment")
|
self.assertEqual(pr.payment_gateway, "Mpesa-Payment")
|
||||||
|
|
||||||
# submitting payment request creates integration requests with random id
|
# submitting payment request creates integration requests with random id
|
||||||
integration_req_ids = frappe.get_all("Integration Request", filters={
|
integration_req_ids = frappe.get_all("Integration Request", filters={
|
||||||
@ -75,12 +75,12 @@ class TestMpesaSettings(unittest.TestCase):
|
|||||||
|
|
||||||
# test integration request creation and successful update of the status on receiving callback response
|
# test integration request creation and successful update of the status on receiving callback response
|
||||||
self.assertTrue(integration_request)
|
self.assertTrue(integration_request)
|
||||||
self.assertEquals(integration_request.status, "Completed")
|
self.assertEqual(integration_request.status, "Completed")
|
||||||
|
|
||||||
pos_invoice.reload()
|
pos_invoice.reload()
|
||||||
integration_request.reload()
|
integration_request.reload()
|
||||||
self.assertEquals(pos_invoice.mpesa_receipt_number, "LGR7OWQX0R")
|
self.assertEqual(pos_invoice.mpesa_receipt_number, "LGR7OWQX0R")
|
||||||
self.assertEquals(integration_request.status, "Completed")
|
self.assertEqual(integration_request.status, "Completed")
|
||||||
|
|
||||||
frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
|
frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
|
||||||
integration_request.delete()
|
integration_request.delete()
|
||||||
@ -104,7 +104,7 @@ class TestMpesaSettings(unittest.TestCase):
|
|||||||
|
|
||||||
pr = pos_invoice.create_payment_request()
|
pr = pos_invoice.create_payment_request()
|
||||||
# test payment request creation
|
# test payment request creation
|
||||||
self.assertEquals(pr.payment_gateway, "Mpesa-Payment")
|
self.assertEqual(pr.payment_gateway, "Mpesa-Payment")
|
||||||
|
|
||||||
# submitting payment request creates integration requests with random id
|
# submitting payment request creates integration requests with random id
|
||||||
integration_req_ids = frappe.get_all("Integration Request", filters={
|
integration_req_ids = frappe.get_all("Integration Request", filters={
|
||||||
@ -126,12 +126,12 @@ class TestMpesaSettings(unittest.TestCase):
|
|||||||
verify_transaction(**callback_response)
|
verify_transaction(**callback_response)
|
||||||
# test completion of integration request
|
# test completion of integration request
|
||||||
integration_request = frappe.get_doc("Integration Request", integration_req_ids[i])
|
integration_request = frappe.get_doc("Integration Request", integration_req_ids[i])
|
||||||
self.assertEquals(integration_request.status, "Completed")
|
self.assertEqual(integration_request.status, "Completed")
|
||||||
integration_requests.append(integration_request)
|
integration_requests.append(integration_request)
|
||||||
|
|
||||||
# check receipt number once all the integration requests are completed
|
# check receipt number once all the integration requests are completed
|
||||||
pos_invoice.reload()
|
pos_invoice.reload()
|
||||||
self.assertEquals(pos_invoice.mpesa_receipt_number, ', '.join(mpesa_receipt_numbers))
|
self.assertEqual(pos_invoice.mpesa_receipt_number, ', '.join(mpesa_receipt_numbers))
|
||||||
|
|
||||||
frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
|
frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
|
||||||
[d.delete() for d in integration_requests]
|
[d.delete() for d in integration_requests]
|
||||||
@ -155,7 +155,7 @@ class TestMpesaSettings(unittest.TestCase):
|
|||||||
|
|
||||||
pr = pos_invoice.create_payment_request()
|
pr = pos_invoice.create_payment_request()
|
||||||
# test payment request creation
|
# test payment request creation
|
||||||
self.assertEquals(pr.payment_gateway, "Mpesa-Payment")
|
self.assertEqual(pr.payment_gateway, "Mpesa-Payment")
|
||||||
|
|
||||||
# submitting payment request creates integration requests with random id
|
# submitting payment request creates integration requests with random id
|
||||||
integration_req_ids = frappe.get_all("Integration Request", filters={
|
integration_req_ids = frappe.get_all("Integration Request", filters={
|
||||||
@ -175,7 +175,7 @@ class TestMpesaSettings(unittest.TestCase):
|
|||||||
verify_transaction(**callback_response)
|
verify_transaction(**callback_response)
|
||||||
# test completion of integration request
|
# test completion of integration request
|
||||||
integration_request = frappe.get_doc("Integration Request", integration_req_ids[0])
|
integration_request = frappe.get_doc("Integration Request", integration_req_ids[0])
|
||||||
self.assertEquals(integration_request.status, "Completed")
|
self.assertEqual(integration_request.status, "Completed")
|
||||||
|
|
||||||
# now one request is completed
|
# now one request is completed
|
||||||
# second integration request fails
|
# second integration request fails
|
||||||
@ -187,7 +187,7 @@ class TestMpesaSettings(unittest.TestCase):
|
|||||||
'name': ['not in', integration_req_ids]
|
'name': ['not in', integration_req_ids]
|
||||||
}, pluck="name")
|
}, pluck="name")
|
||||||
|
|
||||||
self.assertEquals(len(new_integration_req_ids), 1)
|
self.assertEqual(len(new_integration_req_ids), 1)
|
||||||
|
|
||||||
frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
|
frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
|
||||||
frappe.db.sql("delete from `tabIntegration Request` where integration_request_service = 'Mpesa'")
|
frappe.db.sql("delete from `tabIntegration Request` where integration_request_service = 'Mpesa'")
|
||||||
|
@ -30,14 +30,14 @@ class ShopifySettings(Document):
|
|||||||
webhooks = ["orders/create", "orders/paid", "orders/fulfilled"]
|
webhooks = ["orders/create", "orders/paid", "orders/fulfilled"]
|
||||||
# url = get_shopify_url('admin/webhooks.json', self)
|
# url = get_shopify_url('admin/webhooks.json', self)
|
||||||
created_webhooks = [d.method for d in self.webhooks]
|
created_webhooks = [d.method for d in self.webhooks]
|
||||||
url = get_shopify_url('admin/api/2020-04/webhooks.json', self)
|
url = get_shopify_url('admin/api/2021-04/webhooks.json', self)
|
||||||
for method in webhooks:
|
for method in webhooks:
|
||||||
session = get_request_session()
|
session = get_request_session()
|
||||||
try:
|
try:
|
||||||
res = session.post(url, data=json.dumps({
|
res = session.post(url, data=json.dumps({
|
||||||
"webhook": {
|
"webhook": {
|
||||||
"topic": method,
|
"topic": method,
|
||||||
"address": get_webhook_address(connector_name='shopify_connection', method='store_request_data'),
|
"address": get_webhook_address(connector_name='shopify_connection', method='store_request_data', force_https=True),
|
||||||
"format": "json"
|
"format": "json"
|
||||||
}
|
}
|
||||||
}), headers=get_header(self))
|
}), headers=get_header(self))
|
||||||
@ -56,7 +56,7 @@ class ShopifySettings(Document):
|
|||||||
deleted_webhooks = []
|
deleted_webhooks = []
|
||||||
|
|
||||||
for d in self.webhooks:
|
for d in self.webhooks:
|
||||||
url = get_shopify_url('admin/api/2020-04/webhooks/{0}.json'.format(d.webhook_id), self)
|
url = get_shopify_url('admin/api/2021-04/webhooks/{0}.json'.format(d.webhook_id), self)
|
||||||
try:
|
try:
|
||||||
res = session.delete(url, headers=get_header(self))
|
res = session.delete(url, headers=get_header(self))
|
||||||
res.raise_for_status()
|
res.raise_for_status()
|
||||||
|
@ -32,10 +32,12 @@ def create_customer(shopify_customer, shopify_settings):
|
|||||||
raise e
|
raise e
|
||||||
|
|
||||||
def create_customer_address(customer, shopify_customer):
|
def create_customer_address(customer, shopify_customer):
|
||||||
if not shopify_customer.get("addresses"):
|
addresses = shopify_customer.get("addresses", [])
|
||||||
return
|
|
||||||
|
|
||||||
for i, address in enumerate(shopify_customer.get("addresses")):
|
if not addresses and "default_address" in shopify_customer:
|
||||||
|
addresses.append(shopify_customer["default_address"])
|
||||||
|
|
||||||
|
for i, address in enumerate(addresses):
|
||||||
address_title, address_type = get_address_title_and_type(customer.customer_name, i)
|
address_title, address_type = get_address_title_and_type(customer.customer_name, i)
|
||||||
try :
|
try :
|
||||||
frappe.get_doc({
|
frappe.get_doc({
|
||||||
|
@ -8,7 +8,7 @@ from erpnext.erpnext_integrations.doctype.shopify_settings.shopify_settings impo
|
|||||||
shopify_variants_attr_list = ["option1", "option2", "option3"]
|
shopify_variants_attr_list = ["option1", "option2", "option3"]
|
||||||
|
|
||||||
def sync_item_from_shopify(shopify_settings, item):
|
def sync_item_from_shopify(shopify_settings, item):
|
||||||
url = get_shopify_url("admin/api/2020-04/products/{0}.json".format(item.get("product_id")), shopify_settings)
|
url = get_shopify_url("admin/api/2021-04/products/{0}.json".format(item.get("product_id")), shopify_settings)
|
||||||
session = get_request_session()
|
session = get_request_session()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -28,7 +28,7 @@ def validate_webhooks_request(doctype, hmac_key, secret_key='secret'):
|
|||||||
|
|
||||||
return innerfn
|
return innerfn
|
||||||
|
|
||||||
def get_webhook_address(connector_name, method, exclude_uri=False):
|
def get_webhook_address(connector_name, method, exclude_uri=False, force_https=False):
|
||||||
endpoint = "erpnext.erpnext_integrations.connectors.{0}.{1}".format(connector_name, method)
|
endpoint = "erpnext.erpnext_integrations.connectors.{0}.{1}".format(connector_name, method)
|
||||||
|
|
||||||
if exclude_uri:
|
if exclude_uri:
|
||||||
@ -39,7 +39,11 @@ def get_webhook_address(connector_name, method, exclude_uri=False):
|
|||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
url = "http://localhost:8000"
|
url = "http://localhost:8000"
|
||||||
|
|
||||||
server_url = '{uri.scheme}://{uri.netloc}/api/method/{endpoint}'.format(uri=urlparse(url), endpoint=endpoint)
|
url_data = urlparse(url)
|
||||||
|
scheme = "https" if force_https else url_data.scheme
|
||||||
|
netloc = url_data.netloc
|
||||||
|
|
||||||
|
server_url = f"{scheme}://{netloc}/api/method/{endpoint}"
|
||||||
|
|
||||||
return server_url
|
return server_url
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ class TestClinicalProcedure(unittest.TestCase):
|
|||||||
|
|
||||||
procedure_template.disabled = 1
|
procedure_template.disabled = 1
|
||||||
procedure_template.save()
|
procedure_template.save()
|
||||||
self.assertEquals(frappe.db.get_value('Item', procedure_template.item, 'disabled'), 1)
|
self.assertEqual(frappe.db.get_value('Item', procedure_template.item, 'disabled'), 1)
|
||||||
|
|
||||||
def test_consumables(self):
|
def test_consumables(self):
|
||||||
patient, medical_department, practitioner = create_healthcare_docs()
|
patient, medical_department, practitioner = create_healthcare_docs()
|
||||||
|
@ -18,7 +18,7 @@ class TestLabTest(unittest.TestCase):
|
|||||||
|
|
||||||
lab_template.disabled = 1
|
lab_template.disabled = 1
|
||||||
lab_template.save()
|
lab_template.save()
|
||||||
self.assertEquals(frappe.db.get_value('Item', lab_template.item, 'disabled'), 1)
|
self.assertEqual(frappe.db.get_value('Item', lab_template.item, 'disabled'), 1)
|
||||||
|
|
||||||
lab_template.reload()
|
lab_template.reload()
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ class TestLabTest(unittest.TestCase):
|
|||||||
|
|
||||||
# sample collection should not be created
|
# sample collection should not be created
|
||||||
lab_test.reload()
|
lab_test.reload()
|
||||||
self.assertEquals(lab_test.sample, None)
|
self.assertEqual(lab_test.sample, None)
|
||||||
|
|
||||||
def test_create_lab_tests_from_sales_invoice(self):
|
def test_create_lab_tests_from_sales_invoice(self):
|
||||||
sales_invoice = create_sales_invoice()
|
sales_invoice = create_sales_invoice()
|
||||||
|
@ -20,13 +20,13 @@ class TestPatientAppointment(unittest.TestCase):
|
|||||||
patient, medical_department, practitioner = create_healthcare_docs()
|
patient, medical_department, practitioner = create_healthcare_docs()
|
||||||
frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 0)
|
frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 0)
|
||||||
appointment = create_appointment(patient, practitioner, nowdate())
|
appointment = create_appointment(patient, practitioner, nowdate())
|
||||||
self.assertEquals(appointment.status, 'Open')
|
self.assertEqual(appointment.status, 'Open')
|
||||||
appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2))
|
appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2))
|
||||||
self.assertEquals(appointment.status, 'Scheduled')
|
self.assertEqual(appointment.status, 'Scheduled')
|
||||||
encounter = create_encounter(appointment)
|
encounter = create_encounter(appointment)
|
||||||
self.assertEquals(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed')
|
self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed')
|
||||||
encounter.cancel()
|
encounter.cancel()
|
||||||
self.assertEquals(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Open')
|
self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Open')
|
||||||
|
|
||||||
def test_start_encounter(self):
|
def test_start_encounter(self):
|
||||||
patient, medical_department, practitioner = create_healthcare_docs()
|
patient, medical_department, practitioner = create_healthcare_docs()
|
||||||
|
@ -18,24 +18,24 @@ class TestTherapyPlan(unittest.TestCase):
|
|||||||
|
|
||||||
def test_status(self):
|
def test_status(self):
|
||||||
plan = create_therapy_plan()
|
plan = create_therapy_plan()
|
||||||
self.assertEquals(plan.status, 'Not Started')
|
self.assertEqual(plan.status, 'Not Started')
|
||||||
|
|
||||||
session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company')
|
session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company')
|
||||||
frappe.get_doc(session).submit()
|
frappe.get_doc(session).submit()
|
||||||
self.assertEquals(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'In Progress')
|
self.assertEqual(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'In Progress')
|
||||||
|
|
||||||
session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company')
|
session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company')
|
||||||
frappe.get_doc(session).submit()
|
frappe.get_doc(session).submit()
|
||||||
self.assertEquals(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'Completed')
|
self.assertEqual(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'Completed')
|
||||||
|
|
||||||
patient, medical_department, practitioner = create_healthcare_docs()
|
patient, medical_department, practitioner = create_healthcare_docs()
|
||||||
appointment = create_appointment(patient, practitioner, nowdate())
|
appointment = create_appointment(patient, practitioner, nowdate())
|
||||||
session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company', appointment.name)
|
session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company', appointment.name)
|
||||||
session = frappe.get_doc(session)
|
session = frappe.get_doc(session)
|
||||||
session.submit()
|
session.submit()
|
||||||
self.assertEquals(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed')
|
self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed')
|
||||||
session.cancel()
|
session.cancel()
|
||||||
self.assertEquals(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Open')
|
self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Open')
|
||||||
|
|
||||||
def test_therapy_plan_from_template(self):
|
def test_therapy_plan_from_template(self):
|
||||||
patient = create_patient()
|
patient = create_patient()
|
||||||
@ -49,7 +49,7 @@ class TestTherapyPlan(unittest.TestCase):
|
|||||||
si.save()
|
si.save()
|
||||||
|
|
||||||
therapy_plan_template_amt = frappe.db.get_value('Therapy Plan Template', template, 'total_amount')
|
therapy_plan_template_amt = frappe.db.get_value('Therapy Plan Template', template, 'total_amount')
|
||||||
self.assertEquals(si.items[0].amount, therapy_plan_template_amt)
|
self.assertEqual(si.items[0].amount, therapy_plan_template_amt)
|
||||||
|
|
||||||
|
|
||||||
def create_therapy_plan(template=None):
|
def create_therapy_plan(template=None):
|
||||||
|
@ -13,7 +13,7 @@ class TestTherapyType(unittest.TestCase):
|
|||||||
|
|
||||||
therapy_type.disabled = 1
|
therapy_type.disabled = 1
|
||||||
therapy_type.save()
|
therapy_type.save()
|
||||||
self.assertEquals(frappe.db.get_value('Item', therapy_type.item, 'disabled'), 1)
|
self.assertEqual(frappe.db.get_value('Item', therapy_type.item, 'disabled'), 1)
|
||||||
|
|
||||||
def create_therapy_type():
|
def create_therapy_type():
|
||||||
exercise = create_exercise_type()
|
exercise = create_exercise_type()
|
||||||
|
@ -426,7 +426,8 @@ regional_overrides = {
|
|||||||
'erpnext.hr.utils.calculate_annual_eligible_hra_exemption': 'erpnext.regional.india.utils.calculate_annual_eligible_hra_exemption',
|
'erpnext.hr.utils.calculate_annual_eligible_hra_exemption': 'erpnext.regional.india.utils.calculate_annual_eligible_hra_exemption',
|
||||||
'erpnext.hr.utils.calculate_hra_exemption_for_period': 'erpnext.regional.india.utils.calculate_hra_exemption_for_period',
|
'erpnext.hr.utils.calculate_hra_exemption_for_period': 'erpnext.regional.india.utils.calculate_hra_exemption_for_period',
|
||||||
'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_regional_gl_entries': 'erpnext.regional.india.utils.make_regional_gl_entries',
|
'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_regional_gl_entries': 'erpnext.regional.india.utils.make_regional_gl_entries',
|
||||||
'erpnext.controllers.accounts_controller.validate_einvoice_fields': 'erpnext.regional.india.e_invoice.utils.validate_einvoice_fields'
|
'erpnext.controllers.accounts_controller.validate_einvoice_fields': 'erpnext.regional.india.e_invoice.utils.validate_einvoice_fields',
|
||||||
|
'erpnext.assets.doctype.asset.asset.get_depreciation_amount': 'erpnext.regional.india.utils.get_depreciation_amount'
|
||||||
},
|
},
|
||||||
'United Arab Emirates': {
|
'United Arab Emirates': {
|
||||||
'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data',
|
'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data',
|
||||||
|
@ -68,19 +68,19 @@ class TestCompensatoryLeaveRequest(unittest.TestCase):
|
|||||||
filters = dict(transaction_name=compensatory_leave_request.leave_allocation)
|
filters = dict(transaction_name=compensatory_leave_request.leave_allocation)
|
||||||
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=filters)
|
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=filters)
|
||||||
|
|
||||||
self.assertEquals(len(leave_ledger_entry), 1)
|
self.assertEqual(len(leave_ledger_entry), 1)
|
||||||
self.assertEquals(leave_ledger_entry[0].employee, compensatory_leave_request.employee)
|
self.assertEqual(leave_ledger_entry[0].employee, compensatory_leave_request.employee)
|
||||||
self.assertEquals(leave_ledger_entry[0].leave_type, compensatory_leave_request.leave_type)
|
self.assertEqual(leave_ledger_entry[0].leave_type, compensatory_leave_request.leave_type)
|
||||||
self.assertEquals(leave_ledger_entry[0].leaves, 1)
|
self.assertEqual(leave_ledger_entry[0].leaves, 1)
|
||||||
|
|
||||||
# check reverse leave ledger entry on cancellation
|
# check reverse leave ledger entry on cancellation
|
||||||
compensatory_leave_request.cancel()
|
compensatory_leave_request.cancel()
|
||||||
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=filters, order_by = 'creation desc')
|
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=filters, order_by = 'creation desc')
|
||||||
|
|
||||||
self.assertEquals(len(leave_ledger_entry), 2)
|
self.assertEqual(len(leave_ledger_entry), 2)
|
||||||
self.assertEquals(leave_ledger_entry[0].employee, compensatory_leave_request.employee)
|
self.assertEqual(leave_ledger_entry[0].employee, compensatory_leave_request.employee)
|
||||||
self.assertEquals(leave_ledger_entry[0].leave_type, compensatory_leave_request.leave_type)
|
self.assertEqual(leave_ledger_entry[0].leave_type, compensatory_leave_request.leave_type)
|
||||||
self.assertEquals(leave_ledger_entry[0].leaves, -1)
|
self.assertEqual(leave_ledger_entry[0].leaves, -1)
|
||||||
|
|
||||||
def get_compensatory_leave_request(employee, leave_date=today()):
|
def get_compensatory_leave_request(employee, leave_date=today()):
|
||||||
prev_comp_leave_req = frappe.db.get_value('Compensatory Leave Request',
|
prev_comp_leave_req = frappe.db.get_value('Compensatory Leave Request',
|
||||||
|
@ -182,6 +182,10 @@
|
|||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 0,
|
"submit": 0,
|
||||||
"write": 1
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"read": 1,
|
||||||
|
"role": "Sales User"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
@ -191,4 +195,4 @@
|
|||||||
"track_changes": 0,
|
"track_changes": 0,
|
||||||
"track_seen": 0,
|
"track_seen": 0,
|
||||||
"track_views": 0
|
"track_views": 0
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ frappe.ui.form.on('Employee Advance', {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
frm.set_query('salary_component', function(doc) {
|
frm.set_query('salary_component', function() {
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
"type": "Deduction"
|
"type": "Deduction"
|
||||||
@ -44,48 +44,49 @@ frappe.ui.form.on('Employee Advance', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
if (frm.doc.docstatus===1
|
if (frm.doc.docstatus === 1 &&
|
||||||
&& (flt(frm.doc.paid_amount) < flt(frm.doc.advance_amount))
|
(flt(frm.doc.paid_amount) < flt(frm.doc.advance_amount)) &&
|
||||||
&& frappe.model.can_create("Payment Entry")) {
|
frappe.model.can_create("Payment Entry")) {
|
||||||
frm.add_custom_button(__('Payment'),
|
frm.add_custom_button(__('Payment'),
|
||||||
function() { frm.events.make_payment_entry(frm); }, __('Create'));
|
function () {
|
||||||
}
|
frm.events.make_payment_entry(frm);
|
||||||
else if (
|
}, __('Create'));
|
||||||
frm.doc.docstatus === 1
|
} else if (
|
||||||
&& flt(frm.doc.claimed_amount) < flt(frm.doc.paid_amount) - flt(frm.doc.return_amount)
|
frm.doc.docstatus === 1 &&
|
||||||
&& frappe.model.can_create("Expense Claim")
|
flt(frm.doc.claimed_amount) < flt(frm.doc.paid_amount) - flt(frm.doc.return_amount) &&
|
||||||
|
frappe.model.can_create("Expense Claim")
|
||||||
) {
|
) {
|
||||||
frm.add_custom_button(
|
frm.add_custom_button(
|
||||||
__("Expense Claim"),
|
__("Expense Claim"),
|
||||||
function() {
|
function () {
|
||||||
frm.events.make_expense_claim(frm);
|
frm.events.make_expense_claim(frm);
|
||||||
},
|
},
|
||||||
__('Create')
|
__('Create')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frm.doc.docstatus === 1
|
if (frm.doc.docstatus === 1 &&
|
||||||
&& (flt(frm.doc.claimed_amount) < flt(frm.doc.paid_amount) && flt(frm.doc.paid_amount) != flt(frm.doc.return_amount))) {
|
(flt(frm.doc.claimed_amount) < flt(frm.doc.paid_amount) && flt(frm.doc.paid_amount) != flt(frm.doc.return_amount))) {
|
||||||
|
|
||||||
if (frm.doc.repay_unclaimed_amount_from_salary == 0 && frappe.model.can_create("Journal Entry")){
|
if (frm.doc.repay_unclaimed_amount_from_salary == 0 && frappe.model.can_create("Journal Entry")) {
|
||||||
frm.add_custom_button(__("Return"), function() {
|
frm.add_custom_button(__("Return"), function() {
|
||||||
frm.trigger('make_return_entry');
|
frm.trigger('make_return_entry');
|
||||||
}, __('Create'));
|
}, __('Create'));
|
||||||
}else if (frm.doc.repay_unclaimed_amount_from_salary == 1 && frappe.model.can_create("Additional Salary")){
|
} else if (frm.doc.repay_unclaimed_amount_from_salary == 1 && frappe.model.can_create("Additional Salary")) {
|
||||||
frm.add_custom_button(__("Deduction from salary"), function() {
|
frm.add_custom_button(__("Deduction from salary"), function() {
|
||||||
frm.events.make_deduction_via_additional_salary(frm);
|
frm.events.make_deduction_via_additional_salary(frm);
|
||||||
}, __('Create'));
|
}, __('Create'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
make_deduction_via_additional_salary: function(frm){
|
make_deduction_via_additional_salary: function(frm) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.hr.doctype.employee_advance.employee_advance.create_return_through_additional_salary",
|
method: "erpnext.hr.doctype.employee_advance.employee_advance.create_return_through_additional_salary",
|
||||||
args: {
|
args: {
|
||||||
doc: frm.doc
|
doc: frm.doc
|
||||||
},
|
},
|
||||||
callback: function (r){
|
callback: function(r) {
|
||||||
var doclist = frappe.model.sync(r.message);
|
var doclist = frappe.model.sync(r.message);
|
||||||
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
|
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
|
||||||
}
|
}
|
||||||
@ -94,7 +95,7 @@ frappe.ui.form.on('Employee Advance', {
|
|||||||
|
|
||||||
make_payment_entry: function(frm) {
|
make_payment_entry: function(frm) {
|
||||||
var method = "erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry";
|
var method = "erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry";
|
||||||
if(frm.doc.__onload && frm.doc.__onload.make_payment_via_journal_entry) {
|
if (frm.doc.__onload && frm.doc.__onload.make_payment_via_journal_entry) {
|
||||||
method = "erpnext.hr.doctype.employee_advance.employee_advance.make_bank_entry";
|
method = "erpnext.hr.doctype.employee_advance.employee_advance.make_bank_entry";
|
||||||
}
|
}
|
||||||
return frappe.call({
|
return frappe.call({
|
||||||
@ -148,11 +149,11 @@ frappe.ui.form.on('Employee Advance', {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
employee: function (frm) {
|
employee: function(frm) {
|
||||||
if (frm.doc.employee) {
|
if (frm.doc.employee) {
|
||||||
frappe.run_serially([
|
frappe.run_serially([
|
||||||
() => frm.trigger('get_employee_currency'),
|
() => frm.trigger('get_employee_currency'),
|
||||||
() => frm.trigger('get_pending_amount')
|
() => frm.trigger('get_pending_amount')
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -199,7 +200,7 @@ frappe.ui.form.on('Employee Advance', {
|
|||||||
} else {
|
} else {
|
||||||
frm.set_value("exchange_rate", 1.0);
|
frm.set_value("exchange_rate", 1.0);
|
||||||
frm.set_df_property('exchange_rate', 'hidden', 1);
|
frm.set_df_property('exchange_rate', 'hidden', 1);
|
||||||
frm.set_df_property("exchange_rate", "description", "" );
|
frm.set_df_property("exchange_rate", "description", "");
|
||||||
}
|
}
|
||||||
frm.refresh_fields();
|
frm.refresh_fields();
|
||||||
}
|
}
|
||||||
@ -215,8 +216,8 @@ frappe.ui.form.on('Employee Advance', {
|
|||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
frm.set_value("exchange_rate", flt(r.message));
|
frm.set_value("exchange_rate", flt(r.message));
|
||||||
frm.set_df_property('exchange_rate', 'hidden', 0);
|
frm.set_df_property('exchange_rate', 'hidden', 0);
|
||||||
frm.set_df_property("exchange_rate", "description", "1 " + frm.doc.currency
|
frm.set_df_property("exchange_rate", "description", "1 " + frm.doc.currency +
|
||||||
+ " = [?] " + company_currency);
|
" = [?] " + company_currency);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,10 @@ from frappe import _
|
|||||||
def get_data():
|
def get_data():
|
||||||
return {
|
return {
|
||||||
'fieldname': 'employee_advance',
|
'fieldname': 'employee_advance',
|
||||||
'non_standard_fieldnames': {
|
'non_standard_fieldnames': {
|
||||||
'Payment Entry': 'reference_name',
|
'Payment Entry': 'reference_name',
|
||||||
'Journal Entry': 'reference_name'
|
'Journal Entry': 'reference_name'
|
||||||
},
|
},
|
||||||
'transactions': [
|
'transactions': [
|
||||||
{
|
{
|
||||||
'items': ['Expense Claim']
|
'items': ['Expense Claim']
|
||||||
|
0
erpnext/hr/doctype/employee_referral/__init__.py
Normal file
0
erpnext/hr/doctype/employee_referral/__init__.py
Normal file
68
erpnext/hr/doctype/employee_referral/employee_referral.js
Normal file
68
erpnext/hr/doctype/employee_referral/employee_referral.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
frappe.ui.form.on("Employee Referral", {
|
||||||
|
refresh: function(frm) {
|
||||||
|
if (frm.doc.docstatus === 1 && frm.doc.status === "Pending") {
|
||||||
|
frm.add_custom_button(__("Reject Employee Referral"), function() {
|
||||||
|
frappe.confirm(
|
||||||
|
__("Are you sure you want to reject the Employee Referral?"),
|
||||||
|
function() {
|
||||||
|
frm.doc.status = "Rejected";
|
||||||
|
frm.dirty();
|
||||||
|
frm.save_or_update();
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
frm.add_custom_button(__("Create Job Applicant"), function() {
|
||||||
|
frm.events.create_job_applicant(frm);
|
||||||
|
}).addClass("btn-primary");
|
||||||
|
}
|
||||||
|
|
||||||
|
// To check whether Payment is done or not
|
||||||
|
if (frm.doc.docstatus === 1 && frm.doc.status === "Accepted") {
|
||||||
|
frappe.db.get_list("Additional Salary", {
|
||||||
|
filters: {
|
||||||
|
ref_docname: cur_frm.doc.name,
|
||||||
|
docstatus: 1
|
||||||
|
},
|
||||||
|
fields: ["count(name) as additional_salary_count"]
|
||||||
|
}).then((data) => {
|
||||||
|
|
||||||
|
let additional_salary_count = data[0].additional_salary_count;
|
||||||
|
|
||||||
|
if (frm.doc.is_applicable_for_referral_bonus && !additional_salary_count) {
|
||||||
|
frm.add_custom_button(__("Create Additional Salary"), function() {
|
||||||
|
frm.events.create_additional_salary(frm);
|
||||||
|
}).addClass("btn-primary");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
create_job_applicant: function(frm) {
|
||||||
|
frappe.model.open_mapped_doc({
|
||||||
|
method: "erpnext.hr.doctype.employee_referral.employee_referral.create_job_applicant",
|
||||||
|
frm: frm
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
create_additional_salary: function(frm) {
|
||||||
|
frappe.call({
|
||||||
|
method: "erpnext.hr.doctype.employee_referral.employee_referral.create_additional_salary",
|
||||||
|
args: {
|
||||||
|
doc: frm.doc
|
||||||
|
},
|
||||||
|
callback: function (r) {
|
||||||
|
var doclist = frappe.model.sync(r.message);
|
||||||
|
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
294
erpnext/hr/doctype/employee_referral/employee_referral.json
Normal file
294
erpnext/hr/doctype/employee_referral/employee_referral.json
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"autoname": "format:HR-REF-{####}",
|
||||||
|
"creation": "2021-03-23 14:54:45.047051",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"first_name",
|
||||||
|
"last_name",
|
||||||
|
"full_name",
|
||||||
|
"email",
|
||||||
|
"contact_no",
|
||||||
|
"resume",
|
||||||
|
"resume_link",
|
||||||
|
"column_break_6",
|
||||||
|
"date",
|
||||||
|
"status",
|
||||||
|
"for_designation",
|
||||||
|
"current_employer",
|
||||||
|
"current_job_title",
|
||||||
|
"referrer_details_section",
|
||||||
|
"referrer",
|
||||||
|
"referrer_name",
|
||||||
|
"column_break_14",
|
||||||
|
"is_applicable_for_referral_bonus",
|
||||||
|
"referral_payment_status",
|
||||||
|
"department",
|
||||||
|
"additional_information_section",
|
||||||
|
"qualification_reason",
|
||||||
|
"work_references",
|
||||||
|
"amended_from"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "first_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "First Name ",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "last_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Last Name",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "full_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Full Name",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "contact_no",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_standard_filter": 1,
|
||||||
|
"label": "Contact No.",
|
||||||
|
"options": "Phone"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "current_employer",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Current Employer "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_6",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"in_standard_filter": 1,
|
||||||
|
"label": "Date",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 1,
|
||||||
|
"fieldname": "status",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"in_standard_filter": 1,
|
||||||
|
"label": "Status",
|
||||||
|
"no_copy": 1,
|
||||||
|
"options": "Pending\nIn Process\nAccepted\nRejected",
|
||||||
|
"permlevel": 1,
|
||||||
|
"read_only": 1,
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "current_job_title",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Current Job Title"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "resume",
|
||||||
|
"fieldtype": "Attach",
|
||||||
|
"label": "Resume"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "referrer_details_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Referrer Details"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "employee.department",
|
||||||
|
"fieldname": "department",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Department",
|
||||||
|
"options": "Department",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "additional_information_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Additional Information "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "work_references",
|
||||||
|
"fieldtype": "Text Editor",
|
||||||
|
"label": "Work References"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "amended_from",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Amended From",
|
||||||
|
"no_copy": 1,
|
||||||
|
"options": "Employee Referral",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_14",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "for_designation",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"in_standard_filter": 1,
|
||||||
|
"label": "For Designation ",
|
||||||
|
"options": "Designation",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "email",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"in_standard_filter": 1,
|
||||||
|
"label": "Email",
|
||||||
|
"options": "Email",
|
||||||
|
"reqd": 1,
|
||||||
|
"unique": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "1",
|
||||||
|
"fieldname": "is_applicable_for_referral_bonus",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Is Applicable for Referral Bonus"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "qualification_reason",
|
||||||
|
"fieldtype": "Text Editor",
|
||||||
|
"label": "Why is this Candidate Qualified for this Position?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "referrer",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_standard_filter": 1,
|
||||||
|
"label": "Referrer",
|
||||||
|
"options": "Employee",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "referrer.employee_name",
|
||||||
|
"fieldname": "referrer_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Referrer Name",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "resume_link",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Resume Link"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "referral_payment_status",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "Referral Bonus Payment Status",
|
||||||
|
"options": "\nUnpaid\nPaid",
|
||||||
|
"read_only": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"is_submittable": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2021-04-26 21:21:38.094086",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "HR",
|
||||||
|
"name": "Employee Referral",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "System Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"amend": 1,
|
||||||
|
"create": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Employee",
|
||||||
|
"share": 1,
|
||||||
|
"submit": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"amend": 1,
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "HR Manager",
|
||||||
|
"share": 1,
|
||||||
|
"submit": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"amend": 1,
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "HR User",
|
||||||
|
"share": 1,
|
||||||
|
"submit": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"permlevel": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "HR Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"permlevel": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "HR User",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"permlevel": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Employee",
|
||||||
|
"share": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"title_field": "full_name"
|
||||||
|
}
|
71
erpnext/hr/doctype/employee_referral/employee_referral.py
Normal file
71
erpnext/hr/doctype/employee_referral/employee_referral.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2021, 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 get_link_to_form
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
class EmployeeReferral(Document):
|
||||||
|
def validate(self):
|
||||||
|
self.set_full_name()
|
||||||
|
self.set_referral_bonus_payment_status()
|
||||||
|
|
||||||
|
def set_full_name(self):
|
||||||
|
self.full_name = " ".join(filter(None, [self.first_name, self.last_name]))
|
||||||
|
|
||||||
|
def set_referral_bonus_payment_status(self):
|
||||||
|
if not self.is_applicable_for_referral_bonus:
|
||||||
|
self.referral_payment_status = ""
|
||||||
|
else:
|
||||||
|
if not self.referral_payment_status:
|
||||||
|
self.referral_payment_status = "Unpaid"
|
||||||
|
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def create_job_applicant(source_name, target_doc=None):
|
||||||
|
emp_ref = frappe.get_doc("Employee Referral", source_name)
|
||||||
|
#just for Api call if some set status apart from default Status
|
||||||
|
status = emp_ref.status
|
||||||
|
if emp_ref.status in ["Pending", "In process"]:
|
||||||
|
status = "Open"
|
||||||
|
|
||||||
|
job_applicant = frappe.new_doc("Job Applicant")
|
||||||
|
job_applicant.employee_referral = emp_ref.name
|
||||||
|
job_applicant.status = status
|
||||||
|
job_applicant.applicant_name = emp_ref.full_name
|
||||||
|
job_applicant.email_id = emp_ref.email
|
||||||
|
job_applicant.phone_number = emp_ref.contact_no
|
||||||
|
job_applicant.resume_attachment = emp_ref.resume
|
||||||
|
job_applicant.resume_link = emp_ref.resume_link
|
||||||
|
job_applicant.save()
|
||||||
|
|
||||||
|
frappe.msgprint(_("Job Applicant {0} created successfully.").format(
|
||||||
|
get_link_to_form("Job Applicant", job_applicant.name)),
|
||||||
|
title=_("Success"), indicator="green")
|
||||||
|
|
||||||
|
emp_ref.db_set("status", "In Process")
|
||||||
|
|
||||||
|
return job_applicant
|
||||||
|
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def create_additional_salary(doc):
|
||||||
|
import json
|
||||||
|
from six import string_types
|
||||||
|
|
||||||
|
if isinstance(doc, string_types):
|
||||||
|
doc = frappe._dict(json.loads(doc))
|
||||||
|
|
||||||
|
if not frappe.db.exists("Additional Salary", {"ref_docname": doc.name}):
|
||||||
|
additional_salary = frappe.new_doc("Additional Salary")
|
||||||
|
additional_salary.employee = doc.referrer
|
||||||
|
additional_salary.company = frappe.db.get_value("Employee", doc.referrer, "company")
|
||||||
|
additional_salary.overwrite_salary_structure_amount = 0
|
||||||
|
additional_salary.ref_doctype = doc.doctype
|
||||||
|
additional_salary.ref_docname = doc.name
|
||||||
|
|
||||||
|
return additional_salary
|
||||||
|
|
@ -0,0 +1,15 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
def get_data():
|
||||||
|
return {
|
||||||
|
'fieldname': 'employee_referral',
|
||||||
|
'non_standard_fieldnames': {
|
||||||
|
'Additional Salary': 'ref_docname'
|
||||||
|
},
|
||||||
|
'transactions': [
|
||||||
|
{
|
||||||
|
'items': ['Job Applicant', 'Additional Salary']
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
frappe.listview_settings['Employee Referral'] = {
|
||||||
|
add_fields: ["status"],
|
||||||
|
get_indicator: function (doc) {
|
||||||
|
if (doc.status == "Pending") {
|
||||||
|
return [__(doc.status), "grey", "status,=," + doc.status];
|
||||||
|
} else if (doc.status == "In Process") {
|
||||||
|
return [__(doc.status), "orange", "status,=," + doc.status];
|
||||||
|
} else if (doc.status == "Accepted") {
|
||||||
|
return [__(doc.status), "green", "status,=," + doc.status];
|
||||||
|
} else if (doc.status == "Rejected") {
|
||||||
|
return [__(doc.status), "red", "status,=," + doc.status];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,60 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
|
# See license.txt
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
from frappe.utils import today
|
||||||
|
from erpnext.hr.doctype.designation.test_designation import create_designation
|
||||||
|
from erpnext.hr.doctype.employee_referral.employee_referral import create_job_applicant, create_additional_salary
|
||||||
|
from erpnext.hr.doctype.employee.test_employee import make_employee
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
class TestEmployeeReferral(unittest.TestCase):
|
||||||
|
def test_workflow_and_status_sync(self):
|
||||||
|
emp_ref = create_employee_referral()
|
||||||
|
|
||||||
|
#Check Initial status
|
||||||
|
self.assertTrue(emp_ref.status, "Pending")
|
||||||
|
|
||||||
|
job_applicant = create_job_applicant(emp_ref.name)
|
||||||
|
|
||||||
|
|
||||||
|
#Check status sync
|
||||||
|
emp_ref.reload()
|
||||||
|
self.assertTrue(emp_ref.status, "In Process")
|
||||||
|
|
||||||
|
job_applicant.reload()
|
||||||
|
job_applicant.status = "Rejected"
|
||||||
|
job_applicant.save()
|
||||||
|
|
||||||
|
emp_ref.reload()
|
||||||
|
self.assertTrue(emp_ref.status, "Rejected")
|
||||||
|
|
||||||
|
job_applicant.reload()
|
||||||
|
job_applicant.status = "Accepted"
|
||||||
|
job_applicant.save()
|
||||||
|
|
||||||
|
emp_ref.reload()
|
||||||
|
self.assertTrue(emp_ref.status, "Accepted")
|
||||||
|
|
||||||
|
|
||||||
|
# Check for Referral reference in additional salary
|
||||||
|
|
||||||
|
add_sal = create_additional_salary(emp_ref)
|
||||||
|
self.assertTrue(add_sal.ref_docname, emp_ref.name)
|
||||||
|
|
||||||
|
|
||||||
|
def create_employee_referral():
|
||||||
|
emp_ref = frappe.new_doc("Employee Referral")
|
||||||
|
emp_ref.first_name = "Mahesh"
|
||||||
|
emp_ref.last_name = "Singh"
|
||||||
|
emp_ref.email = "a@b.c"
|
||||||
|
emp_ref.date = today()
|
||||||
|
emp_ref.for_designation = create_designation().name
|
||||||
|
emp_ref.referrer = make_employee("testassetmovemp@example.com", company="_Test Company")
|
||||||
|
emp_ref.is_applicable_for_employee_referral_compensation = 1
|
||||||
|
emp_ref.save()
|
||||||
|
emp_ref.submit()
|
||||||
|
|
||||||
|
return emp_ref
|
@ -1,626 +1,177 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_guest_to_view": 0,
|
"autoname": "HR-EMP-SEP-.YYYY.-.#####",
|
||||||
"allow_import": 0,
|
"creation": "2018-05-10 02:29:16.740490",
|
||||||
"allow_rename": 0,
|
"doctype": "DocType",
|
||||||
"autoname": "HR-EMP-SEP-.YYYY.-.#####",
|
"editable_grid": 1,
|
||||||
"beta": 0,
|
"engine": "InnoDB",
|
||||||
"creation": "2018-05-10 02:29:16.740490",
|
"field_order": [
|
||||||
"custom": 0,
|
"employee",
|
||||||
"docstatus": 0,
|
"employee_name",
|
||||||
"doctype": "DocType",
|
"department",
|
||||||
"document_type": "",
|
"designation",
|
||||||
"editable_grid": 1,
|
"employee_grade",
|
||||||
"engine": "InnoDB",
|
"column_break_7",
|
||||||
|
"company",
|
||||||
|
"boarding_status",
|
||||||
|
"resignation_letter_date",
|
||||||
|
"project",
|
||||||
|
"table_for_activity",
|
||||||
|
"employee_separation_template",
|
||||||
|
"activities",
|
||||||
|
"notify_users_by_email",
|
||||||
|
"section_break_14",
|
||||||
|
"exit_interview",
|
||||||
|
"amended_from"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "employee",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Link",
|
||||||
"allow_on_submit": 0,
|
"label": "Employee",
|
||||||
"bold": 0,
|
"options": "Employee",
|
||||||
"collapsible": 0,
|
"reqd": 1
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "employee",
|
|
||||||
"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": "Employee",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Employee",
|
|
||||||
"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_from": "employee.employee_name",
|
|
||||||
"fieldname": "employee_name",
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Employee Name",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "",
|
|
||||||
"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_from": "employee.resignation_letter_date",
|
|
||||||
"fieldname": "resignation_letter_date",
|
|
||||||
"fieldtype": "Date",
|
|
||||||
"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": "Resignation Letter Date",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 1,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "boarding_status",
|
|
||||||
"fieldtype": "Select",
|
|
||||||
"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": "Status",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "\nPending\nIn Process\nCompleted",
|
|
||||||
"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,
|
"fetch_from": "employee.employee_name",
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "employee_name",
|
||||||
"allow_bulk_edit": 0,
|
"fieldtype": "Data",
|
||||||
"allow_in_quick_entry": 0,
|
"in_list_view": 1,
|
||||||
"allow_in_quick_entry": 0,
|
"label": "Employee Name",
|
||||||
"allow_in_quick_entry": 0,
|
"read_only": 1
|
||||||
"allow_on_submit": 1,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "notify_users_by_email",
|
|
||||||
"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": "Notify users by email",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_7",
|
|
||||||
"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,
|
|
||||||
"fieldname": "employee_separation_template",
|
|
||||||
"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": "Employee Separation Template",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Employee Separation Template",
|
|
||||||
"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_from": "employee.company",
|
|
||||||
"fieldname": "company",
|
|
||||||
"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": "Company",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Company",
|
|
||||||
"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,
|
"fetch_from": "employee.resignation_letter_date",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "resignation_letter_date",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Date",
|
||||||
"bold": 0,
|
"in_list_view": 1,
|
||||||
"collapsible": 0,
|
"label": "Resignation Letter Date",
|
||||||
"columns": 0,
|
"read_only": 1
|
||||||
"fieldname": "project",
|
},
|
||||||
"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": "Project",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Project",
|
|
||||||
"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_on_submit": 1,
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "boarding_status",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Select",
|
||||||
"bold": 0,
|
"label": "Status",
|
||||||
"collapsible": 0,
|
"options": "\nPending\nIn Process\nCompleted",
|
||||||
"columns": 0,
|
"reqd": 1
|
||||||
"fetch_from": "employee.department",
|
},
|
||||||
"fieldname": "department",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Department",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Department",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_on_submit": 1,
|
||||||
"allow_in_quick_entry": 0,
|
"default": "0",
|
||||||
"allow_on_submit": 0,
|
"fieldname": "notify_users_by_email",
|
||||||
"bold": 0,
|
"fieldtype": "Check",
|
||||||
"collapsible": 0,
|
"label": "Notify users by email"
|
||||||
"columns": 0,
|
},
|
||||||
"fetch_from": "employee.designation",
|
|
||||||
"fieldname": "designation",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Designation",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Designation",
|
|
||||||
"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,
|
"fieldname": "column_break_7",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Column Break"
|
||||||
"allow_on_submit": 0,
|
},
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "employee.grade",
|
|
||||||
"fieldname": "employee_grade",
|
|
||||||
"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": "Employee Grade",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Employee Grade",
|
|
||||||
"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,
|
"fieldname": "employee_separation_template",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Link",
|
||||||
"allow_on_submit": 0,
|
"label": "Employee Separation Template",
|
||||||
"bold": 0,
|
"options": "Employee Separation Template"
|
||||||
"collapsible": 0,
|
},
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "table_for_activity",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "",
|
|
||||||
"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,
|
"fetch_from": "employee.company",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "company",
|
||||||
"allow_on_submit": 1,
|
"fieldtype": "Link",
|
||||||
"bold": 0,
|
"label": "Company",
|
||||||
"collapsible": 0,
|
"options": "Company",
|
||||||
"columns": 0,
|
"reqd": 1
|
||||||
"fieldname": "activities",
|
},
|
||||||
"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": "Activities",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Employee Boarding Activity",
|
|
||||||
"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,
|
"fieldname": "project",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Link",
|
||||||
"allow_on_submit": 0,
|
"label": "Project",
|
||||||
"bold": 0,
|
"options": "Project",
|
||||||
"collapsible": 0,
|
"read_only": 1
|
||||||
"columns": 0,
|
},
|
||||||
"fieldname": "section_break_14",
|
|
||||||
"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,
|
"fetch_from": "employee.department",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "department",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Link",
|
||||||
"bold": 0,
|
"in_list_view": 1,
|
||||||
"collapsible": 0,
|
"label": "Department",
|
||||||
"columns": 0,
|
"options": "Department",
|
||||||
"fieldname": "exit_interview",
|
"read_only": 1
|
||||||
"fieldtype": "Text Editor",
|
},
|
||||||
"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": "Exit Interview Summary",
|
|
||||||
"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,
|
"fetch_from": "employee.designation",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "designation",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Link",
|
||||||
"bold": 0,
|
"in_list_view": 1,
|
||||||
"collapsible": 0,
|
"label": "Designation",
|
||||||
"columns": 0,
|
"options": "Designation",
|
||||||
"fieldname": "amended_from",
|
"read_only": 1
|
||||||
"fieldtype": "Link",
|
},
|
||||||
"hidden": 0,
|
{
|
||||||
"ignore_user_permissions": 0,
|
"fetch_from": "employee.grade",
|
||||||
"ignore_xss_filter": 0,
|
"fieldname": "employee_grade",
|
||||||
"in_filter": 0,
|
"fieldtype": "Link",
|
||||||
"in_global_search": 0,
|
"label": "Employee Grade",
|
||||||
"in_list_view": 0,
|
"options": "Employee Grade",
|
||||||
"in_standard_filter": 0,
|
"read_only": 1
|
||||||
"label": "Amended From",
|
},
|
||||||
"length": 0,
|
{
|
||||||
"no_copy": 1,
|
"fieldname": "table_for_activity",
|
||||||
"options": "Employee Separation",
|
"fieldtype": "Section Break",
|
||||||
"permlevel": 0,
|
"label": "Separation Activities"
|
||||||
"print_hide": 1,
|
},
|
||||||
"print_hide_if_no_value": 0,
|
{
|
||||||
"read_only": 1,
|
"allow_on_submit": 1,
|
||||||
"remember_last_selected_value": 0,
|
"fieldname": "activities",
|
||||||
"report_hide": 0,
|
"fieldtype": "Table",
|
||||||
"reqd": 0,
|
"label": "Activities",
|
||||||
"search_index": 0,
|
"options": "Employee Boarding Activity"
|
||||||
"set_only_once": 0,
|
},
|
||||||
"translatable": 0,
|
{
|
||||||
"unique": 0
|
"fieldname": "section_break_14",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "exit_interview",
|
||||||
|
"fieldtype": "Text Editor",
|
||||||
|
"label": "Exit Interview Summary"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "amended_from",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Amended From",
|
||||||
|
"no_copy": 1,
|
||||||
|
"options": "Employee Separation",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"is_submittable": 1,
|
||||||
"hide_heading": 0,
|
"links": [],
|
||||||
"hide_toolbar": 0,
|
"modified": "2021-04-28 15:58:36.020196",
|
||||||
"idx": 0,
|
"modified_by": "Administrator",
|
||||||
"image_view": 0,
|
"module": "HR",
|
||||||
"in_create": 0,
|
"name": "Employee Separation",
|
||||||
"is_submittable": 1,
|
"owner": "Administrator",
|
||||||
"issingle": 0,
|
|
||||||
"istable": 0,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2019-08-03 16:15:39.025898",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "HR",
|
|
||||||
"name": "Employee Separation",
|
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 1,
|
"amend": 1,
|
||||||
"cancel": 1,
|
"cancel": 1,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
"print": 1,
|
||||||
"import": 0,
|
"read": 1,
|
||||||
"permlevel": 0,
|
"report": 1,
|
||||||
"print": 1,
|
"role": "System Manager",
|
||||||
"read": 1,
|
"share": 1,
|
||||||
"report": 1,
|
"submit": 1,
|
||||||
"role": "System Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 1,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"read_only": 0,
|
"sort_field": "modified",
|
||||||
"read_only_onload": 0,
|
"sort_order": "DESC",
|
||||||
"show_name_in_global_search": 0,
|
"title_field": "employee_name",
|
||||||
"sort_field": "modified",
|
"track_changes": 1
|
||||||
"sort_order": "DESC",
|
|
||||||
"title_field": "employee_name",
|
|
||||||
"track_changes": 1,
|
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
@ -18,7 +18,7 @@ class TestEmployeeSeparation(unittest.TestCase):
|
|||||||
'activity_name': 'Deactivate Employee',
|
'activity_name': 'Deactivate Employee',
|
||||||
'role': 'HR User'
|
'role': 'HR User'
|
||||||
})
|
})
|
||||||
separation.status = 'Pending'
|
separation.boarding_status = 'Pending'
|
||||||
separation.insert()
|
separation.insert()
|
||||||
separation.submit()
|
separation.submit()
|
||||||
self.assertEqual(separation.docstatus, 1)
|
self.assertEqual(separation.docstatus, 1)
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
"column_break_5",
|
"column_break_5",
|
||||||
"expense_approver",
|
"expense_approver",
|
||||||
"approval_status",
|
"approval_status",
|
||||||
|
"delivery_trip",
|
||||||
"is_paid",
|
"is_paid",
|
||||||
"expense_details",
|
"expense_details",
|
||||||
"expenses",
|
"expenses",
|
||||||
@ -365,13 +366,20 @@
|
|||||||
"label": "Total Taxes and Charges",
|
"label": "Total Taxes and Charges",
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval: doc.delivery_trip",
|
||||||
|
"fieldname": "delivery_trip",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Delivery Trip",
|
||||||
|
"options": "Delivery Trip"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-money",
|
"icon": "fa fa-money",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-09-18 17:26:09.703215",
|
"modified": "2021-05-04 05:35:12.040199",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Expense Claim",
|
"name": "Expense Claim",
|
||||||
|
@ -88,9 +88,9 @@ class TestExpenseClaim(unittest.TestCase):
|
|||||||
])
|
])
|
||||||
|
|
||||||
for gle in gl_entries:
|
for gle in gl_entries:
|
||||||
self.assertEquals(expected_values[gle.account][0], gle.account)
|
self.assertEqual(expected_values[gle.account][0], gle.account)
|
||||||
self.assertEquals(expected_values[gle.account][1], gle.debit)
|
self.assertEqual(expected_values[gle.account][1], gle.debit)
|
||||||
self.assertEquals(expected_values[gle.account][2], gle.credit)
|
self.assertEqual(expected_values[gle.account][2], gle.credit)
|
||||||
|
|
||||||
def test_rejected_expense_claim(self):
|
def test_rejected_expense_claim(self):
|
||||||
payable_account = get_payable_account(company_name)
|
payable_account = get_payable_account(company_name)
|
||||||
@ -104,11 +104,11 @@ class TestExpenseClaim(unittest.TestCase):
|
|||||||
})
|
})
|
||||||
expense_claim.submit()
|
expense_claim.submit()
|
||||||
|
|
||||||
self.assertEquals(expense_claim.status, 'Rejected')
|
self.assertEqual(expense_claim.status, 'Rejected')
|
||||||
self.assertEquals(expense_claim.total_sanctioned_amount, 0.0)
|
self.assertEqual(expense_claim.total_sanctioned_amount, 0.0)
|
||||||
|
|
||||||
gl_entry = frappe.get_all('GL Entry', {'voucher_type': 'Expense Claim', 'voucher_no': expense_claim.name})
|
gl_entry = frappe.get_all('GL Entry', {'voucher_type': 'Expense Claim', 'voucher_no': expense_claim.name})
|
||||||
self.assertEquals(len(gl_entry), 0)
|
self.assertEqual(len(gl_entry), 0)
|
||||||
|
|
||||||
def test_expense_approver_perms(self):
|
def test_expense_approver_perms(self):
|
||||||
user = "test_approver_perm_emp@example.com"
|
user = "test_approver_perm_emp@example.com"
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
"job_title",
|
"job_title",
|
||||||
"source",
|
"source",
|
||||||
"source_name",
|
"source_name",
|
||||||
|
"employee_referral",
|
||||||
"applicant_rating",
|
"applicant_rating",
|
||||||
"section_break_6",
|
"section_break_6",
|
||||||
"notes",
|
"notes",
|
||||||
@ -152,13 +153,20 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Currency",
|
"label": "Currency",
|
||||||
"options": "Currency"
|
"options": "Currency"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "employee_referral",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Employee Referral",
|
||||||
|
"options": "Employee Referral",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-user",
|
"icon": "fa fa-user",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-09-18 12:39:02.557563",
|
"modified": "2021-03-24 15:51:11.117517",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Job Applicant",
|
"name": "Job Applicant",
|
||||||
|
@ -28,10 +28,21 @@ class JobApplicant(Document):
|
|||||||
if self.email_id:
|
if self.email_id:
|
||||||
validate_email_address(self.email_id, True)
|
validate_email_address(self.email_id, True)
|
||||||
|
|
||||||
|
if self.employee_referral:
|
||||||
|
self.set_status_for_employee_referral()
|
||||||
|
|
||||||
if not self.applicant_name and self.email_id:
|
if not self.applicant_name and self.email_id:
|
||||||
guess = self.email_id.split('@')[0]
|
guess = self.email_id.split('@')[0]
|
||||||
self.applicant_name = ' '.join([p.capitalize() for p in guess.split('.')])
|
self.applicant_name = ' '.join([p.capitalize() for p in guess.split('.')])
|
||||||
|
|
||||||
|
def set_status_for_employee_referral(self):
|
||||||
|
emp_ref = frappe.get_doc("Employee Referral", self.employee_referral)
|
||||||
|
if self.status in ["Open", "Replied", "Hold"]:
|
||||||
|
emp_ref.db_set("status", "In Process")
|
||||||
|
elif self.status in ["Accepted", "Rejected"]:
|
||||||
|
emp_ref.db_set("status", self.status)
|
||||||
|
|
||||||
|
|
||||||
def check_email_id_is_unique(self):
|
def check_email_id_is_unique(self):
|
||||||
if self.email_id:
|
if self.email_id:
|
||||||
names = frappe.db.sql_list("""select name from `tabJob Applicant`
|
names = frappe.db.sql_list("""select name from `tabJob Applicant`
|
||||||
|
@ -35,13 +35,13 @@ class TestJobOffer(unittest.TestCase):
|
|||||||
job_offer = create_job_offer(job_applicant=job_applicant.name)
|
job_offer = create_job_offer(job_applicant=job_applicant.name)
|
||||||
job_offer.submit()
|
job_offer.submit()
|
||||||
job_applicant.reload()
|
job_applicant.reload()
|
||||||
self.assertEquals(job_applicant.status, "Accepted")
|
self.assertEqual(job_applicant.status, "Accepted")
|
||||||
|
|
||||||
# status update after rejection
|
# status update after rejection
|
||||||
job_offer.status = "Rejected"
|
job_offer.status = "Rejected"
|
||||||
job_offer.submit()
|
job_offer.submit()
|
||||||
job_applicant.reload()
|
job_applicant.reload()
|
||||||
self.assertEquals(job_applicant.status, "Rejected")
|
self.assertEqual(job_applicant.status, "Rejected")
|
||||||
|
|
||||||
def create_job_offer(**args):
|
def create_job_offer(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
@ -96,7 +96,7 @@ class TestLeaveAllocation(unittest.TestCase):
|
|||||||
carry_forward=1)
|
carry_forward=1)
|
||||||
leave_allocation_1.submit()
|
leave_allocation_1.submit()
|
||||||
|
|
||||||
self.assertEquals(leave_allocation_1.unused_leaves, 10)
|
self.assertEqual(leave_allocation_1.unused_leaves, 10)
|
||||||
|
|
||||||
leave_allocation_1.cancel()
|
leave_allocation_1.cancel()
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ class TestLeaveAllocation(unittest.TestCase):
|
|||||||
new_leaves_allocated=25)
|
new_leaves_allocated=25)
|
||||||
leave_allocation_2.submit()
|
leave_allocation_2.submit()
|
||||||
|
|
||||||
self.assertEquals(leave_allocation_2.unused_leaves, 5)
|
self.assertEqual(leave_allocation_2.unused_leaves, 5)
|
||||||
|
|
||||||
def test_carry_forward_leaves_expiry(self):
|
def test_carry_forward_leaves_expiry(self):
|
||||||
frappe.db.sql("delete from `tabLeave Allocation`")
|
frappe.db.sql("delete from `tabLeave Allocation`")
|
||||||
@ -145,7 +145,7 @@ class TestLeaveAllocation(unittest.TestCase):
|
|||||||
to_date=add_months(nowdate(), 12))
|
to_date=add_months(nowdate(), 12))
|
||||||
leave_allocation_1.submit()
|
leave_allocation_1.submit()
|
||||||
|
|
||||||
self.assertEquals(leave_allocation_1.unused_leaves, leave_allocation.new_leaves_allocated)
|
self.assertEqual(leave_allocation_1.unused_leaves, leave_allocation.new_leaves_allocated)
|
||||||
|
|
||||||
def test_creation_of_leave_ledger_entry_on_submit(self):
|
def test_creation_of_leave_ledger_entry_on_submit(self):
|
||||||
frappe.db.sql("delete from `tabLeave Allocation`")
|
frappe.db.sql("delete from `tabLeave Allocation`")
|
||||||
@ -155,10 +155,10 @@ class TestLeaveAllocation(unittest.TestCase):
|
|||||||
|
|
||||||
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_allocation.name))
|
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_allocation.name))
|
||||||
|
|
||||||
self.assertEquals(len(leave_ledger_entry), 1)
|
self.assertEqual(len(leave_ledger_entry), 1)
|
||||||
self.assertEquals(leave_ledger_entry[0].employee, leave_allocation.employee)
|
self.assertEqual(leave_ledger_entry[0].employee, leave_allocation.employee)
|
||||||
self.assertEquals(leave_ledger_entry[0].leave_type, leave_allocation.leave_type)
|
self.assertEqual(leave_ledger_entry[0].leave_type, leave_allocation.leave_type)
|
||||||
self.assertEquals(leave_ledger_entry[0].leaves, leave_allocation.new_leaves_allocated)
|
self.assertEqual(leave_ledger_entry[0].leaves, leave_allocation.new_leaves_allocated)
|
||||||
|
|
||||||
# check if leave ledger entry is deleted on cancellation
|
# check if leave ledger entry is deleted on cancellation
|
||||||
leave_allocation.cancel()
|
leave_allocation.cancel()
|
||||||
|
@ -16,36 +16,36 @@ from erpnext.hr.doctype.employee.test_employee import make_employee
|
|||||||
test_dependencies = ["Leave Allocation", "Leave Block List", "Employee"]
|
test_dependencies = ["Leave Allocation", "Leave Block List", "Employee"]
|
||||||
|
|
||||||
_test_records = [
|
_test_records = [
|
||||||
{
|
{
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
"doctype": "Leave Application",
|
"doctype": "Leave Application",
|
||||||
"employee": "_T-Employee-00001",
|
"employee": "_T-Employee-00001",
|
||||||
"from_date": "2013-05-01",
|
"from_date": "2013-05-01",
|
||||||
"description": "_Test Reason",
|
"description": "_Test Reason",
|
||||||
"leave_type": "_Test Leave Type",
|
"leave_type": "_Test Leave Type",
|
||||||
"posting_date": "2013-01-02",
|
"posting_date": "2013-01-02",
|
||||||
"to_date": "2013-05-05"
|
"to_date": "2013-05-05"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
"doctype": "Leave Application",
|
"doctype": "Leave Application",
|
||||||
"employee": "_T-Employee-00002",
|
"employee": "_T-Employee-00002",
|
||||||
"from_date": "2013-05-01",
|
"from_date": "2013-05-01",
|
||||||
"description": "_Test Reason",
|
"description": "_Test Reason",
|
||||||
"leave_type": "_Test Leave Type",
|
"leave_type": "_Test Leave Type",
|
||||||
"posting_date": "2013-01-02",
|
"posting_date": "2013-01-02",
|
||||||
"to_date": "2013-05-05"
|
"to_date": "2013-05-05"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
"doctype": "Leave Application",
|
"doctype": "Leave Application",
|
||||||
"employee": "_T-Employee-00001",
|
"employee": "_T-Employee-00001",
|
||||||
"from_date": "2013-01-15",
|
"from_date": "2013-01-15",
|
||||||
"description": "_Test Reason",
|
"description": "_Test Reason",
|
||||||
"leave_type": "_Test Leave Type LWP",
|
"leave_type": "_Test Leave Type LWP",
|
||||||
"posting_date": "2013-01-02",
|
"posting_date": "2013-01-02",
|
||||||
"to_date": "2013-01-15"
|
"to_date": "2013-01-15"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -516,9 +516,9 @@ class TestLeaveApplication(unittest.TestCase):
|
|||||||
leave_application.submit()
|
leave_application.submit()
|
||||||
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_application.name))
|
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_application.name))
|
||||||
|
|
||||||
self.assertEquals(leave_ledger_entry[0].employee, leave_application.employee)
|
self.assertEqual(leave_ledger_entry[0].employee, leave_application.employee)
|
||||||
self.assertEquals(leave_ledger_entry[0].leave_type, leave_application.leave_type)
|
self.assertEqual(leave_ledger_entry[0].leave_type, leave_application.leave_type)
|
||||||
self.assertEquals(leave_ledger_entry[0].leaves, leave_application.total_leave_days * -1)
|
self.assertEqual(leave_ledger_entry[0].leaves, leave_application.total_leave_days * -1)
|
||||||
|
|
||||||
# check if leave ledger entry is deleted on cancellation
|
# check if leave ledger entry is deleted on cancellation
|
||||||
leave_application.cancel()
|
leave_application.cancel()
|
||||||
@ -549,11 +549,11 @@ class TestLeaveApplication(unittest.TestCase):
|
|||||||
|
|
||||||
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', '*', filters=dict(transaction_name=leave_application.name))
|
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', '*', filters=dict(transaction_name=leave_application.name))
|
||||||
|
|
||||||
self.assertEquals(len(leave_ledger_entry), 2)
|
self.assertEqual(len(leave_ledger_entry), 2)
|
||||||
self.assertEquals(leave_ledger_entry[0].employee, leave_application.employee)
|
self.assertEqual(leave_ledger_entry[0].employee, leave_application.employee)
|
||||||
self.assertEquals(leave_ledger_entry[0].leave_type, leave_application.leave_type)
|
self.assertEqual(leave_ledger_entry[0].leave_type, leave_application.leave_type)
|
||||||
self.assertEquals(leave_ledger_entry[0].leaves, -9)
|
self.assertEqual(leave_ledger_entry[0].leaves, -9)
|
||||||
self.assertEquals(leave_ledger_entry[1].leaves, -2)
|
self.assertEqual(leave_ledger_entry[1].leaves, -2)
|
||||||
|
|
||||||
def test_leave_application_creation_after_expiry(self):
|
def test_leave_application_creation_after_expiry(self):
|
||||||
# test leave balance for carry forwarded allocation
|
# test leave balance for carry forwarded allocation
|
||||||
@ -566,7 +566,7 @@ class TestLeaveApplication(unittest.TestCase):
|
|||||||
|
|
||||||
create_carry_forwarded_allocation(employee, leave_type)
|
create_carry_forwarded_allocation(employee, leave_type)
|
||||||
|
|
||||||
self.assertEquals(get_leave_balance_on(employee.name, leave_type.name, add_days(nowdate(), -85), add_days(nowdate(), -84)), 0)
|
self.assertEqual(get_leave_balance_on(employee.name, leave_type.name, add_days(nowdate(), -85), add_days(nowdate(), -84)), 0)
|
||||||
|
|
||||||
def test_leave_approver_perms(self):
|
def test_leave_approver_perms(self):
|
||||||
employee = get_employee()
|
employee = get_employee()
|
||||||
|
@ -88,10 +88,10 @@ class TestLeaveEncashment(unittest.TestCase):
|
|||||||
|
|
||||||
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_encashment.name))
|
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_encashment.name))
|
||||||
|
|
||||||
self.assertEquals(len(leave_ledger_entry), 1)
|
self.assertEqual(len(leave_ledger_entry), 1)
|
||||||
self.assertEquals(leave_ledger_entry[0].employee, leave_encashment.employee)
|
self.assertEqual(leave_ledger_entry[0].employee, leave_encashment.employee)
|
||||||
self.assertEquals(leave_ledger_entry[0].leave_type, leave_encashment.leave_type)
|
self.assertEqual(leave_ledger_entry[0].leave_type, leave_encashment.leave_type)
|
||||||
self.assertEquals(leave_ledger_entry[0].leaves, leave_encashment.encashable_days * -1)
|
self.assertEqual(leave_ledger_entry[0].leaves, leave_encashment.encashable_days * -1)
|
||||||
|
|
||||||
# check if leave ledger entry is deleted on cancellation
|
# check if leave ledger entry is deleted on cancellation
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"attach_print": 0,
|
"attach_print": 0,
|
||||||
|
"channel": "Email",
|
||||||
"creation": "2017-08-11 03:17:11.769210",
|
"creation": "2017-08-11 03:17:11.769210",
|
||||||
"days_in_advance": 0,
|
"days_in_advance": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
|
@ -32,13 +32,15 @@ class EmployeeBoardingController(Document):
|
|||||||
project_name += self.job_applicant
|
project_name += self.job_applicant
|
||||||
else:
|
else:
|
||||||
project_name += self.employee
|
project_name += self.employee
|
||||||
|
|
||||||
project = frappe.get_doc({
|
project = frappe.get_doc({
|
||||||
"doctype": "Project",
|
"doctype": "Project",
|
||||||
"project_name": project_name,
|
"project_name": project_name,
|
||||||
"expected_start_date": self.date_of_joining if self.doctype == "Employee Onboarding" else self.resignation_letter_date,
|
"expected_start_date": self.date_of_joining if self.doctype == "Employee Onboarding" else self.resignation_letter_date,
|
||||||
"department": self.department,
|
"department": self.department,
|
||||||
"company": self.company
|
"company": self.company
|
||||||
}).insert(ignore_permissions=True)
|
}).insert(ignore_permissions=True, ignore_mandatory=True)
|
||||||
|
|
||||||
self.db_set("project", project.name)
|
self.db_set("project", project.name)
|
||||||
self.db_set("boarding_status", "Pending")
|
self.db_set("boarding_status", "Pending")
|
||||||
self.reload()
|
self.reload()
|
||||||
|
@ -520,6 +520,15 @@
|
|||||||
"onboard": 1,
|
"onboard": 1,
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"hidden": 0,
|
||||||
|
"is_query_report": 0,
|
||||||
|
"label": "Employee Referral",
|
||||||
|
"link_to": "Employee Referral",
|
||||||
|
"link_type": "DocType",
|
||||||
|
"onboard": 0,
|
||||||
|
"type": "Link"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"dependencies": "",
|
"dependencies": "",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -814,7 +823,7 @@
|
|||||||
"type": "Link"
|
"type": "Link"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2021-03-24 17:35:21.483297",
|
"modified": "2021-04-26 13:36:15.413819",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "HR",
|
"name": "HR",
|
||||||
|
@ -71,7 +71,6 @@ class Loan(AccountsController):
|
|||||||
frappe.throw(_("Repay From Salary can be selected only for term loans"))
|
frappe.throw(_("Repay From Salary can be selected only for term loans"))
|
||||||
|
|
||||||
def make_repayment_schedule(self):
|
def make_repayment_schedule(self):
|
||||||
|
|
||||||
if not self.repayment_start_date:
|
if not self.repayment_start_date:
|
||||||
frappe.throw(_("Repayment Start Date is mandatory for term loans"))
|
frappe.throw(_("Repayment Start Date is mandatory for term loans"))
|
||||||
|
|
||||||
@ -79,10 +78,9 @@ class Loan(AccountsController):
|
|||||||
payment_date = self.repayment_start_date
|
payment_date = self.repayment_start_date
|
||||||
balance_amount = self.loan_amount
|
balance_amount = self.loan_amount
|
||||||
while(balance_amount > 0):
|
while(balance_amount > 0):
|
||||||
interest_amount = rounded(balance_amount * flt(self.rate_of_interest) / (12*100))
|
interest_amount = flt(balance_amount * flt(self.rate_of_interest) / (12*100))
|
||||||
principal_amount = self.monthly_repayment_amount - interest_amount
|
principal_amount = self.monthly_repayment_amount - interest_amount
|
||||||
balance_amount = rounded(balance_amount + interest_amount - self.monthly_repayment_amount)
|
balance_amount = flt(balance_amount + interest_amount - self.monthly_repayment_amount)
|
||||||
|
|
||||||
if balance_amount < 0:
|
if balance_amount < 0:
|
||||||
principal_amount += balance_amount
|
principal_amount += balance_amount
|
||||||
balance_amount = 0.0
|
balance_amount = 0.0
|
||||||
@ -196,7 +194,8 @@ def request_loan_closure(loan, posting_date=None):
|
|||||||
posting_date = getdate()
|
posting_date = getdate()
|
||||||
|
|
||||||
amounts = calculate_amounts(loan, posting_date)
|
amounts = calculate_amounts(loan, posting_date)
|
||||||
pending_amount = amounts['payable_amount'] + amounts['unaccrued_interest']
|
pending_amount = amounts['pending_principal_amount'] + amounts['unaccrued_interest'] + \
|
||||||
|
amounts['interest_amount'] + amounts['penalty_amount']
|
||||||
|
|
||||||
loan_type = frappe.get_value('Loan', loan, 'loan_type')
|
loan_type = frappe.get_value('Loan', loan, 'loan_type')
|
||||||
write_off_limit = frappe.get_value('Loan Type', loan_type, 'write_off_amount')
|
write_off_limit = frappe.get_value('Loan Type', loan_type, 'write_off_amount')
|
||||||
|
@ -55,26 +55,26 @@ class TestLoan(unittest.TestCase):
|
|||||||
|
|
||||||
def test_loan(self):
|
def test_loan(self):
|
||||||
loan = frappe.get_doc("Loan", {"applicant":self.applicant1})
|
loan = frappe.get_doc("Loan", {"applicant":self.applicant1})
|
||||||
self.assertEquals(loan.monthly_repayment_amount, 15052)
|
self.assertEqual(loan.monthly_repayment_amount, 15052)
|
||||||
self.assertEquals(loan.total_interest_payable, 21034)
|
self.assertEqual(flt(loan.total_interest_payable, 0), 21034)
|
||||||
self.assertEquals(loan.total_payment, 301034)
|
self.assertEqual(flt(loan.total_payment, 0), 301034)
|
||||||
|
|
||||||
schedule = loan.repayment_schedule
|
schedule = loan.repayment_schedule
|
||||||
|
|
||||||
self.assertEqual(len(schedule), 20)
|
self.assertEqual(len(schedule), 20)
|
||||||
|
|
||||||
for idx, principal_amount, interest_amount, balance_loan_amount in [[3, 13369, 1683, 227079], [19, 14941, 105, 0], [17, 14740, 312, 29785]]:
|
for idx, principal_amount, interest_amount, balance_loan_amount in [[3, 13369, 1683, 227080], [19, 14941, 105, 0], [17, 14740, 312, 29785]]:
|
||||||
self.assertEqual(schedule[idx].principal_amount, principal_amount)
|
self.assertEqual(flt(schedule[idx].principal_amount, 0), principal_amount)
|
||||||
self.assertEqual(schedule[idx].interest_amount, interest_amount)
|
self.assertEqual(flt(schedule[idx].interest_amount, 0), interest_amount)
|
||||||
self.assertEqual(schedule[idx].balance_loan_amount, balance_loan_amount)
|
self.assertEqual(flt(schedule[idx].balance_loan_amount, 0), balance_loan_amount)
|
||||||
|
|
||||||
loan.repayment_method = "Repay Fixed Amount per Period"
|
loan.repayment_method = "Repay Fixed Amount per Period"
|
||||||
loan.monthly_repayment_amount = 14000
|
loan.monthly_repayment_amount = 14000
|
||||||
loan.save()
|
loan.save()
|
||||||
|
|
||||||
self.assertEquals(len(loan.repayment_schedule), 22)
|
self.assertEqual(len(loan.repayment_schedule), 22)
|
||||||
self.assertEquals(loan.total_interest_payable, 22712)
|
self.assertEqual(flt(loan.total_interest_payable, 0), 22712)
|
||||||
self.assertEquals(loan.total_payment, 302712)
|
self.assertEqual(flt(loan.total_payment, 0), 302712)
|
||||||
|
|
||||||
def test_loan_with_security(self):
|
def test_loan_with_security(self):
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
|
|
||||||
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods",
|
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods",
|
||||||
12, loan_application)
|
12, loan_application)
|
||||||
self.assertEquals(loan.loan_amount, 1000000)
|
self.assertEqual(loan.loan_amount, 1000000)
|
||||||
|
|
||||||
def test_loan_disbursement(self):
|
def test_loan_disbursement(self):
|
||||||
pledge = [{
|
pledge = [{
|
||||||
@ -102,7 +102,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
create_pledge(loan_application)
|
create_pledge(loan_application)
|
||||||
|
|
||||||
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_application)
|
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_application)
|
||||||
self.assertEquals(loan.loan_amount, 1000000)
|
self.assertEqual(loan.loan_amount, 1000000)
|
||||||
|
|
||||||
loan.submit()
|
loan.submit()
|
||||||
|
|
||||||
@ -120,8 +120,8 @@ class TestLoan(unittest.TestCase):
|
|||||||
filters = {'voucher_type': 'Loan Disbursement', 'voucher_no': loan_disbursement_entry2.name}
|
filters = {'voucher_type': 'Loan Disbursement', 'voucher_no': loan_disbursement_entry2.name}
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEquals(loan.status, "Disbursed")
|
self.assertEqual(loan.status, "Disbursed")
|
||||||
self.assertEquals(loan.disbursed_amount, 1000000)
|
self.assertEqual(loan.disbursed_amount, 1000000)
|
||||||
self.assertTrue(gl_entries1)
|
self.assertTrue(gl_entries1)
|
||||||
self.assertTrue(gl_entries2)
|
self.assertTrue(gl_entries2)
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
||||||
loan.submit()
|
loan.submit()
|
||||||
|
|
||||||
self.assertEquals(loan.loan_amount, 1000000)
|
self.assertEqual(loan.loan_amount, 1000000)
|
||||||
|
|
||||||
first_date = '2019-10-01'
|
first_date = '2019-10-01'
|
||||||
last_date = '2019-10-30'
|
last_date = '2019-10-30'
|
||||||
@ -156,15 +156,15 @@ class TestLoan(unittest.TestCase):
|
|||||||
repayment_entry.submit()
|
repayment_entry.submit()
|
||||||
|
|
||||||
penalty_amount = (accrued_interest_amount * 5 * 25) / 100
|
penalty_amount = (accrued_interest_amount * 5 * 25) / 100
|
||||||
self.assertEquals(flt(repayment_entry.penalty_amount,0), flt(penalty_amount, 0))
|
self.assertEqual(flt(repayment_entry.penalty_amount,0), flt(penalty_amount, 0))
|
||||||
|
|
||||||
amounts = frappe.db.get_all('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount'])
|
amounts = frappe.db.get_all('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount'])
|
||||||
|
|
||||||
loan.load_from_db()
|
loan.load_from_db()
|
||||||
|
|
||||||
total_interest_paid = amounts[0]['paid_interest_amount'] + amounts[1]['paid_interest_amount']
|
total_interest_paid = amounts[0]['paid_interest_amount'] + amounts[1]['paid_interest_amount']
|
||||||
self.assertEquals(amounts[1]['paid_interest_amount'], repayment_entry.interest_payable)
|
self.assertEqual(amounts[1]['paid_interest_amount'], repayment_entry.interest_payable)
|
||||||
self.assertEquals(flt(loan.total_principal_paid, 0), flt(repayment_entry.amount_paid -
|
self.assertEqual(flt(loan.total_principal_paid, 0), flt(repayment_entry.amount_paid -
|
||||||
penalty_amount - total_interest_paid, 0))
|
penalty_amount - total_interest_paid, 0))
|
||||||
|
|
||||||
def test_loan_closure(self):
|
def test_loan_closure(self):
|
||||||
@ -179,7 +179,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
||||||
loan.submit()
|
loan.submit()
|
||||||
|
|
||||||
self.assertEquals(loan.loan_amount, 1000000)
|
self.assertEqual(loan.loan_amount, 1000000)
|
||||||
|
|
||||||
first_date = '2019-10-01'
|
first_date = '2019-10-01'
|
||||||
last_date = '2019-10-30'
|
last_date = '2019-10-30'
|
||||||
@ -204,12 +204,12 @@ class TestLoan(unittest.TestCase):
|
|||||||
|
|
||||||
amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
|
amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
|
||||||
|
|
||||||
self.assertEquals(flt(amount, 0),flt(accrued_interest_amount, 0))
|
self.assertEqual(flt(amount, 0),flt(accrued_interest_amount, 0))
|
||||||
self.assertEquals(flt(repayment_entry.penalty_amount, 5), 0)
|
self.assertEqual(flt(repayment_entry.penalty_amount, 5), 0)
|
||||||
|
|
||||||
request_loan_closure(loan.name)
|
request_loan_closure(loan.name)
|
||||||
loan.load_from_db()
|
loan.load_from_db()
|
||||||
self.assertEquals(loan.status, "Loan Closure Requested")
|
self.assertEqual(loan.status, "Loan Closure Requested")
|
||||||
|
|
||||||
def test_loan_repayment_for_term_loan(self):
|
def test_loan_repayment_for_term_loan(self):
|
||||||
pledges = [{
|
pledges = [{
|
||||||
@ -241,8 +241,8 @@ class TestLoan(unittest.TestCase):
|
|||||||
amounts = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount',
|
amounts = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount',
|
||||||
'paid_principal_amount'])
|
'paid_principal_amount'])
|
||||||
|
|
||||||
self.assertEquals(amounts[0], 11250.00)
|
self.assertEqual(amounts[0], 11250.00)
|
||||||
self.assertEquals(amounts[1], 78303.00)
|
self.assertEqual(amounts[1], 78303.00)
|
||||||
|
|
||||||
def test_security_shortfall(self):
|
def test_security_shortfall(self):
|
||||||
pledges = [{
|
pledges = [{
|
||||||
@ -268,17 +268,17 @@ class TestLoan(unittest.TestCase):
|
|||||||
loan_security_shortfall = frappe.get_doc("Loan Security Shortfall", {"loan": loan.name})
|
loan_security_shortfall = frappe.get_doc("Loan Security Shortfall", {"loan": loan.name})
|
||||||
self.assertTrue(loan_security_shortfall)
|
self.assertTrue(loan_security_shortfall)
|
||||||
|
|
||||||
self.assertEquals(loan_security_shortfall.loan_amount, 1000000.00)
|
self.assertEqual(loan_security_shortfall.loan_amount, 1000000.00)
|
||||||
self.assertEquals(loan_security_shortfall.security_value, 800000.00)
|
self.assertEqual(loan_security_shortfall.security_value, 800000.00)
|
||||||
self.assertEquals(loan_security_shortfall.shortfall_amount, 600000.00)
|
self.assertEqual(loan_security_shortfall.shortfall_amount, 600000.00)
|
||||||
|
|
||||||
frappe.db.sql(""" UPDATE `tabLoan Security Price` SET loan_security_price = 250
|
frappe.db.sql(""" UPDATE `tabLoan Security Price` SET loan_security_price = 250
|
||||||
where loan_security='Test Security 2'""")
|
where loan_security='Test Security 2'""")
|
||||||
|
|
||||||
create_process_loan_security_shortfall()
|
create_process_loan_security_shortfall()
|
||||||
loan_security_shortfall = frappe.get_doc("Loan Security Shortfall", {"loan": loan.name})
|
loan_security_shortfall = frappe.get_doc("Loan Security Shortfall", {"loan": loan.name})
|
||||||
self.assertEquals(loan_security_shortfall.status, "Completed")
|
self.assertEqual(loan_security_shortfall.status, "Completed")
|
||||||
self.assertEquals(loan_security_shortfall.shortfall_amount, 0)
|
self.assertEqual(loan_security_shortfall.shortfall_amount, 0)
|
||||||
|
|
||||||
def test_loan_security_unpledge(self):
|
def test_loan_security_unpledge(self):
|
||||||
pledge = [{
|
pledge = [{
|
||||||
@ -292,7 +292,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
||||||
loan.submit()
|
loan.submit()
|
||||||
|
|
||||||
self.assertEquals(loan.loan_amount, 1000000)
|
self.assertEqual(loan.loan_amount, 1000000)
|
||||||
|
|
||||||
first_date = '2019-10-01'
|
first_date = '2019-10-01'
|
||||||
last_date = '2019-10-30'
|
last_date = '2019-10-30'
|
||||||
@ -312,7 +312,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
|
|
||||||
request_loan_closure(loan.name)
|
request_loan_closure(loan.name)
|
||||||
loan.load_from_db()
|
loan.load_from_db()
|
||||||
self.assertEquals(loan.status, "Loan Closure Requested")
|
self.assertEqual(loan.status, "Loan Closure Requested")
|
||||||
|
|
||||||
unpledge_request = unpledge_security(loan=loan.name, save=1)
|
unpledge_request = unpledge_security(loan=loan.name, save=1)
|
||||||
unpledge_request.submit()
|
unpledge_request.submit()
|
||||||
@ -323,11 +323,11 @@ class TestLoan(unittest.TestCase):
|
|||||||
pledged_qty = get_pledged_security_qty(loan.name)
|
pledged_qty = get_pledged_security_qty(loan.name)
|
||||||
|
|
||||||
self.assertEqual(loan.status, 'Closed')
|
self.assertEqual(loan.status, 'Closed')
|
||||||
self.assertEquals(sum(pledged_qty.values()), 0)
|
self.assertEqual(sum(pledged_qty.values()), 0)
|
||||||
|
|
||||||
amounts = amounts = calculate_amounts(loan.name, add_days(last_date, 5))
|
amounts = amounts = calculate_amounts(loan.name, add_days(last_date, 5))
|
||||||
self.assertEqual(amounts['pending_principal_amount'], 0)
|
self.assertEqual(amounts['pending_principal_amount'], 0)
|
||||||
self.assertEquals(amounts['payable_principal_amount'], 0.0)
|
self.assertEqual(amounts['payable_principal_amount'], 0.0)
|
||||||
self.assertEqual(amounts['interest_amount'], 0)
|
self.assertEqual(amounts['interest_amount'], 0)
|
||||||
|
|
||||||
def test_partial_loan_security_unpledge(self):
|
def test_partial_loan_security_unpledge(self):
|
||||||
@ -346,7 +346,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
||||||
loan.submit()
|
loan.submit()
|
||||||
|
|
||||||
self.assertEquals(loan.loan_amount, 1000000)
|
self.assertEqual(loan.loan_amount, 1000000)
|
||||||
|
|
||||||
first_date = '2019-10-01'
|
first_date = '2019-10-01'
|
||||||
last_date = '2019-10-30'
|
last_date = '2019-10-30'
|
||||||
@ -379,7 +379,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
||||||
loan.submit()
|
loan.submit()
|
||||||
|
|
||||||
self.assertEquals(loan.loan_amount, 1000000)
|
self.assertEqual(loan.loan_amount, 1000000)
|
||||||
|
|
||||||
unpledge_map = {'Test Security 1': 4000}
|
unpledge_map = {'Test Security 1': 4000}
|
||||||
unpledge_request = unpledge_security(loan=loan.name, security_map = unpledge_map, save=1)
|
unpledge_request = unpledge_security(loan=loan.name, security_map = unpledge_map, save=1)
|
||||||
@ -450,7 +450,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
||||||
loan.submit()
|
loan.submit()
|
||||||
|
|
||||||
self.assertEquals(loan.loan_amount, 1000000)
|
self.assertEqual(loan.loan_amount, 1000000)
|
||||||
|
|
||||||
first_date = '2019-10-01'
|
first_date = '2019-10-01'
|
||||||
last_date = '2019-10-30'
|
last_date = '2019-10-30'
|
||||||
@ -475,7 +475,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
|
|
||||||
request_loan_closure(loan.name)
|
request_loan_closure(loan.name)
|
||||||
loan.load_from_db()
|
loan.load_from_db()
|
||||||
self.assertEquals(loan.status, "Loan Closure Requested")
|
self.assertEqual(loan.status, "Loan Closure Requested")
|
||||||
|
|
||||||
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
|
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
|
||||||
self.assertEqual(amounts['pending_principal_amount'], 0.0)
|
self.assertEqual(amounts['pending_principal_amount'], 0.0)
|
||||||
@ -492,7 +492,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
||||||
loan.submit()
|
loan.submit()
|
||||||
|
|
||||||
self.assertEquals(loan.loan_amount, 1000000)
|
self.assertEqual(loan.loan_amount, 1000000)
|
||||||
|
|
||||||
first_date = '2019-10-01'
|
first_date = '2019-10-01'
|
||||||
last_date = '2019-10-30'
|
last_date = '2019-10-30'
|
||||||
@ -533,8 +533,8 @@ class TestLoan(unittest.TestCase):
|
|||||||
calculated_penalty_amount = frappe.db.get_value('Loan Interest Accrual',
|
calculated_penalty_amount = frappe.db.get_value('Loan Interest Accrual',
|
||||||
{'process_loan_interest_accrual': process, 'loan': loan.name}, 'penalty_amount')
|
{'process_loan_interest_accrual': process, 'loan': loan.name}, 'penalty_amount')
|
||||||
|
|
||||||
self.assertEquals(loan.loan_amount, 1000000)
|
self.assertEqual(loan.loan_amount, 1000000)
|
||||||
self.assertEquals(calculated_penalty_amount, penalty_amount)
|
self.assertEqual(calculated_penalty_amount, penalty_amount)
|
||||||
|
|
||||||
def test_penalty_repayment(self):
|
def test_penalty_repayment(self):
|
||||||
loan, dummy = create_loan_scenario_for_penalty(self)
|
loan, dummy = create_loan_scenario_for_penalty(self)
|
||||||
@ -547,13 +547,13 @@ class TestLoan(unittest.TestCase):
|
|||||||
repayment_entry.submit()
|
repayment_entry.submit()
|
||||||
|
|
||||||
amounts = calculate_amounts(loan.name, '2019-11-30 00:00:01')
|
amounts = calculate_amounts(loan.name, '2019-11-30 00:00:01')
|
||||||
self.assertEquals(amounts['penalty_amount'], second_penalty)
|
self.assertEqual(amounts['penalty_amount'], second_penalty)
|
||||||
|
|
||||||
repayment_entry = create_repayment_entry(loan.name, self.applicant2, '2019-11-30 00:00:01', second_penalty)
|
repayment_entry = create_repayment_entry(loan.name, self.applicant2, '2019-11-30 00:00:01', second_penalty)
|
||||||
repayment_entry.submit()
|
repayment_entry.submit()
|
||||||
|
|
||||||
amounts = calculate_amounts(loan.name, '2019-11-30 00:00:02')
|
amounts = calculate_amounts(loan.name, '2019-11-30 00:00:02')
|
||||||
self.assertEquals(amounts['penalty_amount'], 0)
|
self.assertEqual(amounts['penalty_amount'], 0)
|
||||||
|
|
||||||
def test_loan_write_off_limit(self):
|
def test_loan_write_off_limit(self):
|
||||||
pledge = [{
|
pledge = [{
|
||||||
@ -567,7 +567,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
||||||
loan.submit()
|
loan.submit()
|
||||||
|
|
||||||
self.assertEquals(loan.loan_amount, 1000000)
|
self.assertEqual(loan.loan_amount, 1000000)
|
||||||
|
|
||||||
first_date = '2019-10-01'
|
first_date = '2019-10-01'
|
||||||
last_date = '2019-10-30'
|
last_date = '2019-10-30'
|
||||||
@ -589,15 +589,15 @@ class TestLoan(unittest.TestCase):
|
|||||||
|
|
||||||
amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
|
amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
|
||||||
|
|
||||||
self.assertEquals(flt(amount, 0),flt(accrued_interest_amount, 0))
|
self.assertEqual(flt(amount, 0),flt(accrued_interest_amount, 0))
|
||||||
self.assertEquals(flt(repayment_entry.penalty_amount, 5), 0)
|
self.assertEqual(flt(repayment_entry.penalty_amount, 5), 0)
|
||||||
|
|
||||||
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
|
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
|
||||||
self.assertEquals(flt(amounts['pending_principal_amount'], 0), 50)
|
self.assertEqual(flt(amounts['pending_principal_amount'], 0), 50)
|
||||||
|
|
||||||
request_loan_closure(loan.name)
|
request_loan_closure(loan.name)
|
||||||
loan.load_from_db()
|
loan.load_from_db()
|
||||||
self.assertEquals(loan.status, "Loan Closure Requested")
|
self.assertEqual(loan.status, "Loan Closure Requested")
|
||||||
|
|
||||||
def test_loan_amount_write_off(self):
|
def test_loan_amount_write_off(self):
|
||||||
pledge = [{
|
pledge = [{
|
||||||
@ -611,7 +611,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
||||||
loan.submit()
|
loan.submit()
|
||||||
|
|
||||||
self.assertEquals(loan.loan_amount, 1000000)
|
self.assertEqual(loan.loan_amount, 1000000)
|
||||||
|
|
||||||
first_date = '2019-10-01'
|
first_date = '2019-10-01'
|
||||||
last_date = '2019-10-30'
|
last_date = '2019-10-30'
|
||||||
@ -633,17 +633,17 @@ class TestLoan(unittest.TestCase):
|
|||||||
|
|
||||||
amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
|
amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
|
||||||
|
|
||||||
self.assertEquals(flt(amount, 0),flt(accrued_interest_amount, 0))
|
self.assertEqual(flt(amount, 0),flt(accrued_interest_amount, 0))
|
||||||
self.assertEquals(flt(repayment_entry.penalty_amount, 5), 0)
|
self.assertEqual(flt(repayment_entry.penalty_amount, 5), 0)
|
||||||
|
|
||||||
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
|
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
|
||||||
self.assertEquals(flt(amounts['pending_principal_amount'], 0), 100)
|
self.assertEqual(flt(amounts['pending_principal_amount'], 0), 100)
|
||||||
|
|
||||||
we = make_loan_write_off(loan.name, amount=amounts['pending_principal_amount'])
|
we = make_loan_write_off(loan.name, amount=amounts['pending_principal_amount'])
|
||||||
we.submit()
|
we.submit()
|
||||||
|
|
||||||
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
|
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
|
||||||
self.assertEquals(flt(amounts['pending_principal_amount'], 0), 0)
|
self.assertEqual(flt(amounts['pending_principal_amount'], 0), 0)
|
||||||
|
|
||||||
def create_loan_scenario_for_penalty(doc):
|
def create_loan_scenario_for_penalty(doc):
|
||||||
pledge = [{
|
pledge = [{
|
||||||
|
@ -87,7 +87,7 @@ class TestLoanDisbursement(unittest.TestCase):
|
|||||||
loan = create_demand_loan(self.applicant, "Demand Loan", loan_application, posting_date='2019-10-01')
|
loan = create_demand_loan(self.applicant, "Demand Loan", loan_application, posting_date='2019-10-01')
|
||||||
loan.submit()
|
loan.submit()
|
||||||
|
|
||||||
self.assertEquals(loan.loan_amount, 1000000)
|
self.assertEqual(loan.loan_amount, 1000000)
|
||||||
|
|
||||||
first_date = '2019-10-01'
|
first_date = '2019-10-01'
|
||||||
last_date = '2019-10-30'
|
last_date = '2019-10-30'
|
||||||
@ -114,5 +114,5 @@ class TestLoanDisbursement(unittest.TestCase):
|
|||||||
per_day_interest = get_per_day_interest(1500000, 13.5, '2019-10-30')
|
per_day_interest = get_per_day_interest(1500000, 13.5, '2019-10-30')
|
||||||
interest = per_day_interest * 15
|
interest = per_day_interest * 15
|
||||||
|
|
||||||
self.assertEquals(amounts['pending_principal_amount'], 1500000)
|
self.assertEqual(amounts['pending_principal_amount'], 1500000)
|
||||||
self.assertEquals(amounts['interest_amount'], flt(interest + previous_interest, 2))
|
self.assertEqual(amounts['interest_amount'], flt(interest + previous_interest, 2))
|
||||||
|
@ -52,7 +52,7 @@ class TestLoanInterestAccrual(unittest.TestCase):
|
|||||||
process_loan_interest_accrual_for_demand_loans(posting_date=last_date)
|
process_loan_interest_accrual_for_demand_loans(posting_date=last_date)
|
||||||
loan_interest_accural = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name})
|
loan_interest_accural = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name})
|
||||||
|
|
||||||
self.assertEquals(flt(loan_interest_accural.interest_amount, 0), flt(accrued_interest_amount, 0))
|
self.assertEqual(flt(loan_interest_accural.interest_amount, 0), flt(accrued_interest_amount, 0))
|
||||||
|
|
||||||
def test_accumulated_amounts(self):
|
def test_accumulated_amounts(self):
|
||||||
pledge = [{
|
pledge = [{
|
||||||
@ -76,7 +76,7 @@ class TestLoanInterestAccrual(unittest.TestCase):
|
|||||||
process_loan_interest_accrual_for_demand_loans(posting_date=last_date)
|
process_loan_interest_accrual_for_demand_loans(posting_date=last_date)
|
||||||
loan_interest_accrual = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name})
|
loan_interest_accrual = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name})
|
||||||
|
|
||||||
self.assertEquals(flt(loan_interest_accrual.interest_amount, 0), flt(accrued_interest_amount, 0))
|
self.assertEqual(flt(loan_interest_accrual.interest_amount, 0), flt(accrued_interest_amount, 0))
|
||||||
|
|
||||||
next_start_date = '2019-10-31'
|
next_start_date = '2019-10-31'
|
||||||
next_end_date = '2019-11-29'
|
next_end_date = '2019-11-29'
|
||||||
@ -90,4 +90,4 @@ class TestLoanInterestAccrual(unittest.TestCase):
|
|||||||
|
|
||||||
loan_interest_accrual = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name,
|
loan_interest_accrual = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name,
|
||||||
'process_loan_interest_accrual': process})
|
'process_loan_interest_accrual': process})
|
||||||
self.assertEquals(flt(loan_interest_accrual.total_pending_interest_amount, 0), total_pending_interest_amount)
|
self.assertEqual(flt(loan_interest_accrual.total_pending_interest_amount, 0), total_pending_interest_amount)
|
||||||
|
@ -435,7 +435,6 @@ def get_amounts(amounts, against_loan, posting_date):
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def calculate_amounts(against_loan, posting_date, payment_type=''):
|
def calculate_amounts(against_loan, posting_date, payment_type=''):
|
||||||
|
|
||||||
amounts = {
|
amounts = {
|
||||||
'penalty_amount': 0.0,
|
'penalty_amount': 0.0,
|
||||||
'interest_amount': 0.0,
|
'interest_amount': 0.0,
|
||||||
|
@ -29,7 +29,10 @@ frappe.ui.form.on("BOM", {
|
|||||||
|
|
||||||
frm.set_query("item", function() {
|
frm.set_query("item", function() {
|
||||||
return {
|
return {
|
||||||
query: "erpnext.manufacturing.doctype.bom.bom.item_query"
|
query: "erpnext.manufacturing.doctype.bom.bom.item_query",
|
||||||
|
filters: {
|
||||||
|
"is_stock_item": 1
|
||||||
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -973,6 +973,9 @@ def item_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
if not has_variants:
|
if not has_variants:
|
||||||
query_filters["has_variants"] = 0
|
query_filters["has_variants"] = 0
|
||||||
|
|
||||||
|
if filters and filters.get("is_stock_item"):
|
||||||
|
query_filters["is_stock_item"] = 1
|
||||||
|
|
||||||
return frappe.get_all("Item",
|
return frappe.get_all("Item",
|
||||||
fields = fields, filters=query_filters,
|
fields = fields, filters=query_filters,
|
||||||
or_filters = or_cond_filters, order_by=order_by,
|
or_filters = or_cond_filters, order_by=order_by,
|
||||||
|
@ -223,7 +223,7 @@ class TestBOM(unittest.TestCase):
|
|||||||
is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC")
|
is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC")
|
||||||
bom_items = sorted([d.item_code for d in bom.items if d.sourced_by_supplier != 1])
|
bom_items = sorted([d.item_code for d in bom.items if d.sourced_by_supplier != 1])
|
||||||
supplied_items = sorted([d.rm_item_code for d in po.supplied_items])
|
supplied_items = sorted([d.rm_item_code for d in po.supplied_items])
|
||||||
self.assertEquals(bom_items, supplied_items)
|
self.assertEqual(bom_items, supplied_items)
|
||||||
|
|
||||||
def get_default_bom(item_code="_Test FG Item 2"):
|
def get_default_bom(item_code="_Test FG Item 2"):
|
||||||
return frappe.db.get_value("BOM", {"item": item_code, "is_active": 1, "is_default": 1})
|
return frappe.db.get_value("BOM", {"item": item_code, "is_active": 1, "is_default": 1})
|
||||||
|
@ -45,16 +45,16 @@ class TestBOMUpdateTool(unittest.TestCase):
|
|||||||
else:
|
else:
|
||||||
doc = frappe.get_doc("BOM", bom_no)
|
doc = frappe.get_doc("BOM", bom_no)
|
||||||
|
|
||||||
self.assertEquals(doc.total_cost, 200)
|
self.assertEqual(doc.total_cost, 200)
|
||||||
|
|
||||||
frappe.db.set_value("Item", "BOM Cost Test Item 2", "valuation_rate", 200)
|
frappe.db.set_value("Item", "BOM Cost Test Item 2", "valuation_rate", 200)
|
||||||
update_cost()
|
update_cost()
|
||||||
|
|
||||||
doc.load_from_db()
|
doc.load_from_db()
|
||||||
self.assertEquals(doc.total_cost, 300)
|
self.assertEqual(doc.total_cost, 300)
|
||||||
|
|
||||||
frappe.db.set_value("Item", "BOM Cost Test Item 2", "valuation_rate", 100)
|
frappe.db.set_value("Item", "BOM Cost Test Item 2", "valuation_rate", 100)
|
||||||
update_cost()
|
update_cost()
|
||||||
|
|
||||||
doc.load_from_db()
|
doc.load_from_db()
|
||||||
self.assertEquals(doc.total_cost, 200)
|
self.assertEqual(doc.total_cost, 200)
|
||||||
|
@ -473,7 +473,7 @@ class TestWorkOrder(unittest.TestCase):
|
|||||||
def test_cost_center_for_manufacture(self):
|
def test_cost_center_for_manufacture(self):
|
||||||
wo_order = make_wo_order_test_record()
|
wo_order = make_wo_order_test_record()
|
||||||
ste = make_stock_entry(wo_order.name, "Material Transfer for Manufacture", wo_order.qty)
|
ste = make_stock_entry(wo_order.name, "Material Transfer for Manufacture", wo_order.qty)
|
||||||
self.assertEquals(ste.get("items")[0].get("cost_center"), "_Test Cost Center - _TC")
|
self.assertEqual(ste.get("items")[0].get("cost_center"), "_Test Cost Center - _TC")
|
||||||
|
|
||||||
def test_operation_time_with_batch_size(self):
|
def test_operation_time_with_batch_size(self):
|
||||||
fg_item = "Test Batch Size Item For BOM"
|
fg_item = "Test Batch Size Item For BOM"
|
||||||
@ -539,11 +539,11 @@ class TestWorkOrder(unittest.TestCase):
|
|||||||
ste_cancel_list.append(ste1)
|
ste_cancel_list.append(ste1)
|
||||||
|
|
||||||
ste3 = frappe.get_doc(make_stock_entry(wo_order.name, "Material Consumption for Manufacture", 2))
|
ste3 = frappe.get_doc(make_stock_entry(wo_order.name, "Material Consumption for Manufacture", 2))
|
||||||
self.assertEquals(ste3.fg_completed_qty, 2)
|
self.assertEqual(ste3.fg_completed_qty, 2)
|
||||||
|
|
||||||
expected_qty = {"_Test Item": 2, "_Test Item Home Desktop 100": 4}
|
expected_qty = {"_Test Item": 2, "_Test Item Home Desktop 100": 4}
|
||||||
for row in ste3.items:
|
for row in ste3.items:
|
||||||
self.assertEquals(row.qty, expected_qty.get(row.item_code))
|
self.assertEqual(row.qty, expected_qty.get(row.item_code))
|
||||||
ste_cancel_list.reverse()
|
ste_cancel_list.reverse()
|
||||||
for ste_doc in ste_cancel_list:
|
for ste_doc in ste_cancel_list:
|
||||||
ste_doc.cancel()
|
ste_doc.cancel()
|
||||||
@ -577,7 +577,7 @@ class TestWorkOrder(unittest.TestCase):
|
|||||||
ste3 = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 2))
|
ste3 = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 2))
|
||||||
for ste_row in ste3.items:
|
for ste_row in ste3.items:
|
||||||
if itemwise_qty.get(ste_row.item_code) and ste_row.s_warehouse:
|
if itemwise_qty.get(ste_row.item_code) and ste_row.s_warehouse:
|
||||||
self.assertEquals(ste_row.qty, itemwise_qty.get(ste_row.item_code) / 2)
|
self.assertEqual(ste_row.qty, itemwise_qty.get(ste_row.item_code) / 2)
|
||||||
|
|
||||||
ste3.submit()
|
ste3.submit()
|
||||||
ste_cancel_list.append(ste3)
|
ste_cancel_list.append(ste3)
|
||||||
@ -585,7 +585,7 @@ class TestWorkOrder(unittest.TestCase):
|
|||||||
ste2 = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 2))
|
ste2 = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 2))
|
||||||
for ste_row in ste2.items:
|
for ste_row in ste2.items:
|
||||||
if itemwise_qty.get(ste_row.item_code) and ste_row.s_warehouse:
|
if itemwise_qty.get(ste_row.item_code) and ste_row.s_warehouse:
|
||||||
self.assertEquals(ste_row.qty, itemwise_qty.get(ste_row.item_code) / 2)
|
self.assertEqual(ste_row.qty, itemwise_qty.get(ste_row.item_code) / 2)
|
||||||
ste_cancel_list.reverse()
|
ste_cancel_list.reverse()
|
||||||
for ste_doc in ste_cancel_list:
|
for ste_doc in ste_cancel_list:
|
||||||
ste_doc.cancel()
|
ste_doc.cancel()
|
||||||
|
@ -39,7 +39,7 @@ class TestDonation(unittest.TestCase):
|
|||||||
donation.on_payment_authorized()
|
donation.on_payment_authorized()
|
||||||
donation.reload()
|
donation.reload()
|
||||||
|
|
||||||
self.assertEquals(donation.paid, 1)
|
self.assertEqual(donation.paid, 1)
|
||||||
self.assertTrue(frappe.db.exists('Payment Entry', {'reference_no': donation.name}))
|
self.assertTrue(frappe.db.exists('Payment Entry', {'reference_no': donation.name}))
|
||||||
|
|
||||||
|
|
||||||
|
@ -774,4 +774,7 @@ erpnext.patches.v12_0.add_document_type_field_for_italy_einvoicing
|
|||||||
erpnext.patches.v13_0.make_non_standard_user_type #13-04-2021
|
erpnext.patches.v13_0.make_non_standard_user_type #13-04-2021
|
||||||
erpnext.patches.v13_0.update_shipment_status
|
erpnext.patches.v13_0.update_shipment_status
|
||||||
erpnext.patches.v13_0.remove_attribute_field_from_item_variant_setting
|
erpnext.patches.v13_0.remove_attribute_field_from_item_variant_setting
|
||||||
|
erpnext.patches.v12_0.add_ewaybill_validity_field
|
||||||
|
erpnext.patches.v13_0.germany_make_custom_fields
|
||||||
|
erpnext.patches.v13_0.germany_fill_debtor_creditor_number
|
||||||
erpnext.patches.v13_0.set_pos_closing_as_failed
|
erpnext.patches.v13_0.set_pos_closing_as_failed
|
||||||
|
16
erpnext/patches/v12_0/add_ewaybill_validity_field.py
Normal file
16
erpnext/patches/v12_0/add_ewaybill_validity_field.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
company = frappe.get_all('Company', filters = {'country': 'India'})
|
||||||
|
if not company:
|
||||||
|
return
|
||||||
|
|
||||||
|
custom_fields = {
|
||||||
|
'Sales Invoice': [
|
||||||
|
dict(fieldname='eway_bill_validity', label='E-Way Bill Validity', fieldtype='Data', no_copy=1, print_hide=1,
|
||||||
|
depends_on='ewaybill', read_only=1, allow_on_submit=1, insert_after='ewaybill')
|
||||||
|
]
|
||||||
|
}
|
||||||
|
create_custom_fields(custom_fields, update=True)
|
@ -44,9 +44,11 @@ def execute():
|
|||||||
# make current item's tax map
|
# make current item's tax map
|
||||||
item_tax_map = {}
|
item_tax_map = {}
|
||||||
for d in old_item_taxes[item_code]:
|
for d in old_item_taxes[item_code]:
|
||||||
item_tax_map[d.tax_type] = d.tax_rate
|
if d.tax_type not in item_tax_map:
|
||||||
|
item_tax_map[d.tax_type] = d.tax_rate
|
||||||
|
|
||||||
item_tax_template_name = get_item_tax_template(item_tax_templates, item_tax_map, item_code)
|
tax_types = []
|
||||||
|
item_tax_template_name = get_item_tax_template(item_tax_templates, item_tax_map, item_code, tax_types=tax_types)
|
||||||
|
|
||||||
# update the item tax table
|
# update the item tax table
|
||||||
frappe.db.sql("delete from `tabItem Tax` where parent=%s and parenttype='Item'", item_code)
|
frappe.db.sql("delete from `tabItem Tax` where parent=%s and parenttype='Item'", item_code)
|
||||||
@ -68,7 +70,7 @@ def execute():
|
|||||||
and item_tax_template is NULL""".format(dt), as_dict=1):
|
and item_tax_template is NULL""".format(dt), as_dict=1):
|
||||||
item_tax_map = json.loads(d.item_tax_rate)
|
item_tax_map = json.loads(d.item_tax_rate)
|
||||||
item_tax_template_name = get_item_tax_template(item_tax_templates,
|
item_tax_template_name = get_item_tax_template(item_tax_templates,
|
||||||
item_tax_map, d.item_code, d.parenttype, d.parent)
|
item_tax_map, d.item_code, d.parenttype, d.parent, tax_types=tax_types)
|
||||||
frappe.db.set_value(dt + " Item", d.name, "item_tax_template", item_tax_template_name)
|
frappe.db.set_value(dt + " Item", d.name, "item_tax_template", item_tax_template_name)
|
||||||
|
|
||||||
frappe.db.auto_commit_on_many_writes = False
|
frappe.db.auto_commit_on_many_writes = False
|
||||||
@ -78,7 +80,7 @@ def execute():
|
|||||||
settings.determine_address_tax_category_from = "Billing Address"
|
settings.determine_address_tax_category_from = "Billing Address"
|
||||||
settings.save()
|
settings.save()
|
||||||
|
|
||||||
def get_item_tax_template(item_tax_templates, item_tax_map, item_code, parenttype=None, parent=None):
|
def get_item_tax_template(item_tax_templates, item_tax_map, item_code, parenttype=None, parent=None, tax_types=None):
|
||||||
# search for previously created item tax template by comparing tax maps
|
# search for previously created item tax template by comparing tax maps
|
||||||
for template, item_tax_template_map in iteritems(item_tax_templates):
|
for template, item_tax_template_map in iteritems(item_tax_templates):
|
||||||
if item_tax_map == item_tax_template_map:
|
if item_tax_map == item_tax_template_map:
|
||||||
@ -126,7 +128,9 @@ def get_item_tax_template(item_tax_templates, item_tax_map, item_code, parenttyp
|
|||||||
account_type = frappe.get_cached_value("Account", tax_type, "account_type")
|
account_type = frappe.get_cached_value("Account", tax_type, "account_type")
|
||||||
|
|
||||||
if tax_type and account_type in ('Tax', 'Chargeable', 'Income Account', 'Expense Account', 'Expenses Included In Valuation'):
|
if tax_type and account_type in ('Tax', 'Chargeable', 'Income Account', 'Expense Account', 'Expenses Included In Valuation'):
|
||||||
item_tax_template.append("taxes", {"tax_type": tax_type, "tax_rate": tax_rate})
|
if tax_type not in tax_types:
|
||||||
|
item_tax_template.append("taxes", {"tax_type": tax_type, "tax_rate": tax_rate})
|
||||||
|
tax_types.append(tax_type)
|
||||||
item_tax_templates.setdefault(item_tax_template.title, {})
|
item_tax_templates.setdefault(item_tax_template.title, {})
|
||||||
item_tax_templates[item_tax_template.title][tax_type] = tax_rate
|
item_tax_templates[item_tax_template.title][tax_type] = tax_rate
|
||||||
if item_tax_template.get("taxes"):
|
if item_tax_template.get("taxes"):
|
||||||
|
@ -22,5 +22,7 @@ def execute():
|
|||||||
|
|
||||||
frappe.delete_doc("Page", "bank-reconciliation", force=1)
|
frappe.delete_doc("Page", "bank-reconciliation", force=1)
|
||||||
|
|
||||||
|
frappe.reload_doc('accounts', 'doctype', 'bank_transaction')
|
||||||
|
|
||||||
rename_field("Bank Transaction", "debit", "deposit")
|
rename_field("Bank Transaction", "debit", "deposit")
|
||||||
rename_field("Bank Transaction", "credit", "withdrawal")
|
rename_field("Bank Transaction", "credit", "withdrawal")
|
||||||
|
31
erpnext/patches/v13_0/germany_fill_debtor_creditor_number.py
Normal file
31
erpnext/patches/v13_0/germany_fill_debtor_creditor_number.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Copyright (c) 2019, Frappe and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
"""Move account number into the new custom field debtor_creditor_number.
|
||||||
|
|
||||||
|
German companies used to use a dedicated payable/receivable account for
|
||||||
|
every party to mimick party accounts in the external accounting software
|
||||||
|
"DATEV". This is no longer necessary. The reference ID for DATEV will be
|
||||||
|
stored in a new custom field "debtor_creditor_number".
|
||||||
|
"""
|
||||||
|
company_list = frappe.get_all('Company', filters={'country': 'Germany'})
|
||||||
|
|
||||||
|
for company in company_list:
|
||||||
|
party_account_list = frappe.get_all('Party Account', filters={'company': company.name}, fields=['name', 'account', 'debtor_creditor_number'])
|
||||||
|
for party_account in party_account_list:
|
||||||
|
if (not party_account.account) or party_account.debtor_creditor_number:
|
||||||
|
# account empty or debtor_creditor_number already filled
|
||||||
|
continue
|
||||||
|
|
||||||
|
account_number = frappe.db.get_value('Account', party_account.account, 'account_number')
|
||||||
|
if not account_number:
|
||||||
|
continue
|
||||||
|
|
||||||
|
frappe.db.set_value('Party Account', party_account.name, 'debtor_creditor_number', account_number)
|
||||||
|
frappe.db.set_value('Party Account', party_account.name, 'account', '')
|
20
erpnext/patches/v13_0/germany_make_custom_fields.py
Normal file
20
erpnext/patches/v13_0/germany_make_custom_fields.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Copyright (c) 2019, Frappe and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
from erpnext.regional.germany.setup import make_custom_fields
|
||||||
|
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
"""Execute the make_custom_fields method for german companies.
|
||||||
|
|
||||||
|
It is usually run once at setup of a new company. Since it's new, run it
|
||||||
|
once for existing companies as well.
|
||||||
|
"""
|
||||||
|
company_list = frappe.get_all('Company', filters = {'country': 'Germany'})
|
||||||
|
if not company_list:
|
||||||
|
return
|
||||||
|
|
||||||
|
make_custom_fields()
|
@ -13,12 +13,19 @@ class AdditionalSalary(Document):
|
|||||||
if self.ref_doctype == "Employee Advance" and self.ref_docname:
|
if self.ref_doctype == "Employee Advance" and self.ref_docname:
|
||||||
frappe.db.set_value("Employee Advance", self.ref_docname, "return_amount", self.amount)
|
frappe.db.set_value("Employee Advance", self.ref_docname, "return_amount", self.amount)
|
||||||
|
|
||||||
|
self.update_employee_referral()
|
||||||
|
|
||||||
|
def on_cancel(self):
|
||||||
|
self.update_employee_referral(cancel=True)
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_dates()
|
self.validate_dates()
|
||||||
self.validate_salary_structure()
|
self.validate_salary_structure()
|
||||||
self.validate_recurring_additional_salary_overlap()
|
self.validate_recurring_additional_salary_overlap()
|
||||||
|
self.validate_employee_referral()
|
||||||
|
|
||||||
if self.amount < 0:
|
if self.amount < 0:
|
||||||
frappe.throw(_("Amount should not be less than zero."))
|
frappe.throw(_("Amount should not be less than zero"))
|
||||||
|
|
||||||
def validate_salary_structure(self):
|
def validate_salary_structure(self):
|
||||||
if not frappe.db.exists('Salary Structure Assignment', {'employee': self.employee}):
|
if not frappe.db.exists('Salary Structure Assignment', {'employee': self.employee}):
|
||||||
@ -70,6 +77,27 @@ class AdditionalSalary(Document):
|
|||||||
if self.payroll_date and getdate(self.payroll_date) > getdate(relieving_date):
|
if self.payroll_date and getdate(self.payroll_date) > getdate(relieving_date):
|
||||||
frappe.throw(_("Payroll date can not be greater than employee's relieving date."))
|
frappe.throw(_("Payroll date can not be greater than employee's relieving date."))
|
||||||
|
|
||||||
|
def validate_employee_referral(self):
|
||||||
|
if self.ref_doctype == "Employee Referral":
|
||||||
|
referral_details = frappe.db.get_value("Employee Referral", self.ref_docname,
|
||||||
|
["is_applicable_for_referral_bonus", "status"], as_dict=1)
|
||||||
|
|
||||||
|
if not referral_details.is_applicable_for_referral_bonus:
|
||||||
|
frappe.throw(_("Employee Referral {0} is not applicable for referral bonus.").format(
|
||||||
|
self.ref_docname))
|
||||||
|
|
||||||
|
if self.type == "Deduction":
|
||||||
|
frappe.throw(_("Earning Salary Component is required for Employee Referral Bonus."))
|
||||||
|
|
||||||
|
if referral_details.status != "Accepted":
|
||||||
|
frappe.throw(_("Additional Salary for referral bonus can only be created against Employee Referral with status {0}").format(
|
||||||
|
frappe.bold("Accepted")))
|
||||||
|
|
||||||
|
def update_employee_referral(self, cancel=False):
|
||||||
|
if self.ref_doctype == "Employee Referral":
|
||||||
|
status = "Unpaid" if cancel else "Paid"
|
||||||
|
frappe.db.set_value("Employee Referral", self.ref_docname, "referral_payment_status", status)
|
||||||
|
|
||||||
def get_amount(self, sal_start_date, sal_end_date):
|
def get_amount(self, sal_start_date, sal_end_date):
|
||||||
start_date = getdate(sal_start_date)
|
start_date = getdate(sal_start_date)
|
||||||
end_date = getdate(sal_end_date)
|
end_date = getdate(sal_end_date)
|
||||||
@ -110,8 +138,7 @@ def get_additional_salaries(employee, start_date, end_date, component_type):
|
|||||||
for d in additional_salary_list:
|
for d in additional_salary_list:
|
||||||
if d.overwrite:
|
if d.overwrite:
|
||||||
if d.component in components_to_overwrite:
|
if d.component in components_to_overwrite:
|
||||||
frappe.throw(_("Multiple Additional Salaries with overwrite "
|
frappe.throw(_("Multiple Additional Salaries with overwrite property exist for Salary Component {0} between {1} and {2}.").format(
|
||||||
"property exist for Salary Component {0} between {1} and {2}.").format(
|
|
||||||
frappe.bold(d.component), start_date, end_date), title=_("Error"))
|
frappe.bold(d.component), start_date, end_date), title=_("Error"))
|
||||||
|
|
||||||
components_to_overwrite.append(d.component)
|
components_to_overwrite.append(d.component)
|
||||||
|
@ -16,11 +16,11 @@ frappe.ui.form.on('Salary Structure', {
|
|||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
|
|
||||||
let help_button = $(`<a class = 'control-label'>
|
let help_button = $(`<a class = 'control-label'>
|
||||||
Condition and Formula Help
|
${__("Condition and Formula Help")}
|
||||||
</a>`).click(()=>{
|
</a>`).click(()=>{
|
||||||
|
|
||||||
let d = new frappe.ui.Dialog({
|
let d = new frappe.ui.Dialog({
|
||||||
title: 'Condition and Formula Help',
|
title: __('Condition and Formula Help'),
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
fieldname: 'msg_wrapper',
|
fieldname: 'msg_wrapper',
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"attach_print": 0,
|
"attach_print": 0,
|
||||||
|
"channel": "Email",
|
||||||
"condition": "doc.docstatus==1",
|
"condition": "doc.docstatus==1",
|
||||||
"creation": "2018-05-15 18:52:36.362838",
|
"creation": "2018-05-15 18:52:36.362838",
|
||||||
"date_changed": "bonus_payment_date",
|
"date_changed": "bonus_payment_date",
|
||||||
|
@ -13,7 +13,7 @@ class TestHomepage(unittest.TestCase):
|
|||||||
set_request(method='GET', path='home')
|
set_request(method='GET', path='home')
|
||||||
response = render()
|
response = render()
|
||||||
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
html = frappe.safe_decode(response.get_data())
|
html = frappe.safe_decode(response.get_data())
|
||||||
self.assertTrue('<section class="hero-section' in html)
|
self.assertTrue('<section class="hero-section' in html)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user