commit
18cf2f31d1
14
.editorconfig
Normal file
14
.editorconfig
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Root editor config file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# Common settings
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
charset = utf-8
|
||||||
|
|
||||||
|
# python, js indentation settings
|
||||||
|
[{*.py,*.js}]
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 4
|
20
.eslintrc
20
.eslintrc
@ -5,7 +5,7 @@
|
|||||||
"es6": true
|
"es6": true
|
||||||
},
|
},
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 6,
|
"ecmaVersion": 9,
|
||||||
"sourceType": "module"
|
"sourceType": "module"
|
||||||
},
|
},
|
||||||
"extends": "eslint:recommended",
|
"extends": "eslint:recommended",
|
||||||
@ -15,6 +15,14 @@
|
|||||||
"tab",
|
"tab",
|
||||||
{ "SwitchCase": 1 }
|
{ "SwitchCase": 1 }
|
||||||
],
|
],
|
||||||
|
"brace-style": [
|
||||||
|
"error",
|
||||||
|
"1tbs"
|
||||||
|
],
|
||||||
|
"space-unary-ops": [
|
||||||
|
"error",
|
||||||
|
{ "words": true }
|
||||||
|
],
|
||||||
"linebreak-style": [
|
"linebreak-style": [
|
||||||
"error",
|
"error",
|
||||||
"unix"
|
"unix"
|
||||||
@ -44,12 +52,10 @@
|
|||||||
"no-control-regex": [
|
"no-control-regex": [
|
||||||
"off"
|
"off"
|
||||||
],
|
],
|
||||||
"spaced-comment": [
|
"space-before-blocks": "warn",
|
||||||
"warn"
|
"keyword-spacing": "warn",
|
||||||
],
|
"comma-spacing": "warn",
|
||||||
"no-trailing-spaces": [
|
"key-spacing": "warn"
|
||||||
"warn"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"root": true,
|
"root": true,
|
||||||
"globals": {
|
"globals": {
|
||||||
|
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: Community Forum
|
||||||
|
url: https://discuss.erpnext.com/
|
||||||
|
about: For general QnA, discussions and community help.
|
@ -9,5 +9,6 @@
|
|||||||
"root_login": "root",
|
"root_login": "root",
|
||||||
"root_password": "travis",
|
"root_password": "travis",
|
||||||
"host_name": "http://test_site:8000",
|
"host_name": "http://test_site:8000",
|
||||||
"install_apps": ["erpnext"]
|
"install_apps": ["erpnext"],
|
||||||
|
"throttle_user_limit": 100
|
||||||
}
|
}
|
@ -5,7 +5,7 @@
|
|||||||
<p>ERP made simple</p>
|
<p>ERP made simple</p>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.com/frappe/erpnext.svg)](https://travis-ci.com/frappe/erpnext)
|
[![Build Status](https://api.travis-ci.com/frappe/erpnext.svg?branch=develop)](https://travis-ci.com/frappe/erpnext)
|
||||||
[![Open Source Helpers](https://www.codetriage.com/frappe/erpnext/badges/users.svg)](https://www.codetriage.com/frappe/erpnext)
|
[![Open Source Helpers](https://www.codetriage.com/frappe/erpnext/badges/users.svg)](https://www.codetriage.com/frappe/erpnext)
|
||||||
[![Coverage Status](https://coveralls.io/repos/github/frappe/erpnext/badge.svg?branch=develop)](https://coveralls.io/github/frappe/erpnext?branch=develop)
|
[![Coverage Status](https://coveralls.io/repos/github/frappe/erpnext/badge.svg?branch=develop)](https://coveralls.io/github/frappe/erpnext?branch=develop)
|
||||||
|
|
||||||
|
@ -6,9 +6,8 @@ import frappe, json
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import add_to_date, date_diff, getdate, nowdate, get_last_day, formatdate, get_link_to_form
|
from frappe.utils import add_to_date, date_diff, getdate, nowdate, get_last_day, formatdate, get_link_to_form
|
||||||
from erpnext.accounts.report.general_ledger.general_ledger import execute
|
from erpnext.accounts.report.general_ledger.general_ledger import execute
|
||||||
from frappe.utils.dashboard import cache_source, get_from_date_from_timespan
|
from frappe.utils.dashboard import cache_source
|
||||||
from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_period_ending
|
from frappe.utils.dateutils import get_from_date_from_timespan, get_period_ending
|
||||||
|
|
||||||
from frappe.utils.nestedset import get_descendants_of
|
from frappe.utils.nestedset import get_descendants_of
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
{
|
{
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"label": "Reports",
|
"label": "Reports",
|
||||||
"links": "[\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Trial Balance for Party\",\n \"name\": \"Trial Balance for Party\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Journal Entry\"\n ],\n \"doctype\": \"Journal Entry\",\n \"is_query_report\": true,\n \"label\": \"Payment Period Based On Invoice Date\",\n \"name\": \"Payment Period Based On Invoice Date\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Partners Commission\",\n \"name\": \"Sales Partners Commission\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Customer Credit Balance\",\n \"name\": \"Customer Credit Balance\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Payment Summary\",\n \"name\": \"Sales Payment Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Address\"\n ],\n \"doctype\": \"Address\",\n \"is_query_report\": true,\n \"label\": \"Address And Contacts\",\n \"name\": \"Address And Contacts\",\n \"type\": \"report\"\n }\n]"
|
"links": "[\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Trial Balance for Party\",\n \"name\": \"Trial Balance for Party\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Journal Entry\"\n ],\n \"doctype\": \"Journal Entry\",\n \"is_query_report\": true,\n \"label\": \"Payment Period Based On Invoice Date\",\n \"name\": \"Payment Period Based On Invoice Date\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Partners Commission\",\n \"name\": \"Sales Partners Commission\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Customer Credit Balance\",\n \"name\": \"Customer Credit Balance\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Payment Summary\",\n \"name\": \"Sales Payment Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Address\"\n ],\n \"doctype\": \"Address\",\n \"is_query_report\": true,\n \"label\": \"Address And Contacts\",\n \"name\": \"Address And Contacts\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"DATEV Export\",\n \"name\": \"DATEV\",\n \"type\": \"report\"\n }\n]"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -43,7 +43,7 @@
|
|||||||
{
|
{
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"label": "Bank Statement",
|
"label": "Bank Statement",
|
||||||
"links": "[\n {\n \"label\": \"Bank\",\n \"name\": \"Bank\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Account\",\n \"name\": \"Bank Account\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Statement Transaction Entry\",\n \"name\": \"Bank Statement Transaction Entry\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Statement Settings\",\n \"name\": \"Bank Statement Settings\",\n \"type\": \"doctype\"\n }\n]"
|
"links": "[\n {\n \"label\": \"Bank\",\n \"name\": \"Bank\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Account\",\n \"name\": \"Bank Account\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Clearance\",\n \"name\": \"Bank Clearance\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Reconciliation\",\n \"name\": \"bank-reconciliation\",\n \"type\": \"page\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Bank Reconciliation Statement\",\n \"name\": \"Bank Reconciliation Statement\",\n \"type\": \"report\"\n }\n]"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -79,6 +79,11 @@
|
|||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"label": "Profitability",
|
"label": "Profitability",
|
||||||
"links": "[\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Gross Profit\",\n \"name\": \"Gross Profit\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Profitability Analysis\",\n \"name\": \"Profitability Analysis\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Invoice Trends\",\n \"name\": \"Sales Invoice Trends\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Purchase Invoice Trends\",\n \"name\": \"Purchase Invoice Trends\",\n \"type\": \"report\"\n }\n]"
|
"links": "[\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Gross Profit\",\n \"name\": \"Gross Profit\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Profitability Analysis\",\n \"name\": \"Profitability Analysis\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Invoice Trends\",\n \"name\": \"Sales Invoice Trends\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Purchase Invoice Trends\",\n \"name\": \"Purchase Invoice Trends\",\n \"type\": \"report\"\n }\n]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": 0,
|
||||||
|
"label": "Value-Added Tax (VAT UAE)",
|
||||||
|
"links": "[\n {\n \"country\": \"United Arab Emirates\",\n \"label\": \"UAE VAT Settings\",\n \"name\": \"UAE VAT Settings\",\n \"type\": \"doctype\"\n },\n {\n \"country\": \"United Arab Emirates\",\n \"is_query_report\": true,\n \"label\": \"UAE VAT 201\",\n \"name\": \"UAE VAT 201\",\n \"type\": \"report\"\n }\n\n]"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"category": "Modules",
|
"category": "Modules",
|
||||||
@ -98,7 +103,7 @@
|
|||||||
"idx": 0,
|
"idx": 0,
|
||||||
"is_standard": 1,
|
"is_standard": 1,
|
||||||
"label": "Accounting",
|
"label": "Accounting",
|
||||||
"modified": "2020-10-08 20:31:46.022470",
|
"modified": "2020-11-11 18:35:11.542909",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Accounting",
|
"name": "Accounting",
|
||||||
@ -108,7 +113,7 @@
|
|||||||
"pin_to_top": 0,
|
"pin_to_top": 0,
|
||||||
"shortcuts": [
|
"shortcuts": [
|
||||||
{
|
{
|
||||||
"label": "Chart of Accounts",
|
"label": "Chart Of Accounts",
|
||||||
"link_to": "Account",
|
"link_to": "Account",
|
||||||
"type": "DocType"
|
"type": "DocType"
|
||||||
},
|
},
|
||||||
|
@ -245,6 +245,9 @@ def get():
|
|||||||
"account_number": "2200"
|
"account_number": "2200"
|
||||||
},
|
},
|
||||||
_("Duties and Taxes"): {
|
_("Duties and Taxes"): {
|
||||||
|
_("TDS Payable"): {
|
||||||
|
"account_number": "2310"
|
||||||
|
},
|
||||||
"account_type": "Tax",
|
"account_type": "Tax",
|
||||||
"is_group": 1,
|
"is_group": 1,
|
||||||
"account_number": "2300"
|
"account_number": "2300"
|
||||||
|
@ -9,11 +9,13 @@ from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sal
|
|||||||
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
||||||
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
|
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
|
||||||
from erpnext.accounts.page.bank_reconciliation.bank_reconciliation import reconcile, get_linked_payments
|
from erpnext.accounts.page.bank_reconciliation.bank_reconciliation import reconcile, get_linked_payments
|
||||||
|
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
|
||||||
|
|
||||||
test_dependencies = ["Item", "Cost Center"]
|
test_dependencies = ["Item", "Cost Center"]
|
||||||
|
|
||||||
class TestBankTransaction(unittest.TestCase):
|
class TestBankTransaction(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
make_pos_profile()
|
||||||
add_transactions()
|
add_transactions()
|
||||||
add_payments()
|
add_payments()
|
||||||
|
|
||||||
@ -27,6 +29,9 @@ class TestBankTransaction(unittest.TestCase):
|
|||||||
frappe.db.sql("""delete from `tabPayment Entry Reference`""")
|
frappe.db.sql("""delete from `tabPayment Entry Reference`""")
|
||||||
frappe.db.sql("""delete from `tabPayment Entry`""")
|
frappe.db.sql("""delete from `tabPayment Entry`""")
|
||||||
|
|
||||||
|
# Delete POS Profile
|
||||||
|
frappe.db.sql("delete from `tabPOS Profile`")
|
||||||
|
|
||||||
frappe.flags.test_bank_transactions_created = False
|
frappe.flags.test_bank_transactions_created = False
|
||||||
frappe.flags.test_payments_created = False
|
frappe.flags.test_payments_created = False
|
||||||
|
|
||||||
|
@ -158,8 +158,11 @@ class TestBudget(unittest.TestCase):
|
|||||||
set_total_expense_zero(nowdate(), "cost_center")
|
set_total_expense_zero(nowdate(), "cost_center")
|
||||||
|
|
||||||
budget = make_budget(budget_against="Cost Center")
|
budget = make_budget(budget_against="Cost Center")
|
||||||
|
month = now_datetime().month
|
||||||
|
if month > 10:
|
||||||
|
month = 10
|
||||||
|
|
||||||
for i in range(now_datetime().month):
|
for i in range(month):
|
||||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||||
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
|
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
|
||||||
|
|
||||||
@ -177,8 +180,11 @@ class TestBudget(unittest.TestCase):
|
|||||||
set_total_expense_zero(nowdate(), "project")
|
set_total_expense_zero(nowdate(), "project")
|
||||||
|
|
||||||
budget = make_budget(budget_against="Project")
|
budget = make_budget(budget_against="Project")
|
||||||
|
month = now_datetime().month
|
||||||
|
if month > 10:
|
||||||
|
month = 10
|
||||||
|
|
||||||
for i in range(now_datetime().month):
|
for i in range(month):
|
||||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||||
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True, project="_Test Project")
|
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True, project="_Test Project")
|
||||||
|
|
||||||
|
@ -94,8 +94,7 @@ frappe.ui.form.on('Chart of Accounts Importer', {
|
|||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if(r.message===false) {
|
if(r.message===false) {
|
||||||
frm.set_value("company", "");
|
frm.set_value("company", "");
|
||||||
frappe.throw(__(`Transactions against the company already exist!
|
frappe.throw(__("Transactions against the Company already exist! Chart of Accounts can only be imported for a Company with no transactions."));
|
||||||
Chart Of accounts can be imported for company with no transactions`));
|
|
||||||
} else {
|
} else {
|
||||||
frm.trigger("refresh");
|
frm.trigger("refresh");
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,7 @@ frappe.ui.form.on('Fiscal Year', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
refresh: function (frm) {
|
refresh: function (frm) {
|
||||||
let doc = frm.doc;
|
if (!frm.doc.__islocal && (frm.doc.name != frappe.sys_defaults.fiscal_year)) {
|
||||||
frm.toggle_enable('year_start_date', doc.__islocal);
|
|
||||||
frm.toggle_enable('year_end_date', doc.__islocal);
|
|
||||||
|
|
||||||
if (!doc.__islocal && (doc.name != frappe.sys_defaults.fiscal_year)) {
|
|
||||||
frm.add_custom_button(__("Set as Default"), () => frm.events.set_as_default(frm));
|
frm.add_custom_button(__("Set as Default"), () => frm.events.set_as_default(frm));
|
||||||
frm.set_intro(__("To set this Fiscal Year as Default, click on 'Set as Default'"));
|
frm.set_intro(__("To set this Fiscal Year as Default, click on 'Set as Default'"));
|
||||||
} else {
|
} else {
|
||||||
@ -24,8 +20,10 @@ frappe.ui.form.on('Fiscal Year', {
|
|||||||
return frm.call('set_as_default');
|
return frm.call('set_as_default');
|
||||||
},
|
},
|
||||||
year_start_date: function(frm) {
|
year_start_date: function(frm) {
|
||||||
let year_end_date =
|
if (!frm.doc.is_short_year) {
|
||||||
frappe.datetime.add_days(frappe.datetime.add_months(frm.doc.year_start_date, 12), -1);
|
let year_end_date =
|
||||||
frm.set_value("year_end_date", year_end_date);
|
frappe.datetime.add_days(frappe.datetime.add_months(frm.doc.year_start_date, 12), -1);
|
||||||
|
frm.set_value("year_end_date", year_end_date);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,347 +1,126 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 0,
|
|
||||||
"autoname": "field:year",
|
"autoname": "field:year",
|
||||||
"beta": 0,
|
|
||||||
"creation": "2013-01-22 16:50:25",
|
"creation": "2013-01-22 16:50:25",
|
||||||
"custom": 0,
|
|
||||||
"description": "**Fiscal Year** represents a Financial Year. All accounting entries and other major transactions are tracked against **Fiscal Year**.",
|
"description": "**Fiscal Year** represents a Financial Year. All accounting entries and other major transactions are tracked against **Fiscal Year**.",
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Setup",
|
"document_type": "Setup",
|
||||||
"editable_grid": 0,
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"year",
|
||||||
|
"disabled",
|
||||||
|
"is_short_year",
|
||||||
|
"year_start_date",
|
||||||
|
"year_end_date",
|
||||||
|
"companies",
|
||||||
|
"auto_created"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"description": "For e.g. 2012, 2012-13",
|
"description": "For e.g. 2012, 2012-13",
|
||||||
"fieldname": "year",
|
"fieldname": "year",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Year Name",
|
"label": "Year Name",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldname": "year",
|
"oldfieldname": "year",
|
||||||
"oldfieldtype": "Data",
|
"oldfieldtype": "Data",
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"unique": 1
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"default": "0",
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "disabled",
|
"fieldname": "disabled",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"label": "Disabled"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Disabled",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "year_start_date",
|
"fieldname": "year_start_date",
|
||||||
"fieldtype": "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_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Year Start Date",
|
"label": "Year Start Date",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "year_start_date",
|
"oldfieldname": "year_start_date",
|
||||||
"oldfieldtype": "Date",
|
"oldfieldtype": "Date",
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"set_only_once": 1
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "year_end_date",
|
"fieldname": "year_end_date",
|
||||||
"fieldtype": "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_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Year End Date",
|
"label": "Year End Date",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"set_only_once": 1
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "companies",
|
"fieldname": "companies",
|
||||||
"fieldtype": "Table",
|
"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": "Companies",
|
"label": "Companies",
|
||||||
"length": 0,
|
"options": "Fiscal Year Company"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Fiscal Year 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,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"fieldname": "auto_created",
|
"fieldname": "auto_created",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Auto Created",
|
"label": "Auto Created",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_hide_if_no_value": 0,
|
"read_only": 1
|
||||||
"read_only": 1,
|
},
|
||||||
"remember_last_selected_value": 0,
|
{
|
||||||
"report_hide": 0,
|
"default": "0",
|
||||||
"reqd": 0,
|
"description": "Less than 12 months.",
|
||||||
"search_index": 0,
|
"fieldname": "is_short_year",
|
||||||
"set_only_once": 0,
|
"fieldtype": "Check",
|
||||||
"translatable": 0,
|
"label": "Is Short Year",
|
||||||
"unique": 0
|
"set_only_once": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"icon": "fa fa-calendar",
|
"icon": "fa fa-calendar",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"image_view": 0,
|
"links": [],
|
||||||
"in_create": 0,
|
"modified": "2020-11-05 12:16:53.081573",
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 0,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2018-04-25 14:21:41.273354",
|
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Fiscal Year",
|
"name": "Fiscal Year",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 0,
|
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "System Manager",
|
"role": "System Manager",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 0,
|
|
||||||
"delete": 0,
|
|
||||||
"email": 0,
|
|
||||||
"export": 0,
|
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 0,
|
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 0,
|
"role": "Sales User"
|
||||||
"role": "Sales User",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 0,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 0,
|
|
||||||
"delete": 0,
|
|
||||||
"email": 0,
|
|
||||||
"export": 0,
|
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 0,
|
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 0,
|
"role": "Purchase User"
|
||||||
"role": "Purchase User",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 0,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 0,
|
|
||||||
"delete": 0,
|
|
||||||
"email": 0,
|
|
||||||
"export": 0,
|
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 0,
|
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 0,
|
"role": "Accounts User"
|
||||||
"role": "Accounts User",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 0,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 0,
|
|
||||||
"delete": 0,
|
|
||||||
"email": 0,
|
|
||||||
"export": 0,
|
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 0,
|
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 0,
|
"role": "Stock User"
|
||||||
"role": "Stock User",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 0,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 0,
|
|
||||||
"delete": 0,
|
|
||||||
"email": 0,
|
|
||||||
"export": 0,
|
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 0,
|
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 0,
|
"role": "Employee"
|
||||||
"role": "Employee",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 0,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 1,
|
"show_name_in_global_search": 1,
|
||||||
"sort_field": "name",
|
"sort_field": "name",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC"
|
||||||
"track_changes": 0,
|
|
||||||
"track_seen": 0
|
|
||||||
}
|
}
|
@ -36,6 +36,11 @@ class FiscalYear(Document):
|
|||||||
frappe.throw(_("Cannot change Fiscal Year Start Date and Fiscal Year End Date once the Fiscal Year is saved."))
|
frappe.throw(_("Cannot change Fiscal Year Start Date and Fiscal Year End Date once the Fiscal Year is saved."))
|
||||||
|
|
||||||
def validate_dates(self):
|
def validate_dates(self):
|
||||||
|
if self.is_short_year:
|
||||||
|
# Fiscal Year can be shorter than one year, in some jurisdictions
|
||||||
|
# under certain circumstances. For example, in the USA and Germany.
|
||||||
|
return
|
||||||
|
|
||||||
if getdate(self.year_start_date) > getdate(self.year_end_date):
|
if getdate(self.year_start_date) > getdate(self.year_end_date):
|
||||||
frappe.throw(_("Fiscal Year Start Date should be one year earlier than Fiscal Year End Date"),
|
frappe.throw(_("Fiscal Year Start Date should be one year earlier than Fiscal Year End Date"),
|
||||||
FiscalYearIncorrectDate)
|
FiscalYearIncorrectDate)
|
||||||
@ -116,12 +121,8 @@ def auto_create_fiscal_year():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def get_from_and_to_date(fiscal_year):
|
def get_from_and_to_date(fiscal_year):
|
||||||
from_and_to_date_tuple = frappe.db.sql("""select year_start_date, year_end_date
|
fields = [
|
||||||
from `tabFiscal Year` where name=%s""", (fiscal_year))[0]
|
"year_start_date as from_date",
|
||||||
|
"year_end_date as to_date"
|
||||||
from_and_to_date = {
|
]
|
||||||
"from_date": from_and_to_date_tuple[0],
|
return frappe.db.get_value("Fiscal Year", fiscal_year, fields, as_dict=1)
|
||||||
"to_date": from_and_to_date_tuple[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
return from_and_to_date
|
|
||||||
|
@ -11,6 +11,7 @@ test_records = frappe.get_test_records('Fiscal Year')
|
|||||||
test_ignore = ["Company"]
|
test_ignore = ["Company"]
|
||||||
|
|
||||||
class TestFiscalYear(unittest.TestCase):
|
class TestFiscalYear(unittest.TestCase):
|
||||||
|
|
||||||
def test_extra_year(self):
|
def test_extra_year(self):
|
||||||
if frappe.db.exists("Fiscal Year", "_Test Fiscal Year 2000"):
|
if frappe.db.exists("Fiscal Year", "_Test Fiscal Year 2000"):
|
||||||
frappe.delete_doc("Fiscal Year", "_Test Fiscal Year 2000")
|
frappe.delete_doc("Fiscal Year", "_Test Fiscal Year 2000")
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"doctype": "Fiscal Year",
|
||||||
|
"year": "_Test Short Fiscal Year 2011",
|
||||||
|
"is_short_year": 1,
|
||||||
|
"year_end_date": "2011-04-01",
|
||||||
|
"year_start_date": "2011-12-31"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"doctype": "Fiscal Year",
|
"doctype": "Fiscal Year",
|
||||||
"year": "_Test Fiscal Year 2012",
|
"year": "_Test Fiscal Year 2012",
|
||||||
|
@ -137,11 +137,12 @@ class InvoiceDiscounting(AccountsController):
|
|||||||
"cost_center": erpnext.get_default_cost_center(self.company)
|
"cost_center": erpnext.get_default_cost_center(self.company)
|
||||||
})
|
})
|
||||||
|
|
||||||
je.append("accounts", {
|
if self.bank_charges:
|
||||||
"account": self.bank_charges_account,
|
je.append("accounts", {
|
||||||
"debit_in_account_currency": flt(self.bank_charges),
|
"account": self.bank_charges_account,
|
||||||
"cost_center": erpnext.get_default_cost_center(self.company)
|
"debit_in_account_currency": flt(self.bank_charges),
|
||||||
})
|
"cost_center": erpnext.get_default_cost_center(self.company)
|
||||||
|
})
|
||||||
|
|
||||||
je.append("accounts", {
|
je.append("accounts", {
|
||||||
"account": self.short_term_loan,
|
"account": self.short_term_loan,
|
||||||
|
@ -80,6 +80,7 @@ class TestInvoiceDiscounting(unittest.TestCase):
|
|||||||
short_term_loan=self.short_term_loan,
|
short_term_loan=self.short_term_loan,
|
||||||
bank_charges_account=self.bank_charges_account,
|
bank_charges_account=self.bank_charges_account,
|
||||||
bank_account=self.bank_account,
|
bank_account=self.bank_account,
|
||||||
|
bank_charges=100
|
||||||
)
|
)
|
||||||
|
|
||||||
je = inv_disc.create_disbursement_entry()
|
je = inv_disc.create_disbursement_entry()
|
||||||
@ -289,6 +290,7 @@ def create_invoice_discounting(invoices, **args):
|
|||||||
inv_disc.bank_account=args.bank_account
|
inv_disc.bank_account=args.bank_account
|
||||||
inv_disc.loan_start_date = args.start or nowdate()
|
inv_disc.loan_start_date = args.start or nowdate()
|
||||||
inv_disc.loan_period = args.period or 30
|
inv_disc.loan_period = args.period or 30
|
||||||
|
inv_disc.bank_charges = flt(args.bank_charges)
|
||||||
|
|
||||||
for d in invoices:
|
for d in invoices:
|
||||||
inv_disc.append("invoices", {
|
inv_disc.append("invoices", {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"actions": [],
|
"actions": [],
|
||||||
|
"allow_auto_repeat": 1,
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"creation": "2013-03-25 10:53:52",
|
"creation": "2013-03-25 10:53:52",
|
||||||
@ -503,7 +504,7 @@
|
|||||||
"idx": 176,
|
"idx": 176,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-06-02 18:15:46.955697",
|
"modified": "2020-10-30 13:56:01.121995",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Journal Entry",
|
"name": "Journal Entry",
|
||||||
|
@ -34,6 +34,7 @@ class JournalEntry(AccountsController):
|
|||||||
self.validate_entries_for_advance()
|
self.validate_entries_for_advance()
|
||||||
self.validate_multi_currency()
|
self.validate_multi_currency()
|
||||||
self.set_amounts_in_company_currency()
|
self.set_amounts_in_company_currency()
|
||||||
|
self.validate_debit_credit_amount()
|
||||||
self.validate_total_debit_and_credit()
|
self.validate_total_debit_and_credit()
|
||||||
self.validate_against_jv()
|
self.validate_against_jv()
|
||||||
self.validate_reference_doc()
|
self.validate_reference_doc()
|
||||||
@ -339,8 +340,7 @@ class JournalEntry(AccountsController):
|
|||||||
currency=account_currency)
|
currency=account_currency)
|
||||||
|
|
||||||
if flt(voucher_total) < (flt(order.advance_paid) + total):
|
if flt(voucher_total) < (flt(order.advance_paid) + total):
|
||||||
frappe.throw(_("Advance paid against {0} {1} cannot be greater \
|
frappe.throw(_("Advance paid against {0} {1} cannot be greater than Grand Total {2}").format(reference_type, reference_name, formatted_voucher_total))
|
||||||
than Grand Total {2}").format(reference_type, reference_name, formatted_voucher_total))
|
|
||||||
|
|
||||||
def validate_invoices(self):
|
def validate_invoices(self):
|
||||||
"""Validate totals and docstatus for invoices"""
|
"""Validate totals and docstatus for invoices"""
|
||||||
@ -369,6 +369,11 @@ class JournalEntry(AccountsController):
|
|||||||
if flt(d.debit > 0): d.against_account = ", ".join(list(set(accounts_credited)))
|
if flt(d.debit > 0): d.against_account = ", ".join(list(set(accounts_credited)))
|
||||||
if flt(d.credit > 0): d.against_account = ", ".join(list(set(accounts_debited)))
|
if flt(d.credit > 0): d.against_account = ", ".join(list(set(accounts_debited)))
|
||||||
|
|
||||||
|
def validate_debit_credit_amount(self):
|
||||||
|
for d in self.get('accounts'):
|
||||||
|
if not flt(d.debit) and not flt(d.credit):
|
||||||
|
frappe.throw(_("Row {0}: Both Debit and Credit values cannot be zero").format(d.idx))
|
||||||
|
|
||||||
def validate_total_debit_and_credit(self):
|
def validate_total_debit_and_credit(self):
|
||||||
self.set_total_debit_credit()
|
self.set_total_debit_credit()
|
||||||
if self.difference:
|
if self.difference:
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
cur_frm.set_query("default_account", "accounts", function(doc, cdt, cdn) {
|
frappe.ui.form.on('Mode of Payment', {
|
||||||
var d = locals[cdt][cdn];
|
setup: function(frm) {
|
||||||
return{
|
frm.set_query("default_account", "accounts", function(doc, cdt, cdn) {
|
||||||
filters: [
|
let d = locals[cdt][cdn];
|
||||||
['Account', 'account_type', 'in', 'Bank, Cash, Receivable'],
|
return {
|
||||||
['Account', 'is_group', '=', 0],
|
filters: [
|
||||||
['Account', 'company', '=', d.company]
|
['Account', 'account_type', 'in', 'Bank, Cash, Receivable'],
|
||||||
]
|
['Account', 'is_group', '=', 0],
|
||||||
}
|
['Account', 'company', '=', d.company]
|
||||||
|
]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
});
|
});
|
@ -155,7 +155,8 @@ class OpeningInvoiceCreationTool(Document):
|
|||||||
"posting_date": row.posting_date,
|
"posting_date": row.posting_date,
|
||||||
frappe.scrub(row.party_type): row.party,
|
frappe.scrub(row.party_type): row.party,
|
||||||
"is_pos": 0,
|
"is_pos": 0,
|
||||||
"doctype": "Sales Invoice" if self.invoice_type == "Sales" else "Purchase Invoice"
|
"doctype": "Sales Invoice" if self.invoice_type == "Sales" else "Purchase Invoice",
|
||||||
|
"update_stock": 0
|
||||||
})
|
})
|
||||||
|
|
||||||
accounting_dimension = get_accounting_dimensions()
|
accounting_dimension = get_accounting_dimensions()
|
||||||
|
@ -7,17 +7,24 @@ import frappe
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
test_dependencies = ["Customer", "Supplier"]
|
test_dependencies = ["Customer", "Supplier"]
|
||||||
|
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
|
||||||
from erpnext.accounts.doctype.opening_invoice_creation_tool.opening_invoice_creation_tool import get_temporary_opening_account
|
from erpnext.accounts.doctype.opening_invoice_creation_tool.opening_invoice_creation_tool import get_temporary_opening_account
|
||||||
|
|
||||||
class TestOpeningInvoiceCreationTool(unittest.TestCase):
|
class TestOpeningInvoiceCreationTool(unittest.TestCase):
|
||||||
def make_invoices(self, invoice_type="Sales"):
|
def setUp(self):
|
||||||
|
if not frappe.db.exists("Company", "_Test Opening Invoice Company"):
|
||||||
|
make_company()
|
||||||
|
|
||||||
|
def make_invoices(self, invoice_type="Sales", company=None, party_1=None, party_2=None):
|
||||||
doc = frappe.get_single("Opening Invoice Creation Tool")
|
doc = frappe.get_single("Opening Invoice Creation Tool")
|
||||||
args = get_opening_invoice_creation_dict(invoice_type=invoice_type)
|
args = get_opening_invoice_creation_dict(invoice_type=invoice_type, company=company,
|
||||||
|
party_1=party_1, party_2=party_2)
|
||||||
doc.update(args)
|
doc.update(args)
|
||||||
return doc.make_invoices()
|
return doc.make_invoices()
|
||||||
|
|
||||||
def test_opening_sales_invoice_creation(self):
|
def test_opening_sales_invoice_creation(self):
|
||||||
invoices = self.make_invoices()
|
property_setter = make_property_setter("Sales Invoice", "update_stock", "default", 1, "Check")
|
||||||
|
invoices = self.make_invoices(company="_Test Opening Invoice Company")
|
||||||
|
|
||||||
self.assertEqual(len(invoices), 2)
|
self.assertEqual(len(invoices), 2)
|
||||||
expected_value = {
|
expected_value = {
|
||||||
@ -27,6 +34,13 @@ class TestOpeningInvoiceCreationTool(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
self.check_expected_values(invoices, expected_value)
|
self.check_expected_values(invoices, expected_value)
|
||||||
|
|
||||||
|
si = frappe.get_doc("Sales Invoice", invoices[0])
|
||||||
|
|
||||||
|
# Check if update stock is not enabled
|
||||||
|
self.assertEqual(si.update_stock, 0)
|
||||||
|
|
||||||
|
property_setter.delete()
|
||||||
|
|
||||||
def check_expected_values(self, invoices, expected_value, invoice_type="Sales"):
|
def check_expected_values(self, invoices, expected_value, invoice_type="Sales"):
|
||||||
doctype = "Sales Invoice" if invoice_type == "Sales" else "Purchase Invoice"
|
doctype = "Sales Invoice" if invoice_type == "Sales" else "Purchase Invoice"
|
||||||
|
|
||||||
@ -36,7 +50,7 @@ class TestOpeningInvoiceCreationTool(unittest.TestCase):
|
|||||||
self.assertEqual(si.get(field, ""), expected_value[invoice_idx][field_idx])
|
self.assertEqual(si.get(field, ""), expected_value[invoice_idx][field_idx])
|
||||||
|
|
||||||
def test_opening_purchase_invoice_creation(self):
|
def test_opening_purchase_invoice_creation(self):
|
||||||
invoices = self.make_invoices(invoice_type="Purchase")
|
invoices = self.make_invoices(invoice_type="Purchase", company="_Test Opening Invoice Company")
|
||||||
|
|
||||||
self.assertEqual(len(invoices), 2)
|
self.assertEqual(len(invoices), 2)
|
||||||
expected_value = {
|
expected_value = {
|
||||||
@ -46,6 +60,32 @@ class TestOpeningInvoiceCreationTool(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
self.check_expected_values(invoices, expected_value, "Purchase")
|
self.check_expected_values(invoices, expected_value, "Purchase")
|
||||||
|
|
||||||
|
def test_opening_sales_invoice_creation_with_missing_debit_account(self):
|
||||||
|
company = "_Test Opening Invoice Company"
|
||||||
|
party_1, party_2 = make_customer("Customer A"), make_customer("Customer B")
|
||||||
|
|
||||||
|
old_default_receivable_account = frappe.db.get_value("Company", company, "default_receivable_account")
|
||||||
|
frappe.db.set_value("Company", company, "default_receivable_account", "")
|
||||||
|
|
||||||
|
if not frappe.db.exists("Cost Center", "_Test Opening Invoice Company - _TOIC"):
|
||||||
|
cc = frappe.get_doc({"doctype": "Cost Center", "cost_center_name": "_Test Opening Invoice Company",
|
||||||
|
"is_group": 1, "company": "_Test Opening Invoice Company"})
|
||||||
|
cc.insert(ignore_mandatory=True)
|
||||||
|
cc2 = frappe.get_doc({"doctype": "Cost Center", "cost_center_name": "Main", "is_group": 0,
|
||||||
|
"company": "_Test Opening Invoice Company", "parent_cost_center": cc.name})
|
||||||
|
cc2.insert()
|
||||||
|
|
||||||
|
frappe.db.set_value("Company", company, "cost_center", "Main - _TOIC")
|
||||||
|
|
||||||
|
self.make_invoices(company="_Test Opening Invoice Company", party_1=party_1, party_2=party_2)
|
||||||
|
|
||||||
|
# Check if missing debit account error raised
|
||||||
|
error_log = frappe.db.exists("Error Log", {"error": ["like", "%erpnext.controllers.accounts_controller.AccountMissingError%"]})
|
||||||
|
self.assertTrue(error_log)
|
||||||
|
|
||||||
|
# teardown
|
||||||
|
frappe.db.set_value("Company", company, "default_receivable_account", old_default_receivable_account)
|
||||||
|
|
||||||
def get_opening_invoice_creation_dict(**args):
|
def get_opening_invoice_creation_dict(**args):
|
||||||
party = "Customer" if args.get("invoice_type", "Sales") == "Sales" else "Supplier"
|
party = "Customer" if args.get("invoice_type", "Sales") == "Sales" else "Supplier"
|
||||||
company = args.get("company", "_Test Company")
|
company = args.get("company", "_Test Company")
|
||||||
@ -57,7 +97,7 @@ def get_opening_invoice_creation_dict(**args):
|
|||||||
{
|
{
|
||||||
"qty": 1.0,
|
"qty": 1.0,
|
||||||
"outstanding_amount": 300,
|
"outstanding_amount": 300,
|
||||||
"party": "_Test {0}".format(party),
|
"party": args.get("party_1") or "_Test {0}".format(party),
|
||||||
"item_name": "Opening Item",
|
"item_name": "Opening Item",
|
||||||
"due_date": "2016-09-10",
|
"due_date": "2016-09-10",
|
||||||
"posting_date": "2016-09-05",
|
"posting_date": "2016-09-05",
|
||||||
@ -66,7 +106,7 @@ def get_opening_invoice_creation_dict(**args):
|
|||||||
{
|
{
|
||||||
"qty": 2.0,
|
"qty": 2.0,
|
||||||
"outstanding_amount": 250,
|
"outstanding_amount": 250,
|
||||||
"party": "_Test {0} 1".format(party),
|
"party": args.get("party_2") or "_Test {0} 1".format(party),
|
||||||
"item_name": "Opening Item",
|
"item_name": "Opening Item",
|
||||||
"due_date": "2016-09-10",
|
"due_date": "2016-09-10",
|
||||||
"posting_date": "2016-09-05",
|
"posting_date": "2016-09-05",
|
||||||
@ -77,3 +117,30 @@ def get_opening_invoice_creation_dict(**args):
|
|||||||
|
|
||||||
invoice_dict.update(args)
|
invoice_dict.update(args)
|
||||||
return invoice_dict
|
return invoice_dict
|
||||||
|
|
||||||
|
def make_company():
|
||||||
|
if frappe.db.exists("Company", "_Test Opening Invoice Company"):
|
||||||
|
return frappe.get_doc("Company", "_Test Opening Invoice Company")
|
||||||
|
|
||||||
|
company = frappe.new_doc("Company")
|
||||||
|
company.company_name = "_Test Opening Invoice Company"
|
||||||
|
company.abbr = "_TOIC"
|
||||||
|
company.default_currency = "INR"
|
||||||
|
company.country = "India"
|
||||||
|
company.insert()
|
||||||
|
return company
|
||||||
|
|
||||||
|
def make_customer(customer=None):
|
||||||
|
customer_name = customer or "Opening Customer"
|
||||||
|
customer = frappe.get_doc({
|
||||||
|
"doctype": "Customer",
|
||||||
|
"customer_name": customer_name,
|
||||||
|
"customer_group": "All Customer Groups",
|
||||||
|
"customer_type": "Company",
|
||||||
|
"territory": "All Territories"
|
||||||
|
})
|
||||||
|
if not frappe.db.exists("Customer", customer_name):
|
||||||
|
customer.insert(ignore_permissions=True)
|
||||||
|
return customer.name
|
||||||
|
else:
|
||||||
|
return frappe.db.exists("Customer", customer_name)
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"actions": [],
|
"actions": [],
|
||||||
|
"allow_auto_repeat": 1,
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"creation": "2016-06-01 14:38:51.012597",
|
"creation": "2016-06-01 14:38:51.012597",
|
||||||
@ -587,7 +588,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-09-02 13:39:43.383705",
|
"modified": "2020-10-30 13:56:20.007336",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Payment Entry",
|
"name": "Payment Entry",
|
||||||
|
@ -202,17 +202,32 @@ class PaymentEntry(AccountsController):
|
|||||||
# if account_type not in account_types:
|
# if account_type not in account_types:
|
||||||
# frappe.throw(_("Account Type for {0} must be {1}").format(account, comma_or(account_types)))
|
# frappe.throw(_("Account Type for {0} must be {1}").format(account, comma_or(account_types)))
|
||||||
|
|
||||||
def set_exchange_rate(self):
|
def set_exchange_rate(self, ref_doc=None):
|
||||||
|
self.set_source_exchange_rate(ref_doc)
|
||||||
|
self.set_target_exchange_rate(ref_doc)
|
||||||
|
|
||||||
|
def set_source_exchange_rate(self, ref_doc=None):
|
||||||
if self.paid_from and not self.source_exchange_rate:
|
if self.paid_from and not self.source_exchange_rate:
|
||||||
if self.paid_from_account_currency == self.company_currency:
|
if self.paid_from_account_currency == self.company_currency:
|
||||||
self.source_exchange_rate = 1
|
self.source_exchange_rate = 1
|
||||||
else:
|
else:
|
||||||
self.source_exchange_rate = get_exchange_rate(self.paid_from_account_currency,
|
if ref_doc:
|
||||||
self.company_currency, self.posting_date)
|
if self.paid_from_account_currency == ref_doc.currency:
|
||||||
|
self.source_exchange_rate = ref_doc.get("exchange_rate")
|
||||||
|
|
||||||
|
if not self.source_exchange_rate:
|
||||||
|
self.source_exchange_rate = get_exchange_rate(self.paid_from_account_currency,
|
||||||
|
self.company_currency, self.posting_date)
|
||||||
|
|
||||||
|
def set_target_exchange_rate(self, ref_doc=None):
|
||||||
if self.paid_to and not self.target_exchange_rate:
|
if self.paid_to and not self.target_exchange_rate:
|
||||||
self.target_exchange_rate = get_exchange_rate(self.paid_to_account_currency,
|
if ref_doc:
|
||||||
self.company_currency, self.posting_date)
|
if self.paid_to_account_currency == ref_doc.currency:
|
||||||
|
self.target_exchange_rate = ref_doc.get("exchange_rate")
|
||||||
|
|
||||||
|
if not self.target_exchange_rate:
|
||||||
|
self.target_exchange_rate = get_exchange_rate(self.paid_to_account_currency,
|
||||||
|
self.company_currency, self.posting_date)
|
||||||
|
|
||||||
def validate_mandatory(self):
|
def validate_mandatory(self):
|
||||||
for field in ("paid_amount", "received_amount", "source_exchange_rate", "target_exchange_rate"):
|
for field in ("paid_amount", "received_amount", "source_exchange_rate", "target_exchange_rate"):
|
||||||
@ -282,9 +297,10 @@ class PaymentEntry(AccountsController):
|
|||||||
no_oustanding_refs.setdefault(d.reference_doctype, []).append(d)
|
no_oustanding_refs.setdefault(d.reference_doctype, []).append(d)
|
||||||
|
|
||||||
for k, v in no_oustanding_refs.items():
|
for k, v in no_oustanding_refs.items():
|
||||||
frappe.msgprint(_("{} - {} now have {} as they had no outstanding amount left before submitting the Payment Entry.<br><br>\
|
frappe.msgprint(
|
||||||
If this is undesirable please cancel the corresponding Payment Entry.")
|
_("{} - {} now have {} as they had no outstanding amount left before submitting the Payment Entry.")
|
||||||
.format(k, frappe.bold(", ".join([d.reference_name for d in v])), frappe.bold("negative outstanding amount")),
|
.format(k, frappe.bold(", ".join([d.reference_name for d in v])), frappe.bold("negative outstanding amount"))
|
||||||
|
+ "<br><br>" + _("If this is undesirable please cancel the corresponding Payment Entry."),
|
||||||
title=_("Warning"), indicator="orange")
|
title=_("Warning"), indicator="orange")
|
||||||
|
|
||||||
|
|
||||||
@ -909,22 +925,24 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
|
|||||||
exchange_rate = 1
|
exchange_rate = 1
|
||||||
outstanding_amount = get_outstanding_on_journal_entry(reference_name)
|
outstanding_amount = get_outstanding_on_journal_entry(reference_name)
|
||||||
elif reference_doctype != "Journal Entry":
|
elif reference_doctype != "Journal Entry":
|
||||||
if party_account_currency == company_currency:
|
if ref_doc.doctype == "Expense Claim":
|
||||||
if ref_doc.doctype == "Expense Claim":
|
|
||||||
total_amount = flt(ref_doc.total_sanctioned_amount) + flt(ref_doc.total_taxes_and_charges)
|
total_amount = flt(ref_doc.total_sanctioned_amount) + flt(ref_doc.total_taxes_and_charges)
|
||||||
elif ref_doc.doctype == "Employee Advance":
|
elif ref_doc.doctype == "Employee Advance":
|
||||||
total_amount = ref_doc.advance_amount
|
total_amount = ref_doc.advance_amount
|
||||||
else:
|
exchange_rate = ref_doc.get("exchange_rate")
|
||||||
|
if party_account_currency != ref_doc.currency:
|
||||||
|
total_amount = flt(total_amount) * flt(exchange_rate)
|
||||||
|
if not total_amount:
|
||||||
|
if party_account_currency == company_currency:
|
||||||
total_amount = ref_doc.base_grand_total
|
total_amount = ref_doc.base_grand_total
|
||||||
exchange_rate = 1
|
exchange_rate = 1
|
||||||
else:
|
else:
|
||||||
total_amount = ref_doc.grand_total
|
total_amount = ref_doc.grand_total
|
||||||
|
if not exchange_rate:
|
||||||
# Get the exchange rate from the original ref doc
|
# Get the exchange rate from the original ref doc
|
||||||
# or get it based on the posting date of the ref doc
|
# or get it based on the posting date of the ref doc.
|
||||||
exchange_rate = ref_doc.get("conversion_rate") or \
|
exchange_rate = ref_doc.get("conversion_rate") or \
|
||||||
get_exchange_rate(party_account_currency, company_currency, ref_doc.posting_date)
|
get_exchange_rate(party_account_currency, company_currency, ref_doc.posting_date)
|
||||||
|
|
||||||
if reference_doctype in ("Sales Invoice", "Purchase Invoice"):
|
if reference_doctype in ("Sales Invoice", "Purchase Invoice"):
|
||||||
outstanding_amount = ref_doc.get("outstanding_amount")
|
outstanding_amount = ref_doc.get("outstanding_amount")
|
||||||
bill_no = ref_doc.get("bill_no")
|
bill_no = ref_doc.get("bill_no")
|
||||||
@ -932,11 +950,15 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
|
|||||||
outstanding_amount = flt(ref_doc.get("total_sanctioned_amount")) + flt(ref_doc.get("total_taxes_and_charges"))\
|
outstanding_amount = flt(ref_doc.get("total_sanctioned_amount")) + flt(ref_doc.get("total_taxes_and_charges"))\
|
||||||
- flt(ref_doc.get("total_amount_reimbursed")) - flt(ref_doc.get("total_advance_amount"))
|
- flt(ref_doc.get("total_amount_reimbursed")) - flt(ref_doc.get("total_advance_amount"))
|
||||||
elif reference_doctype == "Employee Advance":
|
elif reference_doctype == "Employee Advance":
|
||||||
outstanding_amount = ref_doc.advance_amount - flt(ref_doc.paid_amount)
|
outstanding_amount = (flt(ref_doc.advance_amount) - flt(ref_doc.paid_amount))
|
||||||
|
if party_account_currency != ref_doc.currency:
|
||||||
|
outstanding_amount = flt(outstanding_amount) * flt(exchange_rate)
|
||||||
|
if party_account_currency == company_currency:
|
||||||
|
exchange_rate = 1
|
||||||
else:
|
else:
|
||||||
outstanding_amount = flt(total_amount) - flt(ref_doc.advance_paid)
|
outstanding_amount = flt(total_amount) - flt(ref_doc.advance_paid)
|
||||||
else:
|
else:
|
||||||
# Get the exchange rate based on the posting date of the ref doc
|
# Get the exchange rate based on the posting date of the ref doc.
|
||||||
exchange_rate = get_exchange_rate(party_account_currency,
|
exchange_rate = get_exchange_rate(party_account_currency,
|
||||||
company_currency, ref_doc.posting_date)
|
company_currency, ref_doc.posting_date)
|
||||||
|
|
||||||
@ -948,102 +970,104 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
|
|||||||
"bill_no": bill_no
|
"bill_no": bill_no
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def get_amounts_based_on_reference_doctype(reference_doctype, ref_doc, party_account_currency, company_currency, reference_name):
|
||||||
|
total_amount, outstanding_amount, exchange_rate = None
|
||||||
|
if reference_doctype == "Fees":
|
||||||
|
total_amount = ref_doc.get("grand_total")
|
||||||
|
exchange_rate = 1
|
||||||
|
outstanding_amount = ref_doc.get("outstanding_amount")
|
||||||
|
elif reference_doctype == "Dunning":
|
||||||
|
total_amount = ref_doc.get("dunning_amount")
|
||||||
|
exchange_rate = 1
|
||||||
|
outstanding_amount = ref_doc.get("dunning_amount")
|
||||||
|
elif reference_doctype == "Journal Entry" and ref_doc.docstatus == 1:
|
||||||
|
total_amount = ref_doc.get("total_amount")
|
||||||
|
if ref_doc.multi_currency:
|
||||||
|
exchange_rate = get_exchange_rate(party_account_currency, company_currency, ref_doc.posting_date)
|
||||||
|
else:
|
||||||
|
exchange_rate = 1
|
||||||
|
outstanding_amount = get_outstanding_on_journal_entry(reference_name)
|
||||||
|
|
||||||
|
return total_amount, outstanding_amount, exchange_rate
|
||||||
|
|
||||||
|
def get_amounts_based_on_ref_doc(reference_doctype, ref_doc, party_account_currency, company_currency):
|
||||||
|
total_amount, outstanding_amount, exchange_rate = None
|
||||||
|
if ref_doc.doctype == "Expense Claim":
|
||||||
|
total_amount = flt(ref_doc.total_sanctioned_amount) + flt(ref_doc.total_taxes_and_charges)
|
||||||
|
elif ref_doc.doctype == "Employee Advance":
|
||||||
|
total_amount, exchange_rate = get_total_amount_exchange_rate_for_employee_advance(party_account_currency, ref_doc)
|
||||||
|
|
||||||
|
if not total_amount:
|
||||||
|
total_amount, exchange_rate = get_total_amount_exchange_rate_base_on_currency(
|
||||||
|
party_account_currency, company_currency, ref_doc)
|
||||||
|
|
||||||
|
if not exchange_rate:
|
||||||
|
# Get the exchange rate from the original ref doc
|
||||||
|
# or get it based on the posting date of the ref doc
|
||||||
|
exchange_rate = ref_doc.get("conversion_rate") or \
|
||||||
|
get_exchange_rate(party_account_currency, company_currency, ref_doc.posting_date)
|
||||||
|
|
||||||
|
outstanding_amount, exchange_rate, bill_no = get_bill_no_and_update_amounts(
|
||||||
|
reference_doctype, ref_doc, total_amount, exchange_rate, party_account_currency, company_currency)
|
||||||
|
|
||||||
|
return total_amount, outstanding_amount, exchange_rate, bill_no
|
||||||
|
|
||||||
|
def get_total_amount_exchange_rate_for_employee_advance(party_account_currency, ref_doc):
|
||||||
|
total_amount = ref_doc.advance_amount
|
||||||
|
exchange_rate = ref_doc.get("exchange_rate")
|
||||||
|
if party_account_currency != ref_doc.currency:
|
||||||
|
total_amount = flt(total_amount) * flt(exchange_rate)
|
||||||
|
|
||||||
|
return total_amount, exchange_rate
|
||||||
|
|
||||||
|
def get_total_amount_exchange_rate_base_on_currency(party_account_currency, company_currency, ref_doc):
|
||||||
|
exchange_rate = None
|
||||||
|
if party_account_currency == company_currency:
|
||||||
|
total_amount = ref_doc.base_grand_total
|
||||||
|
exchange_rate = 1
|
||||||
|
else:
|
||||||
|
total_amount = ref_doc.grand_total
|
||||||
|
|
||||||
|
return total_amount, exchange_rate
|
||||||
|
|
||||||
|
def get_bill_no_and_update_amounts(reference_doctype, ref_doc, total_amount, exchange_rate, party_account_currency, company_currency):
|
||||||
|
outstanding_amount, bill_no = None
|
||||||
|
if reference_doctype in ("Sales Invoice", "Purchase Invoice"):
|
||||||
|
outstanding_amount = ref_doc.get("outstanding_amount")
|
||||||
|
bill_no = ref_doc.get("bill_no")
|
||||||
|
elif reference_doctype == "Expense Claim":
|
||||||
|
outstanding_amount = flt(ref_doc.get("total_sanctioned_amount")) + flt(ref_doc.get("total_taxes_and_charges"))\
|
||||||
|
- flt(ref_doc.get("total_amount_reimbursed")) - flt(ref_doc.get("total_advance_amount"))
|
||||||
|
elif reference_doctype == "Employee Advance":
|
||||||
|
outstanding_amount = (flt(ref_doc.advance_amount) - flt(ref_doc.paid_amount))
|
||||||
|
if party_account_currency != ref_doc.currency:
|
||||||
|
outstanding_amount = flt(outstanding_amount) * flt(exchange_rate)
|
||||||
|
if party_account_currency == company_currency:
|
||||||
|
exchange_rate = 1
|
||||||
|
else:
|
||||||
|
outstanding_amount = flt(total_amount) - flt(ref_doc.advance_paid)
|
||||||
|
|
||||||
|
return outstanding_amount, exchange_rate, bill_no
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=None):
|
def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=None):
|
||||||
|
reference_doc = None
|
||||||
doc = frappe.get_doc(dt, dn)
|
doc = frappe.get_doc(dt, dn)
|
||||||
if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) > 0:
|
if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) > 0:
|
||||||
frappe.throw(_("Can only make payment against unbilled {0}").format(dt))
|
frappe.throw(_("Can only make payment against unbilled {0}").format(dt))
|
||||||
|
|
||||||
if dt in ("Sales Invoice", "Sales Order", "Dunning"):
|
party_type = set_party_type(dt)
|
||||||
party_type = "Customer"
|
party_account = set_party_account(dt, dn, doc, party_type)
|
||||||
elif dt in ("Purchase Invoice", "Purchase Order"):
|
party_account_currency = set_party_account_currency(dt, party_account, doc)
|
||||||
party_type = "Supplier"
|
payment_type = set_payment_type(dt, doc)
|
||||||
elif dt in ("Expense Claim", "Employee Advance"):
|
grand_total, outstanding_amount = set_grand_total_and_outstanding_amount(party_amount, dt, party_account_currency, doc)
|
||||||
party_type = "Employee"
|
|
||||||
elif dt in ("Fees"):
|
|
||||||
party_type = "Student"
|
|
||||||
|
|
||||||
# party account
|
|
||||||
if dt == "Sales Invoice":
|
|
||||||
party_account = get_party_account_based_on_invoice_discounting(dn) or doc.debit_to
|
|
||||||
elif dt == "Purchase Invoice":
|
|
||||||
party_account = doc.credit_to
|
|
||||||
elif dt == "Fees":
|
|
||||||
party_account = doc.receivable_account
|
|
||||||
elif dt == "Employee Advance":
|
|
||||||
party_account = doc.advance_account
|
|
||||||
elif dt == "Expense Claim":
|
|
||||||
party_account = doc.payable_account
|
|
||||||
else:
|
|
||||||
party_account = get_party_account(party_type, doc.get(party_type.lower()), doc.company)
|
|
||||||
|
|
||||||
if dt not in ("Sales Invoice", "Purchase Invoice"):
|
|
||||||
party_account_currency = get_account_currency(party_account)
|
|
||||||
else:
|
|
||||||
party_account_currency = doc.get("party_account_currency") or get_account_currency(party_account)
|
|
||||||
|
|
||||||
# payment type
|
|
||||||
if (dt == "Sales Order" or (dt in ("Sales Invoice", "Fees", "Dunning") and doc.outstanding_amount > 0)) \
|
|
||||||
or (dt=="Purchase Invoice" and doc.outstanding_amount < 0):
|
|
||||||
payment_type = "Receive"
|
|
||||||
else:
|
|
||||||
payment_type = "Pay"
|
|
||||||
|
|
||||||
# amounts
|
|
||||||
grand_total = outstanding_amount = 0
|
|
||||||
if party_amount:
|
|
||||||
grand_total = outstanding_amount = party_amount
|
|
||||||
elif dt in ("Sales Invoice", "Purchase Invoice"):
|
|
||||||
if party_account_currency == doc.company_currency:
|
|
||||||
grand_total = doc.base_rounded_total or doc.base_grand_total
|
|
||||||
else:
|
|
||||||
grand_total = doc.rounded_total or doc.grand_total
|
|
||||||
outstanding_amount = doc.outstanding_amount
|
|
||||||
elif dt in ("Expense Claim"):
|
|
||||||
grand_total = doc.total_sanctioned_amount + doc.total_taxes_and_charges
|
|
||||||
outstanding_amount = doc.grand_total \
|
|
||||||
- doc.total_amount_reimbursed
|
|
||||||
elif dt == "Employee Advance":
|
|
||||||
grand_total = doc.advance_amount
|
|
||||||
outstanding_amount = flt(doc.advance_amount) - flt(doc.paid_amount)
|
|
||||||
elif dt == "Fees":
|
|
||||||
grand_total = doc.grand_total
|
|
||||||
outstanding_amount = doc.outstanding_amount
|
|
||||||
elif dt == "Dunning":
|
|
||||||
grand_total = doc.grand_total
|
|
||||||
outstanding_amount = doc.grand_total
|
|
||||||
else:
|
|
||||||
if party_account_currency == doc.company_currency:
|
|
||||||
grand_total = flt(doc.get("base_rounded_total") or doc.base_grand_total)
|
|
||||||
else:
|
|
||||||
grand_total = flt(doc.get("rounded_total") or doc.grand_total)
|
|
||||||
outstanding_amount = grand_total - flt(doc.advance_paid)
|
|
||||||
|
|
||||||
# bank or cash
|
# bank or cash
|
||||||
bank = get_default_bank_cash_account(doc.company, "Bank", mode_of_payment=doc.get("mode_of_payment"),
|
bank = get_bank_cash_account(doc, bank_account)
|
||||||
account=bank_account)
|
|
||||||
|
|
||||||
if not bank:
|
paid_amount, received_amount = set_paid_amount_and_received_amount(
|
||||||
bank = get_default_bank_cash_account(doc.company, "Cash", mode_of_payment=doc.get("mode_of_payment"),
|
dt, party_account_currency, bank, outstanding_amount, payment_type, bank_amount, doc)
|
||||||
account=bank_account)
|
|
||||||
|
|
||||||
paid_amount = received_amount = 0
|
|
||||||
if party_account_currency == bank.account_currency:
|
|
||||||
paid_amount = received_amount = abs(outstanding_amount)
|
|
||||||
elif payment_type == "Receive":
|
|
||||||
paid_amount = abs(outstanding_amount)
|
|
||||||
if bank_amount:
|
|
||||||
received_amount = bank_amount
|
|
||||||
else:
|
|
||||||
received_amount = paid_amount * doc.get('conversion_rate', 1)
|
|
||||||
else:
|
|
||||||
received_amount = abs(outstanding_amount)
|
|
||||||
if bank_amount:
|
|
||||||
paid_amount = bank_amount
|
|
||||||
else:
|
|
||||||
# if party account currency and bank currency is different then populate paid amount as well
|
|
||||||
paid_amount = received_amount * doc.get('conversion_rate', 1)
|
|
||||||
|
|
||||||
pe = frappe.new_doc("Payment Entry")
|
pe = frappe.new_doc("Payment Entry")
|
||||||
pe.payment_type = payment_type
|
pe.payment_type = payment_type
|
||||||
@ -1115,10 +1139,120 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
|||||||
pe.setup_party_account_field()
|
pe.setup_party_account_field()
|
||||||
pe.set_missing_values()
|
pe.set_missing_values()
|
||||||
if party_account and bank:
|
if party_account and bank:
|
||||||
pe.set_exchange_rate()
|
if dt == "Employee Advance":
|
||||||
|
reference_doc = doc
|
||||||
|
pe.set_exchange_rate(ref_doc=reference_doc)
|
||||||
pe.set_amounts()
|
pe.set_amounts()
|
||||||
return pe
|
return pe
|
||||||
|
|
||||||
|
def get_bank_cash_account(doc, bank_account):
|
||||||
|
bank = get_default_bank_cash_account(doc.company, "Bank", mode_of_payment=doc.get("mode_of_payment"),
|
||||||
|
account=bank_account)
|
||||||
|
|
||||||
|
if not bank:
|
||||||
|
bank = get_default_bank_cash_account(doc.company, "Cash", mode_of_payment=doc.get("mode_of_payment"),
|
||||||
|
account=bank_account)
|
||||||
|
|
||||||
|
return bank
|
||||||
|
|
||||||
|
def set_party_type(dt):
|
||||||
|
if dt in ("Sales Invoice", "Sales Order", "Dunning"):
|
||||||
|
party_type = "Customer"
|
||||||
|
elif dt in ("Purchase Invoice", "Purchase Order"):
|
||||||
|
party_type = "Supplier"
|
||||||
|
elif dt in ("Expense Claim", "Employee Advance"):
|
||||||
|
party_type = "Employee"
|
||||||
|
elif dt in ("Fees"):
|
||||||
|
party_type = "Student"
|
||||||
|
return party_type
|
||||||
|
|
||||||
|
def set_party_account(dt, dn, doc, party_type):
|
||||||
|
if dt == "Sales Invoice":
|
||||||
|
party_account = get_party_account_based_on_invoice_discounting(dn) or doc.debit_to
|
||||||
|
elif dt == "Purchase Invoice":
|
||||||
|
party_account = doc.credit_to
|
||||||
|
elif dt == "Fees":
|
||||||
|
party_account = doc.receivable_account
|
||||||
|
elif dt == "Employee Advance":
|
||||||
|
party_account = doc.advance_account
|
||||||
|
elif dt == "Expense Claim":
|
||||||
|
party_account = doc.payable_account
|
||||||
|
else:
|
||||||
|
party_account = get_party_account(party_type, doc.get(party_type.lower()), doc.company)
|
||||||
|
return party_account
|
||||||
|
|
||||||
|
def set_party_account_currency(dt, party_account, doc):
|
||||||
|
if dt not in ("Sales Invoice", "Purchase Invoice"):
|
||||||
|
party_account_currency = get_account_currency(party_account)
|
||||||
|
else:
|
||||||
|
party_account_currency = doc.get("party_account_currency") or get_account_currency(party_account)
|
||||||
|
return party_account_currency
|
||||||
|
|
||||||
|
def set_payment_type(dt, doc):
|
||||||
|
if (dt == "Sales Order" or (dt in ("Sales Invoice", "Fees", "Dunning") and doc.outstanding_amount > 0)) \
|
||||||
|
or (dt=="Purchase Invoice" and doc.outstanding_amount < 0):
|
||||||
|
payment_type = "Receive"
|
||||||
|
else:
|
||||||
|
payment_type = "Pay"
|
||||||
|
return payment_type
|
||||||
|
|
||||||
|
def set_grand_total_and_outstanding_amount(party_amount, dt, party_account_currency, doc):
|
||||||
|
grand_total = outstanding_amount = 0
|
||||||
|
if party_amount:
|
||||||
|
grand_total = outstanding_amount = party_amount
|
||||||
|
elif dt in ("Sales Invoice", "Purchase Invoice"):
|
||||||
|
if party_account_currency == doc.company_currency:
|
||||||
|
grand_total = doc.base_rounded_total or doc.base_grand_total
|
||||||
|
else:
|
||||||
|
grand_total = doc.rounded_total or doc.grand_total
|
||||||
|
outstanding_amount = doc.outstanding_amount
|
||||||
|
elif dt in ("Expense Claim"):
|
||||||
|
grand_total = doc.total_sanctioned_amount + doc.total_taxes_and_charges
|
||||||
|
outstanding_amount = doc.grand_total \
|
||||||
|
- doc.total_amount_reimbursed
|
||||||
|
elif dt == "Employee Advance":
|
||||||
|
grand_total = flt(doc.advance_amount)
|
||||||
|
outstanding_amount = flt(doc.advance_amount) - flt(doc.paid_amount)
|
||||||
|
if party_account_currency != doc.currency:
|
||||||
|
grand_total = flt(doc.advance_amount) * flt(doc.exchange_rate)
|
||||||
|
outstanding_amount = (flt(doc.advance_amount) - flt(doc.paid_amount)) * flt(doc.exchange_rate)
|
||||||
|
elif dt == "Fees":
|
||||||
|
grand_total = doc.grand_total
|
||||||
|
outstanding_amount = doc.outstanding_amount
|
||||||
|
elif dt == "Dunning":
|
||||||
|
grand_total = doc.grand_total
|
||||||
|
outstanding_amount = doc.grand_total
|
||||||
|
else:
|
||||||
|
if party_account_currency == doc.company_currency:
|
||||||
|
grand_total = flt(doc.get("base_rounded_total") or doc.base_grand_total)
|
||||||
|
else:
|
||||||
|
grand_total = flt(doc.get("rounded_total") or doc.grand_total)
|
||||||
|
outstanding_amount = grand_total - flt(doc.advance_paid)
|
||||||
|
return grand_total, outstanding_amount
|
||||||
|
|
||||||
|
def set_paid_amount_and_received_amount(dt, party_account_currency, bank, outstanding_amount, payment_type, bank_amount, doc):
|
||||||
|
paid_amount = received_amount = 0
|
||||||
|
if party_account_currency == bank.account_currency:
|
||||||
|
paid_amount = received_amount = abs(outstanding_amount)
|
||||||
|
elif payment_type == "Receive":
|
||||||
|
paid_amount = abs(outstanding_amount)
|
||||||
|
if bank_amount:
|
||||||
|
received_amount = bank_amount
|
||||||
|
else:
|
||||||
|
received_amount = paid_amount * doc.get('conversion_rate', 1)
|
||||||
|
if dt == "Employee Advance":
|
||||||
|
received_amount = paid_amount * doc.get('exchange_rate', 1)
|
||||||
|
else:
|
||||||
|
received_amount = abs(outstanding_amount)
|
||||||
|
if bank_amount:
|
||||||
|
paid_amount = bank_amount
|
||||||
|
else:
|
||||||
|
# if party account currency and bank currency is different then populate paid amount as well
|
||||||
|
paid_amount = received_amount * doc.get('conversion_rate', 1)
|
||||||
|
if dt == "Employee Advance":
|
||||||
|
paid_amount = received_amount * doc.get('exchange_rate', 1)
|
||||||
|
return paid_amount, received_amount
|
||||||
|
|
||||||
def get_reference_as_per_payment_terms(payment_schedule, dt, dn, doc, grand_total, outstanding_amount):
|
def get_reference_as_per_payment_terms(payment_schedule, dt, dn, doc, grand_total, outstanding_amount):
|
||||||
references = []
|
references = []
|
||||||
for payment_term in payment_schedule:
|
for payment_term in payment_schedule:
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"actions": [],
|
"actions": [],
|
||||||
|
"allow_auto_repeat": 1,
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"creation": "2020-01-24 15:29:29.933693",
|
"creation": "2020-01-24 15:29:29.933693",
|
||||||
@ -1580,7 +1581,7 @@
|
|||||||
"icon": "fa fa-file-text",
|
"icon": "fa fa-file-text",
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-09-28 16:51:24.641755",
|
"modified": "2020-10-30 13:56:51.056083",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "POS Invoice",
|
"name": "POS Invoice",
|
||||||
|
@ -39,6 +39,7 @@ class POSInvoice(SalesInvoice):
|
|||||||
self.validate_serialised_or_batched_item()
|
self.validate_serialised_or_batched_item()
|
||||||
self.validate_stock_availablility()
|
self.validate_stock_availablility()
|
||||||
self.validate_return_items_qty()
|
self.validate_return_items_qty()
|
||||||
|
self.validate_non_stock_items()
|
||||||
self.set_status()
|
self.set_status()
|
||||||
self.set_account_for_mode_of_payment()
|
self.set_account_for_mode_of_payment()
|
||||||
self.validate_pos()
|
self.validate_pos()
|
||||||
@ -132,15 +133,19 @@ class POSInvoice(SalesInvoice):
|
|||||||
|
|
||||||
msg = ""
|
msg = ""
|
||||||
item_code = frappe.bold(d.item_code)
|
item_code = frappe.bold(d.item_code)
|
||||||
|
serial_nos = get_serial_nos(d.serial_no)
|
||||||
if serialized and batched and (no_batch_selected or no_serial_selected):
|
if serialized and batched and (no_batch_selected or no_serial_selected):
|
||||||
msg = (_('Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.')
|
msg = (_('Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.')
|
||||||
.format(d.idx, item_code))
|
.format(d.idx, item_code))
|
||||||
if serialized and no_serial_selected:
|
elif serialized and no_serial_selected:
|
||||||
msg = (_('Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.')
|
msg = (_('Row #{}: No serial number selected against item: {}. Please select one or remove it to complete transaction.')
|
||||||
.format(d.idx, item_code))
|
.format(d.idx, item_code))
|
||||||
if batched and no_batch_selected:
|
elif batched and no_batch_selected:
|
||||||
msg = (_('Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.')
|
msg = (_('Row #{}: No batch selected against item: {}. Please select a batch or remove it to complete transaction.')
|
||||||
.format(d.idx, item_code))
|
.format(d.idx, item_code))
|
||||||
|
elif serialized and not no_serial_selected and len(serial_nos) != d.qty:
|
||||||
|
msg = (_("Row #{}: You must select {} serial numbers for item {}.").format(d.idx, frappe.bold(cint(d.qty)), item_code))
|
||||||
|
|
||||||
if msg:
|
if msg:
|
||||||
error_msg.append(msg)
|
error_msg.append(msg)
|
||||||
|
|
||||||
@ -171,6 +176,14 @@ class POSInvoice(SalesInvoice):
|
|||||||
.format(d.idx, bold_serial_no, bold_return_against)
|
.format(d.idx, bold_serial_no, bold_return_against)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def validate_non_stock_items(self):
|
||||||
|
for d in self.get("items"):
|
||||||
|
is_stock_item = frappe.get_cached_value("Item", d.get("item_code"), "is_stock_item")
|
||||||
|
if not is_stock_item:
|
||||||
|
frappe.throw(_("Row #{}: Item {} is a non stock item. You can only include stock items in a POS Invoice. ").format(
|
||||||
|
d.idx, frappe.bold(d.item_code)
|
||||||
|
), title=_("Invalid Item"))
|
||||||
|
|
||||||
def validate_mode_of_payment(self):
|
def validate_mode_of_payment(self):
|
||||||
if len(self.payments) == 0:
|
if len(self.payments) == 0:
|
||||||
frappe.throw(_("At least one mode of payment is required for POS invoice."))
|
frappe.throw(_("At least one mode of payment is required for POS invoice."))
|
||||||
|
@ -35,6 +35,15 @@ frappe.ui.form.on('POS Profile', {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
frm.set_query("taxes_and_charges", function() {
|
||||||
|
return {
|
||||||
|
filters: [
|
||||||
|
['Sales Taxes and Charges Template', 'company', '=', frm.doc.company],
|
||||||
|
['Sales Taxes and Charges Template', 'docstatus', '!=', 2]
|
||||||
|
]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
frm.set_query('company_address', function(doc) {
|
frm.set_query('company_address', function(doc) {
|
||||||
if(!doc.company) {
|
if(!doc.company) {
|
||||||
frappe.throw(__('Please set Company'));
|
frappe.throw(__('Please set Company'));
|
||||||
|
@ -70,6 +70,7 @@ def get_items_list(pos_profile, company):
|
|||||||
""".format(cond=cond), tuple([company] + args_list), as_dict=1)
|
""".format(cond=cond), tuple([company] + args_list), as_dict=1)
|
||||||
|
|
||||||
def make_pos_profile(**args):
|
def make_pos_profile(**args):
|
||||||
|
frappe.db.sql("delete from `tabPOS Payment Method`")
|
||||||
frappe.db.sql("delete from `tabPOS Profile`")
|
frappe.db.sql("delete from `tabPOS Profile`")
|
||||||
|
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
@ -42,56 +42,56 @@ frappe.ui.form.on('Pricing Rule', {
|
|||||||
<tr><td>
|
<tr><td>
|
||||||
<h4>
|
<h4>
|
||||||
<i class="fa fa-hand-right"></i>
|
<i class="fa fa-hand-right"></i>
|
||||||
${__('Notes')}
|
{{__('Notes')}}
|
||||||
</h4>
|
</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
${__("Pricing Rule is made to overwrite Price List / define discount percentage, based on some criteria.")}
|
{{__("Pricing Rule is made to overwrite Price List / define discount percentage, based on some criteria.")}}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
${__("If selected Pricing Rule is made for 'Rate', it will overwrite Price List. Pricing Rule rate is the final rate, so no further discount should be applied. Hence, in transactions like Sales Order, Purchase Order etc, it will be fetched in 'Rate' field, rather than 'Price List Rate' field.")}
|
{{__("If selected Pricing Rule is made for 'Rate', it will overwrite Price List. Pricing Rule rate is the final rate, so no further discount should be applied. Hence, in transactions like Sales Order, Purchase Order etc, it will be fetched in 'Rate' field, rather than 'Price List Rate' field.")}}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
${__('Discount Percentage can be applied either against a Price List or for all Price List.')}
|
{{__('Discount Percentage can be applied either against a Price List or for all Price List.')}}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
${__('To not apply Pricing Rule in a particular transaction, all applicable Pricing Rules should be disabled.')}
|
{{__('To not apply Pricing Rule in a particular transaction, all applicable Pricing Rules should be disabled.')}}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
<tr><td>
|
<tr><td>
|
||||||
<h4><i class="fa fa-question-sign"></i>
|
<h4><i class="fa fa-question-sign"></i>
|
||||||
${__('How Pricing Rule is applied?')}
|
{{__('How Pricing Rule is applied?')}}
|
||||||
</h4>
|
</h4>
|
||||||
<ol>
|
<ol>
|
||||||
<li>
|
<li>
|
||||||
${__("Pricing Rule is first selected based on 'Apply On' field, which can be Item, Item Group or Brand.")}
|
{{__("Pricing Rule is first selected based on 'Apply On' field, which can be Item, Item Group or Brand.")}}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
${__("Then Pricing Rules are filtered out based on Customer, Customer Group, Territory, Supplier, Supplier Type, Campaign, Sales Partner etc.")}
|
{{__("Then Pricing Rules are filtered out based on Customer, Customer Group, Territory, Supplier, Supplier Type, Campaign, Sales Partner etc.")}}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
${__('Pricing Rules are further filtered based on quantity.')}
|
{{__('Pricing Rules are further filtered based on quantity.')}}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
${__('If two or more Pricing Rules are found based on the above conditions, Priority is applied. Priority is a number between 0 to 20 while default value is zero (blank). Higher number means it will take precedence if there are multiple Pricing Rules with same conditions.')}
|
{{__('If two or more Pricing Rules are found based on the above conditions, Priority is applied. Priority is a number between 0 to 20 while default value is zero (blank). Higher number means it will take precedence if there are multiple Pricing Rules with same conditions.')}}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
${__('Even if there are multiple Pricing Rules with highest priority, then following internal priorities are applied:')}
|
{{__('Even if there are multiple Pricing Rules with highest priority, then following internal priorities are applied:')}}
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
${__('Item Code > Item Group > Brand')}
|
{{__('Item Code > Item Group > Brand')}}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
${__('Customer > Customer Group > Territory')}
|
{{__('Customer > Customer Group > Territory')}}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
${__('Supplier > Supplier Type')}
|
{{__('Supplier > Supplier Type')}}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
${__('If multiple Pricing Rules continue to prevail, users are asked to set Priority manually to resolve conflict.')}
|
{{__('If multiple Pricing Rules continue to prevail, users are asked to set Priority manually to resolve conflict.')}}
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
|
@ -406,6 +406,7 @@
|
|||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": "0",
|
||||||
"depends_on": "eval:doc.rate_or_discount==\"Rate\"",
|
"depends_on": "eval:doc.rate_or_discount==\"Rate\"",
|
||||||
"fieldname": "rate",
|
"fieldname": "rate",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
@ -469,6 +470,7 @@
|
|||||||
"options": "UOM"
|
"options": "UOM"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"description": "If rate is zero them item will be treated as \"Free Item\"",
|
||||||
"fieldname": "free_item_rate",
|
"fieldname": "free_item_rate",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Rate"
|
"label": "Rate"
|
||||||
@ -563,7 +565,7 @@
|
|||||||
"icon": "fa fa-gift",
|
"icon": "fa fa-gift",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-10-28 16:53:14.416172",
|
"modified": "2020-12-04 00:36:24.698219",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Pricing Rule",
|
"name": "Pricing Rule",
|
||||||
|
@ -352,8 +352,14 @@ def apply_price_discount_rule(pricing_rule, item_details, args):
|
|||||||
pricing_rule_rate = 0.0
|
pricing_rule_rate = 0.0
|
||||||
if pricing_rule.currency == args.currency:
|
if pricing_rule.currency == args.currency:
|
||||||
pricing_rule_rate = pricing_rule.rate
|
pricing_rule_rate = pricing_rule.rate
|
||||||
|
|
||||||
|
if pricing_rule_rate:
|
||||||
|
# Override already set price list rate (from item price)
|
||||||
|
# if pricing_rule_rate > 0
|
||||||
|
item_details.update({
|
||||||
|
"price_list_rate": pricing_rule_rate * args.get("conversion_factor", 1),
|
||||||
|
})
|
||||||
item_details.update({
|
item_details.update({
|
||||||
"price_list_rate": pricing_rule_rate * args.get("conversion_factor", 1),
|
|
||||||
"discount_percentage": 0.0
|
"discount_percentage": 0.0
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -484,6 +484,59 @@ class TestPricingRule(unittest.TestCase):
|
|||||||
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1")
|
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1")
|
||||||
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2")
|
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2")
|
||||||
|
|
||||||
|
def test_item_price_with_pricing_rule(self):
|
||||||
|
item = make_item("Water Flask")
|
||||||
|
make_item_price("Water Flask", "_Test Price List", 100)
|
||||||
|
|
||||||
|
pricing_rule_record = {
|
||||||
|
"doctype": "Pricing Rule",
|
||||||
|
"title": "_Test Water Flask Rule",
|
||||||
|
"apply_on": "Item Code",
|
||||||
|
"items": [{
|
||||||
|
"item_code": "Water Flask",
|
||||||
|
}],
|
||||||
|
"selling": 1,
|
||||||
|
"currency": "INR",
|
||||||
|
"rate_or_discount": "Rate",
|
||||||
|
"rate": 0,
|
||||||
|
"margin_type": "Percentage",
|
||||||
|
"margin_rate_or_amount": 2,
|
||||||
|
"company": "_Test Company"
|
||||||
|
}
|
||||||
|
rule = frappe.get_doc(pricing_rule_record)
|
||||||
|
rule.insert()
|
||||||
|
|
||||||
|
si = create_sales_invoice(do_not_save=True, item_code="Water Flask")
|
||||||
|
si.selling_price_list = "_Test Price List"
|
||||||
|
si.save()
|
||||||
|
|
||||||
|
# If rate in Rule is 0, give preference to Item Price if it exists
|
||||||
|
self.assertEqual(si.items[0].price_list_rate, 100)
|
||||||
|
self.assertEqual(si.items[0].margin_rate_or_amount, 2)
|
||||||
|
self.assertEqual(si.items[0].rate_with_margin, 102)
|
||||||
|
self.assertEqual(si.items[0].rate, 102)
|
||||||
|
|
||||||
|
si.delete()
|
||||||
|
rule.delete()
|
||||||
|
frappe.get_doc("Item Price", {"item_code": "Water Flask"}).delete()
|
||||||
|
item.delete()
|
||||||
|
|
||||||
|
def test_pricing_rule_for_transaction(self):
|
||||||
|
make_item("Water Flask 1")
|
||||||
|
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
|
||||||
|
make_pricing_rule(selling=1, min_qty=5, price_or_product_discount="Product",
|
||||||
|
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)
|
||||||
|
self.assertEquals(len(si.items), 2)
|
||||||
|
self.assertEquals(si.items[1].rate, 10)
|
||||||
|
|
||||||
|
si1 = create_sales_invoice(qty=2, do_not_submit=True)
|
||||||
|
self.assertEquals(len(si1.items), 1)
|
||||||
|
|
||||||
|
for doc in [si, si1]:
|
||||||
|
doc.delete()
|
||||||
|
|
||||||
def make_pricing_rule(**args):
|
def make_pricing_rule(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
|
||||||
@ -502,20 +555,23 @@ def make_pricing_rule(**args):
|
|||||||
"rate_or_discount": args.rate_or_discount or "Discount Percentage",
|
"rate_or_discount": args.rate_or_discount or "Discount Percentage",
|
||||||
"discount_percentage": args.discount_percentage or 0.0,
|
"discount_percentage": args.discount_percentage or 0.0,
|
||||||
"rate": args.rate or 0.0,
|
"rate": args.rate or 0.0,
|
||||||
"margin_type": args.margin_type,
|
|
||||||
"margin_rate_or_amount": args.margin_rate_or_amount or 0.0,
|
"margin_rate_or_amount": args.margin_rate_or_amount or 0.0,
|
||||||
"condition": args.condition or '',
|
"condition": args.condition or '',
|
||||||
"apply_multiple_pricing_rules": args.apply_multiple_pricing_rules or 0
|
"apply_multiple_pricing_rules": args.apply_multiple_pricing_rules or 0
|
||||||
})
|
})
|
||||||
|
|
||||||
if args.get("priority"):
|
for field in ["free_item", "free_qty", "free_item_rate", "priority",
|
||||||
doc.priority = args.get("priority")
|
"margin_type", "price_or_product_discount"]:
|
||||||
|
if args.get(field):
|
||||||
|
doc.set(field, args.get(field))
|
||||||
|
|
||||||
apply_on = doc.apply_on.replace(' ', '_').lower()
|
apply_on = doc.apply_on.replace(' ', '_').lower()
|
||||||
child_table = {'Item Code': 'items', 'Item Group': 'item_groups', 'Brand': 'brands'}
|
child_table = {'Item Code': 'items', 'Item Group': 'item_groups', 'Brand': 'brands'}
|
||||||
doc.append(child_table.get(doc.apply_on), {
|
|
||||||
apply_on: args.get(apply_on) or "_Test Item"
|
if doc.apply_on != "Transaction":
|
||||||
})
|
doc.append(child_table.get(doc.apply_on), {
|
||||||
|
apply_on: args.get(apply_on) or "_Test Item"
|
||||||
|
})
|
||||||
|
|
||||||
doc.insert(ignore_permissions=True)
|
doc.insert(ignore_permissions=True)
|
||||||
if args.get(apply_on) and apply_on != "item_code":
|
if args.get(apply_on) and apply_on != "item_code":
|
||||||
|
@ -457,6 +457,9 @@ def apply_pricing_rule_on_transaction(doc):
|
|||||||
pricing_rules = filter_pricing_rules_for_qty_amount(doc.total_qty,
|
pricing_rules = filter_pricing_rules_for_qty_amount(doc.total_qty,
|
||||||
doc.total, pricing_rules)
|
doc.total, pricing_rules)
|
||||||
|
|
||||||
|
if not pricing_rules:
|
||||||
|
remove_free_item(doc)
|
||||||
|
|
||||||
for d in pricing_rules:
|
for d in pricing_rules:
|
||||||
if d.price_or_product_discount == 'Price':
|
if d.price_or_product_discount == 'Price':
|
||||||
if d.apply_discount_on:
|
if d.apply_discount_on:
|
||||||
@ -480,6 +483,12 @@ def apply_pricing_rule_on_transaction(doc):
|
|||||||
get_product_discount_rule(d, item_details, doc=doc)
|
get_product_discount_rule(d, item_details, doc=doc)
|
||||||
apply_pricing_rule_for_free_items(doc, item_details.free_item_data)
|
apply_pricing_rule_for_free_items(doc, item_details.free_item_data)
|
||||||
doc.set_missing_values()
|
doc.set_missing_values()
|
||||||
|
doc.calculate_taxes_and_totals()
|
||||||
|
|
||||||
|
def remove_free_item(doc):
|
||||||
|
for d in doc.items:
|
||||||
|
if d.is_free_item:
|
||||||
|
doc.remove(d)
|
||||||
|
|
||||||
def get_applied_pricing_rules(pricing_rules):
|
def get_applied_pricing_rules(pricing_rules):
|
||||||
if pricing_rules:
|
if pricing_rules:
|
||||||
@ -492,7 +501,7 @@ def get_applied_pricing_rules(pricing_rules):
|
|||||||
|
|
||||||
def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None):
|
def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None):
|
||||||
free_item = pricing_rule.free_item
|
free_item = pricing_rule.free_item
|
||||||
if pricing_rule.same_item:
|
if pricing_rule.same_item and pricing_rule.get("apply_on") != 'Transaction':
|
||||||
free_item = item_details.item_code or args.item_code
|
free_item = item_details.item_code or args.item_code
|
||||||
|
|
||||||
if not free_item:
|
if not free_item:
|
||||||
|
@ -21,7 +21,7 @@ class TestProcessDeferredAccounting(unittest.TestCase):
|
|||||||
item.no_of_months = 12
|
item.no_of_months = 12
|
||||||
item.save()
|
item.save()
|
||||||
|
|
||||||
si = create_sales_invoice(item=item.name, posting_date="2019-01-10", do_not_submit=True)
|
si = create_sales_invoice(item=item.name, update_stock=0, posting_date="2019-01-10", do_not_submit=True)
|
||||||
si.items[0].enable_deferred_revenue = 1
|
si.items[0].enable_deferred_revenue = 1
|
||||||
si.items[0].service_start_date = "2019-01-10"
|
si.items[0].service_start_date = "2019-01-10"
|
||||||
si.items[0].service_end_date = "2019-03-15"
|
si.items[0].service_end_date = "2019-03-15"
|
||||||
|
@ -99,6 +99,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
|||||||
target: me.frm,
|
target: me.frm,
|
||||||
setters: {
|
setters: {
|
||||||
supplier: me.frm.doc.supplier || undefined,
|
supplier: me.frm.doc.supplier || undefined,
|
||||||
|
schedule_date: undefined
|
||||||
},
|
},
|
||||||
get_query_filters: {
|
get_query_filters: {
|
||||||
docstatus: 1,
|
docstatus: 1,
|
||||||
@ -107,16 +108,16 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
|||||||
company: me.frm.doc.company
|
company: me.frm.doc.company
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, __("Get items from"));
|
}, __("Get Items From"));
|
||||||
|
|
||||||
this.frm.add_custom_button(__('Purchase Receipt'), function() {
|
this.frm.add_custom_button(__('Purchase Receipt'), function() {
|
||||||
erpnext.utils.map_current_doc({
|
erpnext.utils.map_current_doc({
|
||||||
method: "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_purchase_invoice",
|
method: "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_purchase_invoice",
|
||||||
source_doctype: "Purchase Receipt",
|
source_doctype: "Purchase Receipt",
|
||||||
target: me.frm,
|
target: me.frm,
|
||||||
date_field: "posting_date",
|
|
||||||
setters: {
|
setters: {
|
||||||
supplier: me.frm.doc.supplier || undefined,
|
supplier: me.frm.doc.supplier || undefined,
|
||||||
|
posting_date: undefined
|
||||||
},
|
},
|
||||||
get_query_filters: {
|
get_query_filters: {
|
||||||
docstatus: 1,
|
docstatus: 1,
|
||||||
@ -125,7 +126,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
|||||||
is_return: 0
|
is_return: 0
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, __("Get items from"));
|
}, __("Get Items From"));
|
||||||
}
|
}
|
||||||
this.frm.toggle_reqd("supplier_warehouse", this.frm.doc.is_subcontracted==="Yes");
|
this.frm.toggle_reqd("supplier_warehouse", this.frm.doc.is_subcontracted==="Yes");
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"actions": [],
|
"actions": [],
|
||||||
|
"allow_auto_repeat": 1,
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"creation": "2013-05-21 16:16:39",
|
"creation": "2013-05-21 16:16:39",
|
||||||
@ -1334,7 +1335,8 @@
|
|||||||
"icon": "fa fa-file-text",
|
"icon": "fa fa-file-text",
|
||||||
"idx": 204,
|
"idx": 204,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"modified": "2020-09-21 12:22:09.164068",
|
"links": [],
|
||||||
|
"modified": "2020-10-30 13:57:18.266978",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Purchase Invoice",
|
"name": "Purchase Invoice",
|
||||||
|
@ -147,6 +147,11 @@ class PurchaseInvoice(BuyingController):
|
|||||||
throw(_("Conversion rate cannot be 0 or 1"))
|
throw(_("Conversion rate cannot be 0 or 1"))
|
||||||
|
|
||||||
def validate_credit_to_acc(self):
|
def validate_credit_to_acc(self):
|
||||||
|
if not self.credit_to:
|
||||||
|
self.credit_to = get_party_account("Supplier", self.supplier, self.company)
|
||||||
|
if not self.credit_to:
|
||||||
|
self.raise_missing_debit_credit_account_error("Supplier", self.supplier)
|
||||||
|
|
||||||
account = frappe.db.get_value("Account", self.credit_to,
|
account = frappe.db.get_value("Account", self.credit_to,
|
||||||
["account_type", "report_type", "account_currency"], as_dict=True)
|
["account_type", "report_type", "account_currency"], as_dict=True)
|
||||||
|
|
||||||
@ -1032,7 +1037,9 @@ class PurchaseInvoice(BuyingController):
|
|||||||
updated_pr += update_billed_amount_based_on_po(d.po_detail, update_modified)
|
updated_pr += update_billed_amount_based_on_po(d.po_detail, update_modified)
|
||||||
|
|
||||||
for pr in set(updated_pr):
|
for pr in set(updated_pr):
|
||||||
frappe.get_doc("Purchase Receipt", pr).update_billing_percentage(update_modified=update_modified)
|
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_billing_percentage
|
||||||
|
pr_doc = frappe.get_doc("Purchase Receipt", pr)
|
||||||
|
update_billing_percentage(pr_doc, update_modified=update_modified)
|
||||||
|
|
||||||
def on_recurring(self, reference_doc, auto_repeat_doc):
|
def on_recurring(self, reference_doc, auto_repeat_doc):
|
||||||
self.due_date = None
|
self.due_date = None
|
||||||
|
@ -998,7 +998,7 @@ def make_purchase_invoice(**args):
|
|||||||
'expense_account': args.expense_account or '_Test Account Cost for Goods Sold - _TC',
|
'expense_account': args.expense_account or '_Test Account Cost for Goods Sold - _TC',
|
||||||
"conversion_factor": 1.0,
|
"conversion_factor": 1.0,
|
||||||
"serial_no": args.serial_no,
|
"serial_no": args.serial_no,
|
||||||
"stock_uom": "_Test UOM",
|
"stock_uom": args.uom or "_Test UOM",
|
||||||
"cost_center": args.cost_center or "_Test Cost Center - _TC",
|
"cost_center": args.cost_center or "_Test Cost Center - _TC",
|
||||||
"project": args.project,
|
"project": args.project,
|
||||||
"rejected_warehouse": args.rejected_warehouse or "",
|
"rejected_warehouse": args.rejected_warehouse or "",
|
||||||
@ -1040,7 +1040,8 @@ def make_purchase_invoice_against_cost_center(**args):
|
|||||||
pi.is_return = args.is_return
|
pi.is_return = args.is_return
|
||||||
pi.credit_to = args.return_against or "Creditors - _TC"
|
pi.credit_to = args.return_against or "Creditors - _TC"
|
||||||
pi.is_subcontracted = args.is_subcontracted or "No"
|
pi.is_subcontracted = args.is_subcontracted or "No"
|
||||||
pi.supplier_warehouse = "_Test Warehouse 1 - _TC"
|
if args.supplier_warehouse:
|
||||||
|
pi.supplier_warehouse = "_Test Warehouse 1 - _TC"
|
||||||
|
|
||||||
pi.append("items", {
|
pi.append("items", {
|
||||||
"item_code": args.item or args.item_code or "_Test Item",
|
"item_code": args.item or args.item_code or "_Test Item",
|
||||||
|
@ -1,92 +1,38 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 0,
|
|
||||||
"beta": 0,
|
|
||||||
"creation": "2016-07-27 17:24:24.956896",
|
"creation": "2016-07-27 17:24:24.956896",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"company",
|
||||||
|
"account"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "company",
|
"fieldname": "company",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Company",
|
"label": "Company",
|
||||||
"length": 0,
|
"options": "Company"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Company",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"description": "Default Bank / Cash account will be automatically updated in Salary Journal Entry when this mode is selected.",
|
"description": "Default Bank / Cash account will be automatically updated in Salary Journal Entry when this mode is selected.",
|
||||||
"fieldname": "default_account",
|
"fieldname": "account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Default Account",
|
"label": "Account",
|
||||||
"length": 0,
|
"options": "Account"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Account",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"links": [],
|
||||||
"modified": "2016-09-02 07:49:06.567389",
|
"modified": "2020-10-18 17:57:57.110257",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Salary Component Account",
|
"name": "Salary Component Account",
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
"quick_entry": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC"
|
||||||
"track_seen": 0
|
|
||||||
}
|
}
|
@ -199,7 +199,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
|||||||
company: me.frm.doc.company
|
company: me.frm.doc.company
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, __("Get items from"));
|
}, __("Get Items From"));
|
||||||
},
|
},
|
||||||
|
|
||||||
quotation_btn: function() {
|
quotation_btn: function() {
|
||||||
@ -223,7 +223,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
|||||||
company: me.frm.doc.company
|
company: me.frm.doc.company
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, __("Get items from"));
|
}, __("Get Items From"));
|
||||||
},
|
},
|
||||||
|
|
||||||
delivery_note_btn: function() {
|
delivery_note_btn: function() {
|
||||||
@ -251,7 +251,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, __("Get items from"));
|
}, __("Get Items From"));
|
||||||
},
|
},
|
||||||
|
|
||||||
tc_name: function() {
|
tc_name: function() {
|
||||||
@ -812,10 +812,10 @@ frappe.ui.form.on('Sales Invoice', {
|
|||||||
if (cint(frm.doc.docstatus==0) && cur_frm.page.current_view_name!=="pos" && !frm.doc.is_return) {
|
if (cint(frm.doc.docstatus==0) && cur_frm.page.current_view_name!=="pos" && !frm.doc.is_return) {
|
||||||
frm.add_custom_button(__('Healthcare Services'), function() {
|
frm.add_custom_button(__('Healthcare Services'), function() {
|
||||||
get_healthcare_services_to_invoice(frm);
|
get_healthcare_services_to_invoice(frm);
|
||||||
},"Get items from");
|
},"Get Items From");
|
||||||
frm.add_custom_button(__('Prescriptions'), function() {
|
frm.add_custom_button(__('Prescriptions'), function() {
|
||||||
get_drugs_to_invoice(frm);
|
get_drugs_to_invoice(frm);
|
||||||
},"Get items from");
|
},"Get Items From");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"actions": [],
|
"actions": [],
|
||||||
|
"allow_auto_repeat": 1,
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"creation": "2013-05-24 19:29:05",
|
"creation": "2013-05-24 19:29:05",
|
||||||
@ -1955,7 +1956,7 @@
|
|||||||
"idx": 181,
|
"idx": 181,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-10-09 15:59:57.544736",
|
"modified": "2020-10-30 13:57:45.086303",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Invoice",
|
"name": "Sales Invoice",
|
||||||
|
@ -405,6 +405,8 @@ class SalesInvoice(SellingController):
|
|||||||
from erpnext.stock.get_item_details import get_pos_profile_item_details, get_pos_profile
|
from erpnext.stock.get_item_details import get_pos_profile_item_details, get_pos_profile
|
||||||
if not self.pos_profile:
|
if not self.pos_profile:
|
||||||
pos_profile = get_pos_profile(self.company) or {}
|
pos_profile = get_pos_profile(self.company) or {}
|
||||||
|
if not pos_profile:
|
||||||
|
frappe.throw(_("No POS Profile found. Please create a New POS Profile first"))
|
||||||
self.pos_profile = pos_profile.get('name')
|
self.pos_profile = pos_profile.get('name')
|
||||||
|
|
||||||
pos = {}
|
pos = {}
|
||||||
@ -472,6 +474,11 @@ class SalesInvoice(SellingController):
|
|||||||
return frappe.db.sql("select abbr from tabCompany where name=%s", self.company)[0][0]
|
return frappe.db.sql("select abbr from tabCompany where name=%s", self.company)[0][0]
|
||||||
|
|
||||||
def validate_debit_to_acc(self):
|
def validate_debit_to_acc(self):
|
||||||
|
if not self.debit_to:
|
||||||
|
self.debit_to = get_party_account("Customer", self.customer, self.company)
|
||||||
|
if not self.debit_to:
|
||||||
|
self.raise_missing_debit_credit_account_error("Customer", self.customer)
|
||||||
|
|
||||||
account = frappe.get_cached_value("Account", self.debit_to,
|
account = frappe.get_cached_value("Account", self.debit_to,
|
||||||
["account_type", "report_type", "account_currency"], as_dict=True)
|
["account_type", "report_type", "account_currency"], as_dict=True)
|
||||||
|
|
||||||
@ -1401,6 +1408,7 @@ def make_delivery_note(source_name, target_doc=None):
|
|||||||
def set_missing_values(source, target):
|
def set_missing_values(source, target):
|
||||||
target.ignore_pricing_rule = 1
|
target.ignore_pricing_rule = 1
|
||||||
target.run_method("set_missing_values")
|
target.run_method("set_missing_values")
|
||||||
|
target.run_method("set_po_nos")
|
||||||
target.run_method("calculate_taxes_and_totals")
|
target.run_method("calculate_taxes_and_totals")
|
||||||
|
|
||||||
def update_item(source_doc, target_doc, source_parent):
|
def update_item(source_doc, target_doc, source_parent):
|
||||||
|
@ -690,7 +690,8 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
self.assertTrue(gle)
|
self.assertTrue(gle)
|
||||||
|
|
||||||
def test_pos_gl_entry_with_perpetual_inventory(self):
|
def test_pos_gl_entry_with_perpetual_inventory(self):
|
||||||
make_pos_profile()
|
make_pos_profile(company="_Test Company with perpetual inventory", income_account = "Sales - TCP1",
|
||||||
|
expense_account = "Cost of Goods Sold - TCP1", warehouse="Stores - TCP1", cost_center = "Main - TCP1", write_off_account="_Test Write Off - TCP1")
|
||||||
|
|
||||||
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
|
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
|
||||||
|
|
||||||
@ -746,7 +747,8 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
self.assertEqual(pos_return.get('payments')[0].amount, -1000)
|
self.assertEqual(pos_return.get('payments')[0].amount, -1000)
|
||||||
|
|
||||||
def test_pos_change_amount(self):
|
def test_pos_change_amount(self):
|
||||||
make_pos_profile()
|
make_pos_profile(company="_Test Company with perpetual inventory", income_account = "Sales - TCP1",
|
||||||
|
expense_account = "Cost of Goods Sold - TCP1", warehouse="Stores - TCP1", cost_center = "Main - TCP1", write_off_account="_Test Write Off - TCP1")
|
||||||
|
|
||||||
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",
|
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",
|
||||||
item_code= "_Test FG Item",warehouse= "Stores - TCP1", cost_center= "Main - TCP1")
|
item_code= "_Test FG Item",warehouse= "Stores - TCP1", cost_center= "Main - TCP1")
|
||||||
|
@ -140,9 +140,9 @@ def get_tds_amount(suppliers, net_total, company, tax_details, fiscal_year_detai
|
|||||||
else:
|
else:
|
||||||
tds_amount = _get_tds(net_total, tax_details.rate)
|
tds_amount = _get_tds(net_total, tax_details.rate)
|
||||||
else:
|
else:
|
||||||
supplier_credit_amount = frappe.get_all('Purchase Invoice Item',
|
supplier_credit_amount = frappe.get_all('Purchase Invoice',
|
||||||
fields = ['sum(net_amount)'],
|
fields = ['sum(net_total)'],
|
||||||
filters = {'parent': ('in', vouchers), 'docstatus': 1}, as_list=1)
|
filters = {'name': ('in', vouchers), 'docstatus': 1, "apply_tds": 1}, as_list=1)
|
||||||
|
|
||||||
supplier_credit_amount = (supplier_credit_amount[0][0]
|
supplier_credit_amount = (supplier_credit_amount[0][0]
|
||||||
if supplier_credit_amount and supplier_credit_amount[0][0] else 0)
|
if supplier_credit_amount and supplier_credit_amount[0][0] else 0)
|
||||||
|
@ -7,6 +7,7 @@ import frappe
|
|||||||
import unittest
|
import unittest
|
||||||
from frappe.utils import today
|
from frappe.utils import today
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
|
from erpnext.buying.doctype.supplier.test_supplier import create_supplier
|
||||||
|
|
||||||
test_dependencies = ["Supplier Group"]
|
test_dependencies = ["Supplier Group"]
|
||||||
|
|
||||||
@ -101,6 +102,32 @@ class TestTaxWithholdingCategory(unittest.TestCase):
|
|||||||
for d in invoices:
|
for d in invoices:
|
||||||
d.cancel()
|
d.cancel()
|
||||||
|
|
||||||
|
def test_single_threshold_tds_with_previous_vouchers_and_no_tds(self):
|
||||||
|
invoices = []
|
||||||
|
doc = create_supplier(supplier_name = "Test TDS Supplier ABC",
|
||||||
|
tax_withholding_category="Single Threshold TDS")
|
||||||
|
supplier = doc.name
|
||||||
|
|
||||||
|
pi = create_purchase_invoice(supplier=supplier)
|
||||||
|
pi.submit()
|
||||||
|
invoices.append(pi)
|
||||||
|
|
||||||
|
# TDS not applied
|
||||||
|
pi = create_purchase_invoice(supplier=supplier, do_not_apply_tds=True)
|
||||||
|
pi.submit()
|
||||||
|
invoices.append(pi)
|
||||||
|
|
||||||
|
pi = create_purchase_invoice(supplier=supplier)
|
||||||
|
pi.submit()
|
||||||
|
invoices.append(pi)
|
||||||
|
|
||||||
|
self.assertEqual(pi.taxes_and_charges_deducted, 2000)
|
||||||
|
self.assertEqual(pi.grand_total, 8000)
|
||||||
|
|
||||||
|
# delete invoices to avoid clashing
|
||||||
|
for d in invoices:
|
||||||
|
d.cancel()
|
||||||
|
|
||||||
def create_purchase_invoice(**args):
|
def create_purchase_invoice(**args):
|
||||||
# return sales invoice doc object
|
# return sales invoice doc object
|
||||||
item = frappe.get_doc('Item', {'item_name': 'TDS Item'})
|
item = frappe.get_doc('Item', {'item_name': 'TDS Item'})
|
||||||
@ -109,7 +136,7 @@ def create_purchase_invoice(**args):
|
|||||||
pi = frappe.get_doc({
|
pi = frappe.get_doc({
|
||||||
"doctype": "Purchase Invoice",
|
"doctype": "Purchase Invoice",
|
||||||
"posting_date": today(),
|
"posting_date": today(),
|
||||||
"apply_tds": 1,
|
"apply_tds": 0 if args.do_not_apply_tds else 1,
|
||||||
"supplier": args.supplier,
|
"supplier": args.supplier,
|
||||||
"company": '_Test Company',
|
"company": '_Test Company',
|
||||||
"taxes_and_charges": "",
|
"taxes_and_charges": "",
|
||||||
|
@ -156,7 +156,7 @@ erpnext.accounts.bankTransactionUpload = class bankTransactionUpload {
|
|||||||
|
|
||||||
setup_transactions_dom() {
|
setup_transactions_dom() {
|
||||||
const me = this;
|
const me = this;
|
||||||
me.parent.$main_section.append(`<div class="transactions-table"></div>`)
|
me.parent.$main_section.append('<div class="transactions-table"></div>');
|
||||||
}
|
}
|
||||||
|
|
||||||
create_datatable() {
|
create_datatable() {
|
||||||
@ -167,9 +167,7 @@ erpnext.accounts.bankTransactionUpload = class bankTransactionUpload {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
catch(err) {
|
catch(err) {
|
||||||
let msg = __(`Your file could not be processed by ERPNext.
|
let msg = __("Your file could not be processed. It should be a standard CSV or XLSX file with headers in the first row.");
|
||||||
<br>It should be a standard CSV or XLSX file.
|
|
||||||
<br>The headers should be in the first row.`)
|
|
||||||
frappe.throw(msg)
|
frappe.throw(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ def _get_party_details(party=None, account=None, party_type="Customer", company=
|
|||||||
billing_address=party_address, shipping_address=shipping_address)
|
billing_address=party_address, shipping_address=shipping_address)
|
||||||
|
|
||||||
if fetch_payment_terms_template:
|
if fetch_payment_terms_template:
|
||||||
party_details["payment_terms_template"] = get_pyt_term_template(party.name, party_type, company)
|
party_details["payment_terms_template"] = get_payment_terms_template(party.name, party_type, company)
|
||||||
|
|
||||||
if not party_details.get("currency"):
|
if not party_details.get("currency"):
|
||||||
party_details["currency"] = currency
|
party_details["currency"] = currency
|
||||||
@ -315,7 +315,7 @@ def get_due_date(posting_date, party_type, party, company=None, bill_date=None):
|
|||||||
due_date = None
|
due_date = None
|
||||||
if (bill_date or posting_date) and party:
|
if (bill_date or posting_date) and party:
|
||||||
due_date = bill_date or posting_date
|
due_date = bill_date or posting_date
|
||||||
template_name = get_pyt_term_template(party, party_type, company)
|
template_name = get_payment_terms_template(party, party_type, company)
|
||||||
|
|
||||||
if template_name:
|
if template_name:
|
||||||
due_date = get_due_date_from_template(template_name, posting_date, bill_date).strftime("%Y-%m-%d")
|
due_date = get_due_date_from_template(template_name, posting_date, bill_date).strftime("%Y-%m-%d")
|
||||||
@ -422,7 +422,7 @@ def set_taxes(party, party_type, posting_date, company, customer_group=None, sup
|
|||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_pyt_term_template(party_name, party_type, company=None):
|
def get_payment_terms_template(party_name, party_type, company=None):
|
||||||
if party_type not in ("Customer", "Supplier"):
|
if party_type not in ("Customer", "Supplier"):
|
||||||
return
|
return
|
||||||
template = None
|
template = None
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
<table>
|
<table>
|
||||||
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
|
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.format_date(doc.creation) }}</td></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
<table>
|
<table>
|
||||||
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
|
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.format_date(doc.creation) }}</td></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
{{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }}
|
{{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }}
|
||||||
|
|
||||||
{%- for label, value in (
|
{%- for label, value in (
|
||||||
(_("Received On"), frappe.utils.formatdate(doc.voucher_date)),
|
(_("Received On"), frappe.utils.format_date(doc.voucher_date)),
|
||||||
(_("Received From"), doc.pay_to_recd_from),
|
(_("Received From"), doc.pay_to_recd_from),
|
||||||
(_("Amount"), "<strong>" + doc.get_formatted("total_amount") + "</strong><br>" + (doc.total_amount_in_words or "") + "<br>"),
|
(_("Amount"), "<strong>" + doc.get_formatted("total_amount") + "</strong><br>" + (doc.total_amount_in_words or "") + "<br>"),
|
||||||
(_("Remarks"), doc.remark)
|
(_("Remarks"), doc.remark)
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
<table>
|
<table>
|
||||||
<tr><td><strong>Supplier Name: </strong></td><td>{{ doc.supplier }}</td></tr>
|
<tr><td><strong>Supplier Name: </strong></td><td>{{ doc.supplier }}</td></tr>
|
||||||
<tr><td><strong>Due Date: </strong></td><td>{{ frappe.utils.formatdate(doc.due_date) }}</td></tr>
|
<tr><td><strong>Due Date: </strong></td><td>{{ frappe.utils.format_date(doc.due_date) }}</td></tr>
|
||||||
<tr><td><strong>Address: </strong></td><td>{{doc.address_display}}</td></tr>
|
<tr><td><strong>Address: </strong></td><td>{{doc.address_display}}</td></tr>
|
||||||
<tr><td><strong>Contact: </strong></td><td>{{doc.contact_display}}</td></tr>
|
<tr><td><strong>Contact: </strong></td><td>{{doc.contact_display}}</td></tr>
|
||||||
<tr><td><strong>Mobile no: </strong> </td><td>{{doc.contact_mobile}}</td></tr>
|
<tr><td><strong>Mobile no: </strong> </td><td>{{doc.contact_mobile}}</td></tr>
|
||||||
@ -17,7 +17,7 @@
|
|||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
<table>
|
<table>
|
||||||
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
|
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
|
||||||
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
|
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.format_date(doc.creation) }}</td></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
<table>
|
<table>
|
||||||
<tr><td><strong>Customer Name: </strong></td><td>{{ doc.customer }}</td></tr>
|
<tr><td><strong>Customer Name: </strong></td><td>{{ doc.customer }}</td></tr>
|
||||||
<tr><td><strong>Due Date: </strong></td><td>{{ frappe.utils.formatdate(doc.due_date) }}</td></tr>
|
<tr><td><strong>Due Date: </strong></td><td>{{ frappe.utils.format_date(doc.due_date) }}</td></tr>
|
||||||
<tr><td><strong>Address: </strong></td><td>{{doc.address_display}}</td></tr>
|
<tr><td><strong>Address: </strong></td><td>{{doc.address_display}}</td></tr>
|
||||||
<tr><td><strong>Contact: </strong></td><td>{{doc.contact_display}}</td></tr>
|
<tr><td><strong>Contact: </strong></td><td>{{doc.contact_display}}</td></tr>
|
||||||
<tr><td><strong>Mobile no: </strong> </td><td>{{doc.contact_mobile}}</td></tr>
|
<tr><td><strong>Mobile no: </strong> </td><td>{{doc.contact_mobile}}</td></tr>
|
||||||
@ -17,7 +17,7 @@
|
|||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
<table>
|
<table>
|
||||||
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
|
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
|
||||||
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
|
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.format_date(doc.creation) }}</td></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -160,6 +160,8 @@ class ReceivablePayableReport(object):
|
|||||||
else:
|
else:
|
||||||
# advance / unlinked payment or other adjustment
|
# advance / unlinked payment or other adjustment
|
||||||
row.paid -= gle_balance
|
row.paid -= gle_balance
|
||||||
|
if gle.cost_center:
|
||||||
|
row.cost_center = str(gle.cost_center)
|
||||||
|
|
||||||
def update_sub_total_row(self, row, party):
|
def update_sub_total_row(self, row, party):
|
||||||
total_row = self.total_row_map.get(party)
|
total_row = self.total_row_map.get(party)
|
||||||
@ -210,7 +212,6 @@ class ReceivablePayableReport(object):
|
|||||||
for key, row in self.voucher_balance.items():
|
for key, row in self.voucher_balance.items():
|
||||||
row.outstanding = flt(row.invoiced - row.paid - row.credit_note, self.currency_precision)
|
row.outstanding = flt(row.invoiced - row.paid - row.credit_note, self.currency_precision)
|
||||||
row.invoice_grand_total = row.invoiced
|
row.invoice_grand_total = row.invoiced
|
||||||
|
|
||||||
if abs(row.outstanding) > 1.0/10 ** self.currency_precision:
|
if abs(row.outstanding) > 1.0/10 ** self.currency_precision:
|
||||||
# non-zero oustanding, we must consider this row
|
# non-zero oustanding, we must consider this row
|
||||||
|
|
||||||
@ -577,7 +578,7 @@ class ReceivablePayableReport(object):
|
|||||||
|
|
||||||
self.gl_entries = frappe.db.sql("""
|
self.gl_entries = frappe.db.sql("""
|
||||||
select
|
select
|
||||||
name, posting_date, account, party_type, party, voucher_type, voucher_no,
|
name, posting_date, account, party_type, party, voucher_type, voucher_no, cost_center,
|
||||||
against_voucher_type, against_voucher, account_currency, remarks, {0}
|
against_voucher_type, against_voucher, account_currency, remarks, {0}
|
||||||
from
|
from
|
||||||
`tabGL Entry`
|
`tabGL Entry`
|
||||||
@ -741,6 +742,7 @@ class ReceivablePayableReport(object):
|
|||||||
self.add_column(_("Customer Contact"), fieldname='customer_primary_contact',
|
self.add_column(_("Customer Contact"), fieldname='customer_primary_contact',
|
||||||
fieldtype='Link', options='Contact')
|
fieldtype='Link', options='Contact')
|
||||||
|
|
||||||
|
self.add_column(label=_('Cost Center'), fieldname='cost_center', fieldtype='Data')
|
||||||
self.add_column(label=_('Voucher Type'), fieldname='voucher_type', fieldtype='Data')
|
self.add_column(label=_('Voucher Type'), fieldname='voucher_type', fieldtype='Data')
|
||||||
self.add_column(label=_('Voucher No'), fieldname='voucher_no', fieldtype='Dynamic Link',
|
self.add_column(label=_('Voucher No'), fieldname='voucher_no', fieldtype='Dynamic Link',
|
||||||
options='voucher_type', width=180)
|
options='voucher_type', width=180)
|
||||||
|
@ -14,11 +14,93 @@ def execute(filters=None):
|
|||||||
|
|
||||||
def get_column():
|
def get_column():
|
||||||
return [
|
return [
|
||||||
_("Delivery Note") + ":Link/Delivery Note:120", _("Status") + "::120", _("Date") + ":Date:100",
|
{
|
||||||
_("Suplier") + ":Link/Customer:120", _("Customer Name") + "::120",
|
"label": _("Delivery Note"),
|
||||||
_("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120",
|
"fieldname": "name",
|
||||||
_("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Pending Amount") + ":Currency:100",
|
"fieldtype": "Link",
|
||||||
_("Item Name") + "::120", _("Description") + "::120", _("Company") + ":Link/Company:120",
|
"options": "Delivery Note",
|
||||||
|
"width": 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Date"),
|
||||||
|
"fieldname": "date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"width": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Customer"),
|
||||||
|
"fieldname": "customer",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Customer",
|
||||||
|
"width": 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Customer Name"),
|
||||||
|
"fieldname": "customer_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"width": 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Item Code"),
|
||||||
|
"fieldname": "item_code",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Item",
|
||||||
|
"width": 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Amount"),
|
||||||
|
"fieldname": "amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 100,
|
||||||
|
"options": "Company:company:default_currency"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Billed Amount"),
|
||||||
|
"fieldname": "billed_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 100,
|
||||||
|
"options": "Company:company:default_currency"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Returned Amount"),
|
||||||
|
"fieldname": "returned_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 120,
|
||||||
|
"options": "Company:company:default_currency"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Pending Amount"),
|
||||||
|
"fieldname": "pending_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 120,
|
||||||
|
"options": "Company:company:default_currency"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Item Name"),
|
||||||
|
"fieldname": "item_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"width": 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Description"),
|
||||||
|
"fieldname": "description",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"width": 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Project"),
|
||||||
|
"fieldname": "project",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Project",
|
||||||
|
"width": 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Company"),
|
||||||
|
"fieldname": "company",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Company",
|
||||||
|
"width": 120
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_args():
|
def get_args():
|
||||||
|
@ -17,18 +17,26 @@ def get_ordered_to_be_billed_data(args):
|
|||||||
|
|
||||||
return frappe.db.sql("""
|
return frappe.db.sql("""
|
||||||
Select
|
Select
|
||||||
`{parent_tab}`.name, `{parent_tab}`.status, `{parent_tab}`.{date_field}, `{parent_tab}`.{party}, `{parent_tab}`.{party}_name,
|
`{parent_tab}`.name, `{parent_tab}`.{date_field},
|
||||||
{project_field}, `{child_tab}`.item_code, `{child_tab}`.base_amount,
|
`{parent_tab}`.{party}, `{parent_tab}`.{party}_name,
|
||||||
|
`{child_tab}`.item_code,
|
||||||
|
`{child_tab}`.base_amount,
|
||||||
(`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1)),
|
(`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1)),
|
||||||
(`{child_tab}`.base_amount - (`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1))),
|
(`{child_tab}`.base_rate * ifnull(`{child_tab}`.returned_qty, 0)),
|
||||||
`{child_tab}`.item_name, `{child_tab}`.description, `{parent_tab}`.company
|
(`{child_tab}`.base_amount -
|
||||||
|
(`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1)) -
|
||||||
|
(`{child_tab}`.base_rate * ifnull(`{child_tab}`.returned_qty, 0))),
|
||||||
|
`{child_tab}`.item_name, `{child_tab}`.description,
|
||||||
|
{project_field}, `{parent_tab}`.company
|
||||||
from
|
from
|
||||||
`{parent_tab}`, `{child_tab}`
|
`{parent_tab}`, `{child_tab}`
|
||||||
where
|
where
|
||||||
`{parent_tab}`.name = `{child_tab}`.parent and `{parent_tab}`.docstatus = 1
|
`{parent_tab}`.name = `{child_tab}`.parent and `{parent_tab}`.docstatus = 1
|
||||||
and `{parent_tab}`.status not in ('Closed', 'Completed')
|
and `{parent_tab}`.status not in ('Closed', 'Completed')
|
||||||
and `{child_tab}`.amount > 0 and round(`{child_tab}`.billed_amt *
|
and `{child_tab}`.amount > 0
|
||||||
ifnull(`{parent_tab}`.conversion_rate, 1), {precision}) < `{child_tab}`.base_amount
|
and (`{child_tab}`.base_amount -
|
||||||
|
round(`{child_tab}`.billed_amt * ifnull(`{parent_tab}`.conversion_rate, 1), {precision}) -
|
||||||
|
(`{child_tab}`.base_rate * ifnull(`{child_tab}`.returned_qty, 0))) > 0
|
||||||
order by
|
order by
|
||||||
`{parent_tab}`.{order} {order_by}
|
`{parent_tab}`.{order} {order_by}
|
||||||
""".format(parent_tab = 'tab' + doctype, child_tab = 'tab' + child_tab, precision= precision, party = party,
|
""".format(parent_tab = 'tab' + doctype, child_tab = 'tab' + child_tab, precision= precision, party = party,
|
||||||
|
@ -14,11 +14,93 @@ def execute(filters=None):
|
|||||||
|
|
||||||
def get_column():
|
def get_column():
|
||||||
return [
|
return [
|
||||||
_("Purchase Receipt") + ":Link/Purchase Receipt:120", _("Status") + "::120", _("Date") + ":Date:100",
|
{
|
||||||
_("Supplier") + ":Link/Supplier:120", _("Supplier Name") + "::120",
|
"label": _("Purchase Receipt"),
|
||||||
_("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120",
|
"fieldname": "name",
|
||||||
_("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Amount to Bill") + ":Currency:100",
|
"fieldtype": "Link",
|
||||||
_("Item Name") + "::120", _("Description") + "::120", _("Company") + ":Link/Company:120",
|
"options": "Purchase Receipt",
|
||||||
|
"width": 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Date"),
|
||||||
|
"fieldname": "date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"width": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Supplier"),
|
||||||
|
"fieldname": "supplier",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Supplier",
|
||||||
|
"width": 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Supplier Name"),
|
||||||
|
"fieldname": "supplier_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"width": 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Item Code"),
|
||||||
|
"fieldname": "item_code",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Item",
|
||||||
|
"width": 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Amount"),
|
||||||
|
"fieldname": "amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 100,
|
||||||
|
"options": "Company:company:default_currency"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Billed Amount"),
|
||||||
|
"fieldname": "billed_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 100,
|
||||||
|
"options": "Company:company:default_currency"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Returned Amount"),
|
||||||
|
"fieldname": "returned_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 120,
|
||||||
|
"options": "Company:company:default_currency"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Pending Amount"),
|
||||||
|
"fieldname": "pending_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 120,
|
||||||
|
"options": "Company:company:default_currency"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Item Name"),
|
||||||
|
"fieldname": "item_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"width": 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Description"),
|
||||||
|
"fieldname": "description",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"width": 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Project"),
|
||||||
|
"fieldname": "project",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Project",
|
||||||
|
"width": 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Company"),
|
||||||
|
"fieldname": "company",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Company",
|
||||||
|
"width": 120
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_args():
|
def get_args():
|
||||||
|
@ -78,7 +78,10 @@ def get_fiscal_years(transaction_date=None, fiscal_year=None, label="Date", verb
|
|||||||
else:
|
else:
|
||||||
return ((fy.name, fy.year_start_date, fy.year_end_date),)
|
return ((fy.name, fy.year_start_date, fy.year_end_date),)
|
||||||
|
|
||||||
error_msg = _("""{0} {1} not in any active Fiscal Year.""").format(label, formatdate(transaction_date))
|
error_msg = _("""{0} {1} is not in any active Fiscal Year""").format(label, formatdate(transaction_date))
|
||||||
|
if company:
|
||||||
|
error_msg = _("""{0} for {1}""").format(error_msg, frappe.bold(company))
|
||||||
|
|
||||||
if verbose==1: frappe.msgprint(error_msg)
|
if verbose==1: frappe.msgprint(error_msg)
|
||||||
raise FiscalYearError(error_msg)
|
raise FiscalYearError(error_msg)
|
||||||
|
|
||||||
|
@ -373,8 +373,8 @@ frappe.ui.form.on('Asset', {
|
|||||||
doctype_field = frappe.scrub(doctype)
|
doctype_field = frappe.scrub(doctype)
|
||||||
frm.set_value(doctype_field, '');
|
frm.set_value(doctype_field, '');
|
||||||
frappe.msgprint({
|
frappe.msgprint({
|
||||||
title: __(`Invalid ${doctype}`),
|
title: __('Invalid {0}', [__(doctype)]),
|
||||||
message: __(`The selected ${doctype} doesn't contains selected Asset Item.`),
|
message: __('The selected {0} does not contain the selected Asset Item.', [__(doctype)]),
|
||||||
indicator: 'red'
|
indicator: 'red'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -436,7 +436,7 @@ frappe.ui.form.on('Asset Finance Book', {
|
|||||||
depreciation_start_date: function(frm, cdt, cdn) {
|
depreciation_start_date: function(frm, cdt, cdn) {
|
||||||
const book = locals[cdt][cdn];
|
const book = locals[cdt][cdn];
|
||||||
if (frm.doc.available_for_use_date && book.depreciation_start_date == frm.doc.available_for_use_date) {
|
if (frm.doc.available_for_use_date && book.depreciation_start_date == frm.doc.available_for_use_date) {
|
||||||
frappe.msgprint(__(`Depreciation Posting Date should not be equal to Available for Use Date.`));
|
frappe.msgprint(__("Depreciation Posting Date should not be equal to Available for Use Date."));
|
||||||
book.depreciation_start_date = "";
|
book.depreciation_start_date = "";
|
||||||
frm.refresh_field("finance_books");
|
frm.refresh_field("finance_books");
|
||||||
}
|
}
|
||||||
|
@ -50,13 +50,11 @@
|
|||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:parent.doctype == 'Asset'",
|
|
||||||
"fieldname": "depreciation_start_date",
|
"fieldname": "depreciation_start_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Depreciation Posting Date",
|
"label": "Depreciation Posting Date",
|
||||||
"mandatory_depends_on": "eval:parent.doctype == 'Asset'",
|
"mandatory_depends_on": "eval:parent.doctype == 'Asset'"
|
||||||
"reqd": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
@ -87,7 +85,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-10-30 15:22:29.119868",
|
"modified": "2020-11-05 16:30:09.213479",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Assets",
|
"module": "Assets",
|
||||||
"name": "Asset Finance Book",
|
"name": "Asset Finance Book",
|
||||||
|
@ -108,7 +108,7 @@ def update_maintenance_log(asset_maintenance, item_code, item_name, task):
|
|||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
@frappe.validate_and_sanitize_search_inputs
|
@frappe.validate_and_sanitize_search_inputs
|
||||||
def get_team_members(doctype, txt, searchfield, start, page_len, filters):
|
def get_team_members(doctype, txt, searchfield, start, page_len, filters):
|
||||||
return frappe.db.get_values('Maintenance Team Member', { 'parent': filters.get("maintenance_team") })
|
return frappe.db.get_values('Maintenance Team Member', { 'parent': filters.get("maintenance_team") }, "team_member")
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_maintenance_log(asset_name):
|
def get_maintenance_log(asset_name):
|
||||||
|
@ -90,6 +90,11 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
|||||||
this.frm.set_df_property("drop_ship", "hidden", !is_drop_ship);
|
this.frm.set_df_property("drop_ship", "hidden", !is_drop_ship);
|
||||||
|
|
||||||
if(doc.docstatus == 1) {
|
if(doc.docstatus == 1) {
|
||||||
|
this.frm.fields_dict.items_section.wrapper.addClass("hide-border");
|
||||||
|
if(!this.frm.doc.set_warehouse) {
|
||||||
|
this.frm.fields_dict.items_section.wrapper.removeClass("hide-border");
|
||||||
|
}
|
||||||
|
|
||||||
if(!in_list(["Closed", "Delivered"], doc.status)) {
|
if(!in_list(["Closed", "Delivered"], doc.status)) {
|
||||||
if(this.frm.doc.status !== 'Closed' && flt(this.frm.doc.per_received) < 100 && flt(this.frm.doc.per_billed) < 100) {
|
if(this.frm.doc.status !== 'Closed' && flt(this.frm.doc.per_received) < 100 && flt(this.frm.doc.per_billed) < 100) {
|
||||||
this.frm.add_custom_button(__('Update Items'), () => {
|
this.frm.add_custom_button(__('Update Items'), () => {
|
||||||
@ -126,16 +131,25 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
|||||||
if(doc.status != "Closed") {
|
if(doc.status != "Closed") {
|
||||||
if (doc.status != "On Hold") {
|
if (doc.status != "On Hold") {
|
||||||
if(flt(doc.per_received) < 100 && allow_receipt) {
|
if(flt(doc.per_received) < 100 && allow_receipt) {
|
||||||
cur_frm.add_custom_button(__('Receipt'), this.make_purchase_receipt, __('Create'));
|
cur_frm.add_custom_button(__('Purchase Receipt'), this.make_purchase_receipt, __('Create'));
|
||||||
if(doc.is_subcontracted==="Yes" && me.has_unsupplied_items()) {
|
if(doc.is_subcontracted==="Yes" && me.has_unsupplied_items()) {
|
||||||
cur_frm.add_custom_button(__('Material to Supplier'),
|
cur_frm.add_custom_button(__('Material to Supplier'),
|
||||||
function() { me.make_stock_entry(); }, __("Transfer"));
|
function() { me.make_stock_entry(); }, __("Transfer"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(flt(doc.per_billed) < 100)
|
if(flt(doc.per_billed) < 100)
|
||||||
cur_frm.add_custom_button(__('Invoice'),
|
cur_frm.add_custom_button(__('Purchase Invoice'),
|
||||||
this.make_purchase_invoice, __('Create'));
|
this.make_purchase_invoice, __('Create'));
|
||||||
|
|
||||||
|
if(flt(doc.per_billed)==0 && doc.status != "Delivered") {
|
||||||
|
cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_payment_entry, __('Create'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(flt(doc.per_billed)==0) {
|
||||||
|
this.frm.add_custom_button(__('Payment Request'),
|
||||||
|
function() { me.make_payment_request() }, __('Create'));
|
||||||
|
}
|
||||||
|
|
||||||
if(!doc.auto_repeat) {
|
if(!doc.auto_repeat) {
|
||||||
cur_frm.add_custom_button(__('Subscription'), function() {
|
cur_frm.add_custom_button(__('Subscription'), function() {
|
||||||
erpnext.utils.make_subscription(doc.doctype, doc.name)
|
erpnext.utils.make_subscription(doc.doctype, doc.name)
|
||||||
@ -156,13 +170,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(flt(doc.per_billed)==0) {
|
|
||||||
this.frm.add_custom_button(__('Payment Request'),
|
|
||||||
function() { me.make_payment_request() }, __('Create'));
|
|
||||||
}
|
|
||||||
if(flt(doc.per_billed)==0 && doc.status != "Delivered") {
|
|
||||||
cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_payment_entry, __('Create'));
|
|
||||||
}
|
|
||||||
cur_frm.page.set_inner_btn_group_as_primary(__('Create'));
|
cur_frm.page.set_inner_btn_group_as_primary(__('Create'));
|
||||||
}
|
}
|
||||||
} else if(doc.docstatus===0) {
|
} else if(doc.docstatus===0) {
|
||||||
@ -299,7 +307,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
|||||||
if(me.values) {
|
if(me.values) {
|
||||||
me.values.sub_con_rm_items.map((row,i) => {
|
me.values.sub_con_rm_items.map((row,i) => {
|
||||||
if (!row.item_code || !row.rm_item_code || !row.warehouse || !row.qty || row.qty === 0) {
|
if (!row.item_code || !row.rm_item_code || !row.warehouse || !row.qty || row.qty === 0) {
|
||||||
frappe.throw(__("Item Code, warehouse, quantity are required on row" + (i+1)));
|
frappe.throw(__("Item Code, warehouse, quantity are required on row {0}", [i+1]));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
me._make_rm_stock_entry(me.dialog.fields_dict.sub_con_rm_items.grid.get_selected_children())
|
me._make_rm_stock_entry(me.dialog.fields_dict.sub_con_rm_items.grid.get_selected_children())
|
||||||
@ -358,15 +366,19 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
|||||||
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
|
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
|
||||||
source_doctype: "Material Request",
|
source_doctype: "Material Request",
|
||||||
target: me.frm,
|
target: me.frm,
|
||||||
setters: {},
|
setters: {
|
||||||
|
schedule_date: undefined,
|
||||||
|
status: undefined
|
||||||
|
},
|
||||||
get_query_filters: {
|
get_query_filters: {
|
||||||
material_request_type: "Purchase",
|
material_request_type: "Purchase",
|
||||||
docstatus: 1,
|
docstatus: 1,
|
||||||
status: ["!=", "Stopped"],
|
status: ["!=", "Stopped"],
|
||||||
per_ordered: ["<", 99.99],
|
per_ordered: ["<", 99.99],
|
||||||
|
company: me.frm.doc.company
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, __("Get items from"));
|
}, __("Get Items From"));
|
||||||
|
|
||||||
this.frm.add_custom_button(__('Supplier Quotation'),
|
this.frm.add_custom_button(__('Supplier Quotation'),
|
||||||
function() {
|
function() {
|
||||||
@ -375,16 +387,17 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
|||||||
source_doctype: "Supplier Quotation",
|
source_doctype: "Supplier Quotation",
|
||||||
target: me.frm,
|
target: me.frm,
|
||||||
setters: {
|
setters: {
|
||||||
supplier: me.frm.doc.supplier
|
supplier: me.frm.doc.supplier,
|
||||||
|
valid_till: undefined
|
||||||
},
|
},
|
||||||
get_query_filters: {
|
get_query_filters: {
|
||||||
docstatus: 1,
|
docstatus: 1,
|
||||||
status: ["!=", "Stopped"],
|
status: ["not in", ["Stopped", "Expired"]],
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, __("Get items from"));
|
}, __("Get Items From"));
|
||||||
|
|
||||||
this.frm.add_custom_button(__('Update rate as per last purchase'),
|
this.frm.add_custom_button(__('Update Rate as per Last Purchase'),
|
||||||
function() {
|
function() {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
"method": "get_last_purchase_rate",
|
"method": "get_last_purchase_rate",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"actions": [],
|
"actions": [],
|
||||||
|
"allow_auto_repeat": 1,
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"creation": "2013-05-21 16:16:39",
|
"creation": "2013-05-21 16:16:39",
|
||||||
@ -30,8 +31,8 @@
|
|||||||
"customer_contact_email",
|
"customer_contact_email",
|
||||||
"section_addresses",
|
"section_addresses",
|
||||||
"supplier_address",
|
"supplier_address",
|
||||||
"contact_person",
|
|
||||||
"address_display",
|
"address_display",
|
||||||
|
"contact_person",
|
||||||
"contact_display",
|
"contact_display",
|
||||||
"contact_mobile",
|
"contact_mobile",
|
||||||
"contact_email",
|
"contact_email",
|
||||||
@ -49,12 +50,14 @@
|
|||||||
"plc_conversion_rate",
|
"plc_conversion_rate",
|
||||||
"ignore_pricing_rule",
|
"ignore_pricing_rule",
|
||||||
"sec_warehouse",
|
"sec_warehouse",
|
||||||
"set_warehouse",
|
|
||||||
"col_break_warehouse",
|
|
||||||
"is_subcontracted",
|
"is_subcontracted",
|
||||||
|
"col_break_warehouse",
|
||||||
"supplier_warehouse",
|
"supplier_warehouse",
|
||||||
"items_section",
|
"before_items_section",
|
||||||
"scan_barcode",
|
"scan_barcode",
|
||||||
|
"items_col_break",
|
||||||
|
"set_warehouse",
|
||||||
|
"items_section",
|
||||||
"items",
|
"items",
|
||||||
"sb_last_purchase",
|
"sb_last_purchase",
|
||||||
"total_qty",
|
"total_qty",
|
||||||
@ -108,18 +111,13 @@
|
|||||||
"payment_terms_template",
|
"payment_terms_template",
|
||||||
"payment_schedule",
|
"payment_schedule",
|
||||||
"tracking_section",
|
"tracking_section",
|
||||||
"per_billed",
|
"status",
|
||||||
"column_break_75",
|
"column_break_75",
|
||||||
|
"per_billed",
|
||||||
"per_received",
|
"per_received",
|
||||||
"terms_section_break",
|
"terms_section_break",
|
||||||
"tc_name",
|
"tc_name",
|
||||||
"terms",
|
"terms",
|
||||||
"more_info",
|
|
||||||
"status",
|
|
||||||
"ref_sq",
|
|
||||||
"column_break_74",
|
|
||||||
"party_account_currency",
|
|
||||||
"inter_company_order_reference",
|
|
||||||
"column_break5",
|
"column_break5",
|
||||||
"letter_head",
|
"letter_head",
|
||||||
"select_print_heading",
|
"select_print_heading",
|
||||||
@ -131,7 +129,12 @@
|
|||||||
"to_date",
|
"to_date",
|
||||||
"column_break_97",
|
"column_break_97",
|
||||||
"auto_repeat",
|
"auto_repeat",
|
||||||
"update_auto_repeat_reference"
|
"update_auto_repeat_reference",
|
||||||
|
"more_info",
|
||||||
|
"ref_sq",
|
||||||
|
"column_break_74",
|
||||||
|
"party_account_currency",
|
||||||
|
"inter_company_order_reference"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -165,6 +168,7 @@
|
|||||||
"bold": 1,
|
"bold": 1,
|
||||||
"fieldname": "supplier",
|
"fieldname": "supplier",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
|
"in_global_search": 1,
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Supplier",
|
"label": "Supplier",
|
||||||
"oldfieldname": "supplier",
|
"oldfieldname": "supplier",
|
||||||
@ -313,34 +317,34 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "supplier_address",
|
"fieldname": "supplier_address",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Select Supplier Address",
|
"label": "Supplier Address",
|
||||||
"options": "Address",
|
"options": "Address",
|
||||||
"print_hide": 1
|
"print_hide": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "contact_person",
|
"fieldname": "contact_person",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Contact Person",
|
"label": "Supplier Contact",
|
||||||
"options": "Contact",
|
"options": "Contact",
|
||||||
"print_hide": 1
|
"print_hide": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "address_display",
|
"fieldname": "address_display",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"label": "Address",
|
"label": "Supplier Address Details",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "contact_display",
|
"fieldname": "contact_display",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"in_global_search": 1,
|
"in_global_search": 1,
|
||||||
"label": "Contact",
|
"label": "Contact Name",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "contact_mobile",
|
"fieldname": "contact_mobile",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"label": "Mobile No",
|
"label": "Contact Mobile No",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -358,14 +362,14 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "shipping_address",
|
"fieldname": "shipping_address",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Select Shipping Address",
|
"label": "Company Shipping Address",
|
||||||
"options": "Address",
|
"options": "Address",
|
||||||
"print_hide": 1
|
"print_hide": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "shipping_address_display",
|
"fieldname": "shipping_address_display",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"label": "Shipping Address",
|
"label": "Shipping Address Details",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
@ -433,7 +437,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "sec_warehouse",
|
"fieldname": "sec_warehouse",
|
||||||
"fieldtype": "Section Break"
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Subcontracting"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Sets 'Warehouse' in each row of the Items table.",
|
"description": "Sets 'Warehouse' in each row of the Items table.",
|
||||||
@ -466,6 +471,7 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "items_section",
|
"fieldname": "items_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
|
"hide_border": 1,
|
||||||
"oldfieldtype": "Section Break",
|
"oldfieldtype": "Section Break",
|
||||||
"options": "fa fa-shopping-cart"
|
"options": "fa fa-shopping-cart"
|
||||||
},
|
},
|
||||||
@ -598,7 +604,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "section_break_52",
|
"fieldname": "section_break_52",
|
||||||
"fieldtype": "Section Break"
|
"fieldtype": "Section Break",
|
||||||
|
"hide_border": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "taxes",
|
"fieldname": "taxes",
|
||||||
@ -626,10 +633,12 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "totals",
|
"fieldname": "totals",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Taxes and Charges",
|
||||||
"oldfieldtype": "Section Break",
|
"oldfieldtype": "Section Break",
|
||||||
"options": "fa fa-money"
|
"options": "fa fa-money"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"depends_on": "base_taxes_and_charges_added",
|
||||||
"fieldname": "base_taxes_and_charges_added",
|
"fieldname": "base_taxes_and_charges_added",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Taxes and Charges Added (Company Currency)",
|
"label": "Taxes and Charges Added (Company Currency)",
|
||||||
@ -640,6 +649,7 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"depends_on": "base_taxes_and_charges_deducted",
|
||||||
"fieldname": "base_taxes_and_charges_deducted",
|
"fieldname": "base_taxes_and_charges_deducted",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Taxes and Charges Deducted (Company Currency)",
|
"label": "Taxes and Charges Deducted (Company Currency)",
|
||||||
@ -650,6 +660,7 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"depends_on": "base_total_taxes_and_charges",
|
||||||
"fieldname": "base_total_taxes_and_charges",
|
"fieldname": "base_total_taxes_and_charges",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Total Taxes and Charges (Company Currency)",
|
"label": "Total Taxes and Charges (Company Currency)",
|
||||||
@ -665,6 +676,7 @@
|
|||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"depends_on": "taxes_and_charges_added",
|
||||||
"fieldname": "taxes_and_charges_added",
|
"fieldname": "taxes_and_charges_added",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Taxes and Charges Added",
|
"label": "Taxes and Charges Added",
|
||||||
@ -675,6 +687,7 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"depends_on": "taxes_and_charges_deducted",
|
||||||
"fieldname": "taxes_and_charges_deducted",
|
"fieldname": "taxes_and_charges_deducted",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Taxes and Charges Deducted",
|
"label": "Taxes and Charges Deducted",
|
||||||
@ -685,6 +698,7 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"depends_on": "total_taxes_and_charges",
|
||||||
"fieldname": "total_taxes_and_charges",
|
"fieldname": "total_taxes_and_charges",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Total Taxes and Charges",
|
"label": "Total Taxes and Charges",
|
||||||
@ -694,7 +708,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"collapsible_depends_on": "discount_amount",
|
"collapsible_depends_on": "apply_discount_on",
|
||||||
"fieldname": "discount_section",
|
"fieldname": "discount_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Additional Discount"
|
"label": "Additional Discount"
|
||||||
@ -734,7 +748,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "totals_section",
|
"fieldname": "totals_section",
|
||||||
"fieldtype": "Section Break"
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Totals"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "base_grand_total",
|
"fieldname": "base_grand_total",
|
||||||
@ -902,12 +917,12 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "ref_sq",
|
"fieldname": "ref_sq",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Link",
|
||||||
"hidden": 1,
|
"label": "Supplier Quotation",
|
||||||
"label": "Ref SQ",
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "ref_sq",
|
"oldfieldname": "ref_sq",
|
||||||
"oldfieldtype": "Data",
|
"oldfieldtype": "Data",
|
||||||
|
"options": "Supplier Quotation",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
@ -1061,7 +1076,7 @@
|
|||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"fieldname": "tracking_section",
|
"fieldname": "tracking_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Tracking"
|
"label": "Order Status"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_75",
|
"fieldname": "column_break_75",
|
||||||
@ -1070,21 +1085,29 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "billing_address",
|
"fieldname": "billing_address",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Select Billing Address",
|
"label": "Company Billing Address",
|
||||||
"options": "Address"
|
"options": "Address"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "billing_address_display",
|
"fieldname": "billing_address_display",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"label": "Billing Address",
|
"label": "Billing Address Details",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "before_items_section",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "items_col_break",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-file-text",
|
"icon": "fa fa-file-text",
|
||||||
"idx": 105,
|
"idx": 105,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-10-07 14:31:57.661221",
|
"modified": "2020-12-03 16:46:44.229351",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Purchase Order",
|
"name": "Purchase Order",
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
"col_break2",
|
"col_break2",
|
||||||
"uom",
|
"uom",
|
||||||
"conversion_factor",
|
"conversion_factor",
|
||||||
|
"stock_qty",
|
||||||
"sec_break1",
|
"sec_break1",
|
||||||
"price_list_rate",
|
"price_list_rate",
|
||||||
"discount_percentage",
|
"discount_percentage",
|
||||||
@ -46,11 +47,8 @@
|
|||||||
"column_break_32",
|
"column_break_32",
|
||||||
"base_net_rate",
|
"base_net_rate",
|
||||||
"base_net_amount",
|
"base_net_amount",
|
||||||
"billed_amt",
|
|
||||||
"warehouse_and_reference",
|
"warehouse_and_reference",
|
||||||
"warehouse",
|
"warehouse",
|
||||||
"delivered_by_supplier",
|
|
||||||
"project",
|
|
||||||
"material_request",
|
"material_request",
|
||||||
"material_request_item",
|
"material_request_item",
|
||||||
"sales_order",
|
"sales_order",
|
||||||
@ -58,36 +56,37 @@
|
|||||||
"supplier_quotation",
|
"supplier_quotation",
|
||||||
"supplier_quotation_item",
|
"supplier_quotation_item",
|
||||||
"col_break5",
|
"col_break5",
|
||||||
|
"delivered_by_supplier",
|
||||||
"against_blanket_order",
|
"against_blanket_order",
|
||||||
"blanket_order",
|
"blanket_order",
|
||||||
"blanket_order_rate",
|
"blanket_order_rate",
|
||||||
"item_group",
|
"item_group",
|
||||||
"brand",
|
"brand",
|
||||||
"bom",
|
|
||||||
"include_exploded_items",
|
|
||||||
"section_break_56",
|
"section_break_56",
|
||||||
"stock_qty",
|
|
||||||
"column_break_60",
|
|
||||||
"received_qty",
|
"received_qty",
|
||||||
"returned_qty",
|
"returned_qty",
|
||||||
"manufacture_details",
|
"column_break_60",
|
||||||
"manufacturer",
|
"billed_amt",
|
||||||
"column_break_14",
|
|
||||||
"manufacturer_part_no",
|
|
||||||
"more_info_section_break",
|
|
||||||
"is_fixed_asset",
|
|
||||||
"item_tax_rate",
|
|
||||||
"accounting_details",
|
"accounting_details",
|
||||||
"expense_account",
|
"expense_account",
|
||||||
"column_break_68",
|
"manufacture_details",
|
||||||
|
"manufacturer",
|
||||||
|
"manufacturer_part_no",
|
||||||
|
"column_break_14",
|
||||||
|
"bom",
|
||||||
|
"include_exploded_items",
|
||||||
"item_weight_details",
|
"item_weight_details",
|
||||||
"weight_per_unit",
|
"weight_per_unit",
|
||||||
"total_weight",
|
"total_weight",
|
||||||
"column_break_40",
|
"column_break_40",
|
||||||
"weight_uom",
|
"weight_uom",
|
||||||
"accounting_dimensions_section",
|
"accounting_dimensions_section",
|
||||||
"cost_center",
|
"project",
|
||||||
"dimension_col_break",
|
"dimension_col_break",
|
||||||
|
"cost_center",
|
||||||
|
"more_info_section_break",
|
||||||
|
"is_fixed_asset",
|
||||||
|
"item_tax_rate",
|
||||||
"section_break_72",
|
"section_break_72",
|
||||||
"page_break"
|
"page_break"
|
||||||
],
|
],
|
||||||
@ -346,6 +345,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
|
"depends_on": "is_free_item",
|
||||||
"fieldname": "is_free_item",
|
"fieldname": "is_free_item",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Is Free Item",
|
"label": "Is Free Item",
|
||||||
@ -508,9 +508,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
|
"depends_on": "delivered_by_supplier",
|
||||||
"fieldname": "delivered_by_supplier",
|
"fieldname": "delivered_by_supplier",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "To be delivered to customer",
|
"label": "To be Delivered to Customer",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
@ -558,6 +559,7 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"depends_on": "eval:parent.is_subcontracted == 'Yes'",
|
||||||
"fieldname": "bom",
|
"fieldname": "bom",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "BOM",
|
"label": "BOM",
|
||||||
@ -574,21 +576,21 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "section_break_56",
|
"fieldname": "section_break_56",
|
||||||
"fieldtype": "Section Break"
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Billed, Received & Returned"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "stock_qty",
|
"fieldname": "stock_qty",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"label": "Qty as per Stock UOM",
|
"label": "Qty in Stock UOM",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "stock_qty",
|
|
||||||
"oldfieldtype": "Currency",
|
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_width": "100px",
|
"print_width": "100px",
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
"width": "100px"
|
"width": "100px"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"depends_on": "received_qty",
|
||||||
"fieldname": "received_qty",
|
"fieldname": "received_qty",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"label": "Received Qty",
|
"label": "Received Qty",
|
||||||
@ -612,9 +614,10 @@
|
|||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"depends_on": "billed_amt",
|
||||||
"fieldname": "billed_amt",
|
"fieldname": "billed_amt",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Billed Amt",
|
"label": "Billed Amount",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "currency",
|
"options": "currency",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
@ -633,6 +636,7 @@
|
|||||||
"report_hide": 1
|
"report_hide": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"collapsible": 1,
|
||||||
"fieldname": "accounting_details",
|
"fieldname": "accounting_details",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Accounting Details"
|
"label": "Accounting Details"
|
||||||
@ -644,10 +648,6 @@
|
|||||||
"options": "Account",
|
"options": "Account",
|
||||||
"print_hide": 1
|
"print_hide": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "column_break_68",
|
|
||||||
"fieldtype": "Column Break"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "cost_center",
|
"fieldname": "cost_center",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
@ -715,6 +715,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
|
"depends_on": "is_fixed_asset",
|
||||||
"fetch_from": "item_code.is_fixed_asset",
|
"fetch_from": "item_code.is_fixed_asset",
|
||||||
"fieldname": "is_fixed_asset",
|
"fieldname": "is_fixed_asset",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
@ -728,9 +729,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-04-21 11:55:58.643393",
|
"modified": "2020-10-30 11:59:47.670951",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Purchase Order Item",
|
"name": "Purchase Order Item",
|
||||||
|
@ -217,13 +217,15 @@ erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.e
|
|||||||
source_doctype: "Material Request",
|
source_doctype: "Material Request",
|
||||||
target: me.frm,
|
target: me.frm,
|
||||||
setters: {
|
setters: {
|
||||||
company: me.frm.doc.company
|
schedule_date: undefined,
|
||||||
|
status: undefined
|
||||||
},
|
},
|
||||||
get_query_filters: {
|
get_query_filters: {
|
||||||
material_request_type: "Purchase",
|
material_request_type: "Purchase",
|
||||||
docstatus: 1,
|
docstatus: 1,
|
||||||
status: ["!=", "Stopped"],
|
status: ["!=", "Stopped"],
|
||||||
per_ordered: ["<", 99.99]
|
per_ordered: ["<", 99.99],
|
||||||
|
company: me.frm.doc.company
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, __("Get Items From"));
|
}, __("Get Items From"));
|
||||||
@ -236,32 +238,40 @@ erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.e
|
|||||||
source_doctype: "Opportunity",
|
source_doctype: "Opportunity",
|
||||||
target: me.frm,
|
target: me.frm,
|
||||||
setters: {
|
setters: {
|
||||||
company: me.frm.doc.company
|
party_name: undefined,
|
||||||
|
opportunity_from: undefined,
|
||||||
|
status: undefined
|
||||||
},
|
},
|
||||||
|
get_query_filters: {
|
||||||
|
status: ["not in", ["Closed", "Lost"]],
|
||||||
|
company: me.frm.doc.company
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}, __("Get Items From"));
|
}, __("Get Items From"));
|
||||||
|
|
||||||
// Get items from open Material Requests based on supplier
|
// Get items from open Material Requests based on supplier
|
||||||
this.frm.add_custom_button(__('Possible Supplier'), function() {
|
this.frm.add_custom_button(__('Possible Supplier'), function() {
|
||||||
// Create a dialog window for the user to pick their supplier
|
// Create a dialog window for the user to pick their supplier
|
||||||
var d = new frappe.ui.Dialog({
|
var dialog = new frappe.ui.Dialog({
|
||||||
title: __('Select Possible Supplier'),
|
title: __('Select Possible Supplier'),
|
||||||
fields: [
|
fields: [
|
||||||
{fieldname: 'supplier', fieldtype:'Link', options:'Supplier', label:'Supplier', reqd:1},
|
{
|
||||||
{fieldname: 'ok_button', fieldtype:'Button', label:'Get Items from Material Requests'},
|
fieldname: 'supplier',
|
||||||
]
|
fieldtype:'Link',
|
||||||
});
|
options:'Supplier',
|
||||||
|
label:'Supplier',
|
||||||
// On the user clicking the ok button
|
reqd:1,
|
||||||
d.fields_dict.ok_button.input.onclick = function() {
|
description: __("Get Items from Material Requests against this Supplier")
|
||||||
var btn = d.fields_dict.ok_button.input;
|
}
|
||||||
var v = d.get_values();
|
],
|
||||||
if(v) {
|
primary_action_label: __("Get Items"),
|
||||||
$(btn).set_working();
|
primary_action: (args) => {
|
||||||
|
if(!args) return;
|
||||||
|
dialog.hide();
|
||||||
|
|
||||||
erpnext.utils.map_current_doc({
|
erpnext.utils.map_current_doc({
|
||||||
method: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.get_item_from_material_requests_based_on_supplier",
|
method: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.get_item_from_material_requests_based_on_supplier",
|
||||||
source_name: v.supplier,
|
source_name: args.supplier,
|
||||||
target: me.frm,
|
target: me.frm,
|
||||||
setters: {
|
setters: {
|
||||||
company: me.frm.doc.company
|
company: me.frm.doc.company
|
||||||
@ -273,18 +283,24 @@ erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.e
|
|||||||
per_ordered: ["<", 99.99]
|
per_ordered: ["<", 99.99]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$(btn).done_working();
|
dialog.hide();
|
||||||
d.hide();
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
d.show();
|
|
||||||
|
dialog.show();
|
||||||
}, __("Get Items From"));
|
}, __("Get Items From"));
|
||||||
|
|
||||||
|
// Link Material Requests
|
||||||
|
this.frm.add_custom_button(__('Link to Material Requests'),
|
||||||
|
function() {
|
||||||
|
erpnext.buying.link_to_mrs(me.frm);
|
||||||
|
}, __("Tools"));
|
||||||
|
|
||||||
// Get Suppliers
|
// Get Suppliers
|
||||||
this.frm.add_custom_button(__('Get Suppliers'),
|
this.frm.add_custom_button(__('Get Suppliers'),
|
||||||
function() {
|
function() {
|
||||||
me.get_suppliers_button(me.frm);
|
me.get_suppliers_button(me.frm);
|
||||||
});
|
}, __("Tools"));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -304,7 +320,7 @@ erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.e
|
|||||||
{
|
{
|
||||||
"fieldtype": "Select", "label": __("Get Suppliers By"),
|
"fieldtype": "Select", "label": __("Get Suppliers By"),
|
||||||
"fieldname": "search_type",
|
"fieldname": "search_type",
|
||||||
"options": ["Tag","Supplier Group"],
|
"options": ["Supplier Group", "Tag"],
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
onchange() {
|
onchange() {
|
||||||
if(dialog.get_value('search_type') == 'Tag'){
|
if(dialog.get_value('search_type') == 'Tag'){
|
||||||
|
@ -18,12 +18,11 @@
|
|||||||
"suppliers",
|
"suppliers",
|
||||||
"items_section",
|
"items_section",
|
||||||
"items",
|
"items",
|
||||||
"link_to_mrs",
|
|
||||||
"supplier_response_section",
|
"supplier_response_section",
|
||||||
"salutation",
|
"salutation",
|
||||||
"email_template",
|
|
||||||
"col_break_email_1",
|
|
||||||
"subject",
|
"subject",
|
||||||
|
"col_break_email_1",
|
||||||
|
"email_template",
|
||||||
"preview",
|
"preview",
|
||||||
"sec_break_email_2",
|
"sec_break_email_2",
|
||||||
"message_for_supplier",
|
"message_for_supplier",
|
||||||
@ -118,13 +117,6 @@
|
|||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:doc.docstatus===0 && (doc.items && doc.items.length)",
|
|
||||||
"fieldname": "link_to_mrs",
|
|
||||||
"fieldtype": "Button",
|
|
||||||
"label": "Link to Material Requests"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"depends_on": "eval:!doc.__islocal",
|
|
||||||
"fieldname": "supplier_response_section",
|
"fieldname": "supplier_response_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Email Details"
|
"label": "Email Details"
|
||||||
@ -260,7 +252,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-10-16 17:49:09.561929",
|
"modified": "2020-11-05 22:04:29.017134",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Request for Quotation",
|
"name": "Request for Quotation",
|
||||||
|
@ -5,14 +5,14 @@
|
|||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"send_email",
|
|
||||||
"email_sent",
|
|
||||||
"supplier",
|
"supplier",
|
||||||
"contact",
|
"contact",
|
||||||
"quote_status",
|
"quote_status",
|
||||||
"column_break_3",
|
"column_break_3",
|
||||||
"supplier_name",
|
"supplier_name",
|
||||||
"email_id"
|
"email_id",
|
||||||
|
"send_email",
|
||||||
|
"email_sent"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -87,7 +87,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-10-16 12:23:41.769820",
|
"modified": "2020-11-04 22:01:43.832942",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Request for Quotation Supplier",
|
"name": "Request for Quotation Supplier",
|
||||||
|
@ -120,3 +120,20 @@ class TestSupplier(unittest.TestCase):
|
|||||||
|
|
||||||
# Rollback
|
# Rollback
|
||||||
address.delete()
|
address.delete()
|
||||||
|
|
||||||
|
def create_supplier(**args):
|
||||||
|
args = frappe._dict(args)
|
||||||
|
|
||||||
|
try:
|
||||||
|
doc = frappe.get_doc({
|
||||||
|
"doctype": "Supplier",
|
||||||
|
"supplier_name": args.supplier_name,
|
||||||
|
"supplier_group": args.supplier_group or "Services",
|
||||||
|
"supplier_type": args.supplier_type or "Company",
|
||||||
|
"tax_withholding_category": args.tax_withholding_category
|
||||||
|
}).insert()
|
||||||
|
|
||||||
|
return doc
|
||||||
|
|
||||||
|
except frappe.DuplicateEntryError:
|
||||||
|
return frappe.get_doc("Supplier", args.supplier_name)
|
@ -37,16 +37,24 @@ erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.ext
|
|||||||
source_doctype: "Material Request",
|
source_doctype: "Material Request",
|
||||||
target: me.frm,
|
target: me.frm,
|
||||||
setters: {
|
setters: {
|
||||||
company: me.frm.doc.company
|
schedule_date: undefined,
|
||||||
|
status: undefined
|
||||||
},
|
},
|
||||||
get_query_filters: {
|
get_query_filters: {
|
||||||
material_request_type: "Purchase",
|
material_request_type: "Purchase",
|
||||||
docstatus: 1,
|
docstatus: 1,
|
||||||
status: ["!=", "Stopped"],
|
status: ["!=", "Stopped"],
|
||||||
per_ordered: ["<", 99.99]
|
per_ordered: ["<", 99.99],
|
||||||
|
company: me.frm.doc.company
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, __("Get items from"));
|
}, __("Get Items From"));
|
||||||
|
|
||||||
|
// Link Material Requests
|
||||||
|
this.frm.add_custom_button(__('Link to Material Requests'),
|
||||||
|
function() {
|
||||||
|
erpnext.buying.link_to_mrs(me.frm);
|
||||||
|
}, __("Tools"));
|
||||||
|
|
||||||
this.frm.add_custom_button(__("Request for Quotation"),
|
this.frm.add_custom_button(__("Request for Quotation"),
|
||||||
function() {
|
function() {
|
||||||
@ -58,16 +66,16 @@ erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.ext
|
|||||||
source_doctype: "Request for Quotation",
|
source_doctype: "Request for Quotation",
|
||||||
target: me.frm,
|
target: me.frm,
|
||||||
setters: {
|
setters: {
|
||||||
company: me.frm.doc.company,
|
|
||||||
transaction_date: null
|
transaction_date: null
|
||||||
},
|
},
|
||||||
get_query_filters: {
|
get_query_filters: {
|
||||||
supplier: me.frm.doc.supplier
|
supplier: me.frm.doc.supplier,
|
||||||
|
company: me.frm.doc.company
|
||||||
},
|
},
|
||||||
get_query_method: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.get_rfq_containing_supplier"
|
get_query_method: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.get_rfq_containing_supplier"
|
||||||
|
|
||||||
})
|
})
|
||||||
}, __("Get items from"));
|
}, __("Get Items From"));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"actions": [],
|
"actions": [],
|
||||||
|
"allow_auto_repeat": 1,
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"creation": "2013-05-21 16:16:45",
|
"creation": "2013-05-21 16:16:45",
|
||||||
@ -34,7 +35,6 @@
|
|||||||
"ignore_pricing_rule",
|
"ignore_pricing_rule",
|
||||||
"items_section",
|
"items_section",
|
||||||
"items",
|
"items",
|
||||||
"link_to_mrs",
|
|
||||||
"pricing_rule_details",
|
"pricing_rule_details",
|
||||||
"pricing_rules",
|
"pricing_rules",
|
||||||
"section_break_22",
|
"section_break_22",
|
||||||
@ -321,12 +321,6 @@
|
|||||||
"options": "Supplier Quotation Item",
|
"options": "Supplier Quotation Item",
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"depends_on": "eval:doc.docstatus===0 && (doc.items && doc.items.length)",
|
|
||||||
"fieldname": "link_to_mrs",
|
|
||||||
"fieldtype": "Button",
|
|
||||||
"label": "Link to material requests"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "pricing_rule_details",
|
"fieldname": "pricing_rule_details",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
@ -805,9 +799,10 @@
|
|||||||
],
|
],
|
||||||
"icon": "fa fa-shopping-cart",
|
"icon": "fa fa-shopping-cart",
|
||||||
"idx": 29,
|
"idx": 29,
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-10-01 20:56:17.932007",
|
"modified": "2020-12-03 15:18:29.073368",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Supplier Quotation",
|
"name": "Supplier Quotation",
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"autoname": "Prompt",
|
"autoname": "Prompt",
|
||||||
"creation": "2019-06-05 11:48:30.572795",
|
"creation": "2019-06-05 11:48:30.572795",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
|
"communication_channel",
|
||||||
"communication_medium_type",
|
"communication_medium_type",
|
||||||
"catch_all",
|
|
||||||
"column_break_3",
|
"column_break_3",
|
||||||
|
"catch_all",
|
||||||
"provider",
|
"provider",
|
||||||
"disabled",
|
"disabled",
|
||||||
"timeslots_section",
|
"timeslots_section",
|
||||||
@ -54,9 +56,16 @@
|
|||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"label": "Timeslots",
|
"label": "Timeslots",
|
||||||
"options": "Communication Medium Timeslot"
|
"options": "Communication Medium Timeslot"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "communication_channel",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "Communication Channel",
|
||||||
|
"options": "\nExotel"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2019-06-05 11:49:30.769006",
|
"links": [],
|
||||||
|
"modified": "2020-10-27 16:22:08.068542",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Communication",
|
"module": "Communication",
|
||||||
"name": "Communication Medium",
|
"name": "Communication Medium",
|
||||||
|
@ -23,6 +23,8 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import g
|
|||||||
from erpnext.stock.get_item_details import get_item_warehouse, _get_item_tax_template, get_item_tax_map
|
from erpnext.stock.get_item_details import get_item_warehouse, _get_item_tax_template, get_item_tax_map
|
||||||
from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
|
from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
|
||||||
|
|
||||||
|
class AccountMissingError(frappe.ValidationError): pass
|
||||||
|
|
||||||
force_item_fields = ("item_group", "brand", "stock_uom", "is_fixed_asset", "item_tax_rate", "pricing_rules")
|
force_item_fields = ("item_group", "brand", "stock_uom", "is_fixed_asset", "item_tax_rate", "pricing_rules")
|
||||||
|
|
||||||
class AccountsController(TransactionBase):
|
class AccountsController(TransactionBase):
|
||||||
@ -735,6 +737,21 @@ class AccountsController(TransactionBase):
|
|||||||
|
|
||||||
return self._abbr
|
return self._abbr
|
||||||
|
|
||||||
|
def raise_missing_debit_credit_account_error(self, party_type, party):
|
||||||
|
"""Raise an error if debit to/credit to account does not exist."""
|
||||||
|
db_or_cr = frappe.bold("Debit To") if self.doctype == "Sales Invoice" else frappe.bold("Credit To")
|
||||||
|
rec_or_pay = "Receivable" if self.doctype == "Sales Invoice" else "Payable"
|
||||||
|
|
||||||
|
link_to_party = frappe.utils.get_link_to_form(party_type, party)
|
||||||
|
link_to_company = frappe.utils.get_link_to_form("Company", self.company)
|
||||||
|
|
||||||
|
message = _("{0} Account not found against Customer {1}.").format(db_or_cr, frappe.bold(party) or '')
|
||||||
|
message += "<br>" + _("Please set one of the following:") + "<br>"
|
||||||
|
message += "<br><ul><li>" + _("'Account' in the Accounting section of Customer {0}").format(link_to_party) + "</li>"
|
||||||
|
message += "<li>" + _("'Default {0} Account' in Company {1}").format(rec_or_pay, link_to_company) + "</li></ul>"
|
||||||
|
|
||||||
|
frappe.throw(message, title=_("Account Missing"), exc=AccountMissingError)
|
||||||
|
|
||||||
def validate_party(self):
|
def validate_party(self):
|
||||||
party_type, party = self.get_party()
|
party_type, party = self.get_party()
|
||||||
validate_party_frozen_disabled(party_type, party)
|
validate_party_frozen_disabled(party_type, party)
|
||||||
|
@ -497,6 +497,10 @@ class BuyingController(StockController):
|
|||||||
frappe.throw(_("Row {0}: Conversion Factor is mandatory").format(d.idx))
|
frappe.throw(_("Row {0}: Conversion Factor is mandatory").format(d.idx))
|
||||||
d.stock_qty = flt(d.qty) * flt(d.conversion_factor)
|
d.stock_qty = flt(d.qty) * flt(d.conversion_factor)
|
||||||
|
|
||||||
|
if self.doctype=="Purchase Receipt" and d.meta.get_field("received_stock_qty"):
|
||||||
|
# Set Received Qty in Stock UOM
|
||||||
|
d.received_stock_qty = flt(d.received_qty) * flt(d.conversion_factor, d.precision("conversion_factor"))
|
||||||
|
|
||||||
def validate_purchase_return(self):
|
def validate_purchase_return(self):
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
if self.is_return and flt(d.rejected_qty) != 0:
|
if self.is_return and flt(d.rejected_qty) != 0:
|
||||||
|
@ -203,10 +203,37 @@ def get_already_returned_items(doc):
|
|||||||
|
|
||||||
return items
|
return items
|
||||||
|
|
||||||
|
def get_returned_qty_map_for_row(row_name, doctype):
|
||||||
|
child_doctype = doctype + " Item"
|
||||||
|
reference_field = frappe.scrub(child_doctype) if doctype == "Purchase Receipt" else "dn_detail"
|
||||||
|
|
||||||
|
fields = [
|
||||||
|
"sum(abs(`tab{0}`.qty)) as qty".format(child_doctype),
|
||||||
|
"sum(abs(`tab{0}`.stock_qty)) as stock_qty".format(child_doctype)
|
||||||
|
]
|
||||||
|
|
||||||
|
if doctype == "Purchase Receipt":
|
||||||
|
fields += [
|
||||||
|
"sum(abs(`tab{0}`.rejected_qty)) as rejected_qty".format(child_doctype),
|
||||||
|
"sum(abs(`tab{0}`.received_qty)) as received_qty".format(child_doctype),
|
||||||
|
"sum(abs(`tab{0}`.received_stock_qty)) as received_stock_qty".format(child_doctype)
|
||||||
|
]
|
||||||
|
|
||||||
|
data = frappe.db.get_list(doctype,
|
||||||
|
fields = fields,
|
||||||
|
filters = [
|
||||||
|
[doctype, "docstatus", "=", 1],
|
||||||
|
[doctype, "is_return", "=", 1],
|
||||||
|
[child_doctype, reference_field, "=", row_name]
|
||||||
|
])
|
||||||
|
|
||||||
|
return data[0]
|
||||||
|
|
||||||
def make_return_doc(doctype, source_name, target_doc=None):
|
def make_return_doc(doctype, source_name, target_doc=None):
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
company = frappe.db.get_value("Delivery Note", source_name, "company")
|
company = frappe.db.get_value("Delivery Note", source_name, "company")
|
||||||
default_warehouse_for_sales_return = frappe.db.get_value("Company", company, "default_warehouse_for_sales_return")
|
default_warehouse_for_sales_return = frappe.db.get_value("Company", company, "default_warehouse_for_sales_return")
|
||||||
|
|
||||||
def set_missing_values(source, target):
|
def set_missing_values(source, target):
|
||||||
doc = frappe.get_doc(target)
|
doc = frappe.get_doc(target)
|
||||||
doc.is_return = 1
|
doc.is_return = 1
|
||||||
@ -261,20 +288,25 @@ def make_return_doc(doctype, source_name, target_doc=None):
|
|||||||
doc.run_method("calculate_taxes_and_totals")
|
doc.run_method("calculate_taxes_and_totals")
|
||||||
|
|
||||||
def update_item(source_doc, target_doc, source_parent):
|
def update_item(source_doc, target_doc, source_parent):
|
||||||
target_doc.qty = -1* source_doc.qty
|
target_doc.qty = -1 * source_doc.qty
|
||||||
|
|
||||||
if doctype == "Purchase Receipt":
|
if doctype == "Purchase Receipt":
|
||||||
target_doc.received_qty = -1* source_doc.received_qty
|
returned_qty_map = get_returned_qty_map_for_row(source_doc.name, doctype)
|
||||||
target_doc.rejected_qty = -1* source_doc.rejected_qty
|
target_doc.received_qty = -1 * flt(source_doc.received_qty - (returned_qty_map.get('received_qty') or 0))
|
||||||
target_doc.qty = -1* source_doc.qty
|
target_doc.rejected_qty = -1 * flt(source_doc.rejected_qty - (returned_qty_map.get('rejected_qty') or 0))
|
||||||
target_doc.stock_qty = -1 * source_doc.stock_qty
|
target_doc.qty = -1 * flt(source_doc.qty - (returned_qty_map.get('qty') or 0))
|
||||||
|
|
||||||
|
target_doc.stock_qty = -1 * flt(source_doc.stock_qty - (returned_qty_map.get('stock_qty') or 0))
|
||||||
|
target_doc.received_stock_qty = -1 * flt(source_doc.received_stock_qty - (returned_qty_map.get('received_stock_qty') or 0))
|
||||||
|
|
||||||
target_doc.purchase_order = source_doc.purchase_order
|
target_doc.purchase_order = source_doc.purchase_order
|
||||||
target_doc.purchase_order_item = source_doc.purchase_order_item
|
target_doc.purchase_order_item = source_doc.purchase_order_item
|
||||||
target_doc.rejected_warehouse = source_doc.rejected_warehouse
|
target_doc.rejected_warehouse = source_doc.rejected_warehouse
|
||||||
target_doc.purchase_receipt_item = source_doc.name
|
target_doc.purchase_receipt_item = source_doc.name
|
||||||
|
|
||||||
elif doctype == "Purchase Invoice":
|
elif doctype == "Purchase Invoice":
|
||||||
target_doc.received_qty = -1* source_doc.received_qty
|
target_doc.received_qty = -1 * source_doc.received_qty
|
||||||
target_doc.rejected_qty = -1* source_doc.rejected_qty
|
target_doc.rejected_qty = -1 * source_doc.rejected_qty
|
||||||
target_doc.qty = -1* source_doc.qty
|
target_doc.qty = -1* source_doc.qty
|
||||||
target_doc.stock_qty = -1 * source_doc.stock_qty
|
target_doc.stock_qty = -1 * source_doc.stock_qty
|
||||||
target_doc.purchase_order = source_doc.purchase_order
|
target_doc.purchase_order = source_doc.purchase_order
|
||||||
@ -285,6 +317,10 @@ def make_return_doc(doctype, source_name, target_doc=None):
|
|||||||
target_doc.purchase_invoice_item = source_doc.name
|
target_doc.purchase_invoice_item = source_doc.name
|
||||||
|
|
||||||
elif doctype == "Delivery Note":
|
elif doctype == "Delivery Note":
|
||||||
|
returned_qty_map = get_returned_qty_map_for_row(source_doc.name, doctype)
|
||||||
|
target_doc.qty = -1 * flt(source_doc.qty - (returned_qty_map.get('qty') or 0))
|
||||||
|
target_doc.stock_qty = -1 * flt(source_doc.stock_qty - (returned_qty_map.get('stock_qty') or 0))
|
||||||
|
|
||||||
target_doc.against_sales_order = source_doc.against_sales_order
|
target_doc.against_sales_order = source_doc.against_sales_order
|
||||||
target_doc.against_sales_invoice = source_doc.against_sales_invoice
|
target_doc.against_sales_invoice = source_doc.against_sales_invoice
|
||||||
target_doc.so_detail = source_doc.so_detail
|
target_doc.so_detail = source_doc.so_detail
|
||||||
|
@ -42,7 +42,7 @@ class SellingController(StockController):
|
|||||||
self.validate_max_discount()
|
self.validate_max_discount()
|
||||||
self.validate_selling_price()
|
self.validate_selling_price()
|
||||||
self.set_qty_as_per_stock_uom()
|
self.set_qty_as_per_stock_uom()
|
||||||
self.set_po_nos()
|
self.set_po_nos(for_validate=True)
|
||||||
self.set_gross_profit()
|
self.set_gross_profit()
|
||||||
set_default_income_account_for_item(self)
|
set_default_income_account_for_item(self)
|
||||||
self.set_customer_address()
|
self.set_customer_address()
|
||||||
@ -370,14 +370,36 @@ class SellingController(StockController):
|
|||||||
}))
|
}))
|
||||||
self.make_sl_entries(sl_entries)
|
self.make_sl_entries(sl_entries)
|
||||||
|
|
||||||
def set_po_nos(self):
|
def set_po_nos(self, for_validate=False):
|
||||||
if self.doctype in ("Delivery Note", "Sales Invoice") and hasattr(self, "items"):
|
if self.doctype == 'Sales Invoice' and hasattr(self, "items"):
|
||||||
ref_fieldname = "against_sales_order" if self.doctype == "Delivery Note" else "sales_order"
|
if for_validate and self.po_no:
|
||||||
sales_orders = list(set([d.get(ref_fieldname) for d in self.items if d.get(ref_fieldname)]))
|
return
|
||||||
if sales_orders:
|
self.set_pos_for_sales_invoice()
|
||||||
po_nos = frappe.get_all('Sales Order', 'po_no', filters = {'name': ('in', sales_orders)})
|
if self.doctype == 'Delivery Note' and hasattr(self, "items"):
|
||||||
if po_nos and po_nos[0].get('po_no'):
|
if for_validate and self.po_no:
|
||||||
self.po_no = ', '.join(list(set([d.po_no for d in po_nos if d.po_no])))
|
return
|
||||||
|
self.set_pos_for_delivery_note()
|
||||||
|
|
||||||
|
def set_pos_for_sales_invoice(self):
|
||||||
|
po_nos = []
|
||||||
|
if self.po_no:
|
||||||
|
po_nos.append(self.po_no)
|
||||||
|
self.get_po_nos('Sales Order', 'sales_order', po_nos)
|
||||||
|
self.get_po_nos('Delivery Note', 'delivery_note', po_nos)
|
||||||
|
self.po_no = ', '.join(list(set(x.strip() for x in ','.join(po_nos).split(','))))
|
||||||
|
|
||||||
|
def set_pos_for_delivery_note(self):
|
||||||
|
po_nos = []
|
||||||
|
if self.po_no:
|
||||||
|
po_nos.append(self.po_no)
|
||||||
|
self.get_po_nos('Sales Order', 'against_sales_order', po_nos)
|
||||||
|
self.get_po_nos('Sales Invoice', 'against_sales_invoice', po_nos)
|
||||||
|
self.po_no = ', '.join(list(set(x.strip() for x in ','.join(po_nos).split(','))))
|
||||||
|
|
||||||
|
def get_po_nos(self, ref_doctype, ref_fieldname, po_nos):
|
||||||
|
doc_list = list(set([d.get(ref_fieldname) for d in self.items if d.get(ref_fieldname)]))
|
||||||
|
if doc_list:
|
||||||
|
po_nos += [d.po_no for d in frappe.get_all(ref_doctype, 'po_no', filters = {'name': ('in', doc_list)}) if d.get('po_no')]
|
||||||
|
|
||||||
def set_gross_profit(self):
|
def set_gross_profit(self):
|
||||||
if self.doctype in ["Sales Order", "Quotation"]:
|
if self.doctype in ["Sales Order", "Quotation"]:
|
||||||
@ -402,26 +424,26 @@ class SellingController(StockController):
|
|||||||
return
|
return
|
||||||
|
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
if self.doctype == "Sales Invoice":
|
if self.doctype in ["POS Invoice","Sales Invoice"]:
|
||||||
e = [d.item_code, d.description, d.warehouse, d.sales_order or d.delivery_note, d.batch_no or '']
|
stock_items = [d.item_code, d.description, d.warehouse, d.sales_order or d.delivery_note, d.batch_no or '']
|
||||||
f = [d.item_code, d.description, d.sales_order or d.delivery_note]
|
non_stock_items = [d.item_code, d.description, d.sales_order or d.delivery_note]
|
||||||
elif self.doctype == "Delivery Note":
|
elif self.doctype == "Delivery Note":
|
||||||
e = [d.item_code, d.description, d.warehouse, d.against_sales_order or d.against_sales_invoice, d.batch_no or '']
|
stock_items = [d.item_code, d.description, d.warehouse, d.against_sales_order or d.against_sales_invoice, d.batch_no or '']
|
||||||
f = [d.item_code, d.description, d.against_sales_order or d.against_sales_invoice]
|
non_stock_items = [d.item_code, d.description, d.against_sales_order or d.against_sales_invoice]
|
||||||
elif self.doctype in ["Sales Order", "Quotation"]:
|
elif self.doctype in ["Sales Order", "Quotation"]:
|
||||||
e = [d.item_code, d.description, d.warehouse, '']
|
stock_items = [d.item_code, d.description, d.warehouse, '']
|
||||||
f = [d.item_code, d.description]
|
non_stock_items = [d.item_code, d.description]
|
||||||
|
|
||||||
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1:
|
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1:
|
||||||
if e in check_list:
|
if stock_items in check_list:
|
||||||
frappe.throw(_("Note: Item {0} entered multiple times").format(d.item_code))
|
frappe.throw(_("Note: Item {0} entered multiple times").format(d.item_code))
|
||||||
else:
|
else:
|
||||||
check_list.append(e)
|
check_list.append(stock_items)
|
||||||
else:
|
else:
|
||||||
if f in chk_dupl_itm:
|
if non_stock_items in chk_dupl_itm:
|
||||||
frappe.throw(_("Note: Item {0} entered multiple times").format(d.item_code))
|
frappe.throw(_("Note: Item {0} entered multiple times").format(d.item_code))
|
||||||
else:
|
else:
|
||||||
chk_dupl_itm.append(f)
|
chk_dupl_itm.append(non_stock_items)
|
||||||
|
|
||||||
def validate_target_warehouse(self):
|
def validate_target_warehouse(self):
|
||||||
items = self.get("items") + (self.get("packed_items") or [])
|
items = self.get("items") + (self.get("packed_items") or [])
|
||||||
|
@ -58,6 +58,7 @@ status_map = {
|
|||||||
"Delivery Note": [
|
"Delivery Note": [
|
||||||
["Draft", None],
|
["Draft", None],
|
||||||
["To Bill", "eval:self.per_billed < 100 and self.docstatus == 1"],
|
["To Bill", "eval:self.per_billed < 100 and self.docstatus == 1"],
|
||||||
|
["Return Issued", "eval:self.per_returned == 100 and self.docstatus == 1"],
|
||||||
["Completed", "eval:self.per_billed == 100 and self.docstatus == 1"],
|
["Completed", "eval:self.per_billed == 100 and self.docstatus == 1"],
|
||||||
["Cancelled", "eval:self.docstatus==2"],
|
["Cancelled", "eval:self.docstatus==2"],
|
||||||
["Closed", "eval:self.status=='Closed'"],
|
["Closed", "eval:self.status=='Closed'"],
|
||||||
@ -65,6 +66,7 @@ status_map = {
|
|||||||
"Purchase Receipt": [
|
"Purchase Receipt": [
|
||||||
["Draft", None],
|
["Draft", None],
|
||||||
["To Bill", "eval:self.per_billed < 100 and self.docstatus == 1"],
|
["To Bill", "eval:self.per_billed < 100 and self.docstatus == 1"],
|
||||||
|
["Return Issued", "eval:self.per_returned == 100 and self.docstatus == 1"],
|
||||||
["Completed", "eval:self.per_billed == 100 and self.docstatus == 1"],
|
["Completed", "eval:self.per_billed == 100 and self.docstatus == 1"],
|
||||||
["Cancelled", "eval:self.docstatus==2"],
|
["Cancelled", "eval:self.docstatus==2"],
|
||||||
["Closed", "eval:self.status=='Closed'"],
|
["Closed", "eval:self.status=='Closed'"],
|
||||||
@ -232,7 +234,7 @@ class StatusUpdater(Document):
|
|||||||
|
|
||||||
self._update_children(args, update_modified)
|
self._update_children(args, update_modified)
|
||||||
|
|
||||||
if "percent_join_field" in args:
|
if "percent_join_field" in args or "percent_join_field_parent" in args:
|
||||||
self._update_percent_field_in_targets(args, update_modified)
|
self._update_percent_field_in_targets(args, update_modified)
|
||||||
|
|
||||||
def _update_children(self, args, update_modified):
|
def _update_children(self, args, update_modified):
|
||||||
@ -272,13 +274,19 @@ class StatusUpdater(Document):
|
|||||||
|
|
||||||
def _update_percent_field_in_targets(self, args, update_modified=True):
|
def _update_percent_field_in_targets(self, args, update_modified=True):
|
||||||
"""Update percent field in parent transaction"""
|
"""Update percent field in parent transaction"""
|
||||||
distinct_transactions = set([d.get(args['percent_join_field'])
|
if args.get('percent_join_field_parent'):
|
||||||
for d in self.get_all_children(args['source_dt'])])
|
# if reference to target doc where % is to be updated, is
|
||||||
|
# in source doc's parent form, consider percent_join_field_parent
|
||||||
|
args['name'] = self.get(args['percent_join_field_parent'])
|
||||||
|
self._update_percent_field(args, update_modified)
|
||||||
|
else:
|
||||||
|
distinct_transactions = set([d.get(args['percent_join_field'])
|
||||||
|
for d in self.get_all_children(args['source_dt'])])
|
||||||
|
|
||||||
for name in distinct_transactions:
|
for name in distinct_transactions:
|
||||||
if name:
|
if name:
|
||||||
args['name'] = name
|
args['name'] = name
|
||||||
self._update_percent_field(args, update_modified)
|
self._update_percent_field(args, update_modified)
|
||||||
|
|
||||||
def _update_percent_field(self, args, update_modified=True):
|
def _update_percent_field(self, args, update_modified=True):
|
||||||
"""Update percent field in parent transaction"""
|
"""Update percent field in parent transaction"""
|
||||||
|
@ -229,9 +229,9 @@ class StockController(AccountsController):
|
|||||||
|
|
||||||
def check_expense_account(self, item):
|
def check_expense_account(self, item):
|
||||||
if not item.get("expense_account"):
|
if not item.get("expense_account"):
|
||||||
frappe.throw(_("Row #{0}: Expense Account not set for Item {1}. Please set an Expense \
|
msg = _("Please set an Expense Account in the Items table")
|
||||||
Account in the Items table").format(item.idx, frappe.bold(item.item_code)),
|
frappe.throw(_("Row #{0}: Expense Account not set for the Item {1}. {2}")
|
||||||
title=_("Expense Account Missing"))
|
.format(item.idx, frappe.bold(item.item_code), msg), title=_("Expense Account Missing"))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
is_expense_account = frappe.db.get_value("Account",
|
is_expense_account = frappe.db.get_value("Account",
|
||||||
@ -247,7 +247,9 @@ class StockController(AccountsController):
|
|||||||
for d in self.items:
|
for d in self.items:
|
||||||
if not d.batch_no: continue
|
if not d.batch_no: continue
|
||||||
|
|
||||||
serial_nos = [sr.name for sr in frappe.get_all("Serial No", {'batch_no': d.batch_no})]
|
serial_nos = [sr.name for sr in frappe.get_all("Serial No",
|
||||||
|
{'batch_no': d.batch_no, 'status': 'Inactive'})]
|
||||||
|
|
||||||
if serial_nos:
|
if serial_nos:
|
||||||
frappe.db.set_value("Serial No", { 'name': ['in', serial_nos] }, "batch_no", None)
|
frappe.db.set_value("Serial No", { 'name': ['in', serial_nos] }, "batch_no", None)
|
||||||
|
|
||||||
@ -338,11 +340,15 @@ class StockController(AccountsController):
|
|||||||
validate_warehouse_company(w, self.company)
|
validate_warehouse_company(w, self.company)
|
||||||
|
|
||||||
def update_billing_percentage(self, update_modified=True):
|
def update_billing_percentage(self, update_modified=True):
|
||||||
|
target_ref_field = "amount"
|
||||||
|
if self.doctype == "Delivery Note":
|
||||||
|
target_ref_field = "amount - (returned_qty * rate)"
|
||||||
|
|
||||||
self._update_percent_field({
|
self._update_percent_field({
|
||||||
"target_dt": self.doctype + " Item",
|
"target_dt": self.doctype + " Item",
|
||||||
"target_parent_dt": self.doctype,
|
"target_parent_dt": self.doctype,
|
||||||
"target_parent_field": "per_billed",
|
"target_parent_field": "per_billed",
|
||||||
"target_ref_field": "amount",
|
"target_ref_field": target_ref_field,
|
||||||
"target_field": "billed_amt",
|
"target_field": "billed_amt",
|
||||||
"name": self.name,
|
"name": self.name,
|
||||||
}, update_modified)
|
}, update_modified)
|
||||||
|
@ -641,7 +641,8 @@ class calculate_taxes_and_totals(object):
|
|||||||
if default_mode_of_payment:
|
if default_mode_of_payment:
|
||||||
self.doc.append('payments', {
|
self.doc.append('payments', {
|
||||||
'mode_of_payment': default_mode_of_payment.mode_of_payment,
|
'mode_of_payment': default_mode_of_payment.mode_of_payment,
|
||||||
'amount': total_amount_to_pay
|
'amount': total_amount_to_pay,
|
||||||
|
'default': 1
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
self.doc.is_pos = 0
|
self.doc.is_pos = 0
|
||||||
|
@ -4,7 +4,7 @@ function check_times(frm) {
|
|||||||
let from_time = Date.parse('01/01/2019 ' + d.from_time);
|
let from_time = Date.parse('01/01/2019 ' + d.from_time);
|
||||||
let to_time = Date.parse('01/01/2019 ' + d.to_time);
|
let to_time = Date.parse('01/01/2019 ' + d.to_time);
|
||||||
if (from_time > to_time) {
|
if (from_time > to_time) {
|
||||||
frappe.throw(__(`In row ${i + 1} of Appointment Booking Slots : "To Time" must be later than "From Time"`));
|
frappe.throw(__('In row {0} of Appointment Booking Slots: "To Time" must be later than "From Time".', [i + 1]));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
@ -23,8 +23,7 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "contract_terms",
|
"fieldname": "contract_terms",
|
||||||
"fieldtype": "Text Editor",
|
"fieldtype": "Text Editor",
|
||||||
"label": "Contract Terms and Conditions",
|
"label": "Contract Terms and Conditions"
|
||||||
"read_only": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "sb_fulfilment",
|
"fieldname": "sb_fulfilment",
|
||||||
@ -45,7 +44,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-06-03 00:24:58.179816",
|
"modified": "2020-11-11 17:49:44.879363",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "CRM",
|
"module": "CRM",
|
||||||
"name": "Contract Template",
|
"name": "Contract Template",
|
||||||
|
@ -4,48 +4,55 @@
|
|||||||
"item_code": "Computer",
|
"item_code": "Computer",
|
||||||
"gross_purchase_amount": 100000,
|
"gross_purchase_amount": 100000,
|
||||||
"asset_owner": "Company",
|
"asset_owner": "Company",
|
||||||
"available_for_use_date": "2017-01-02"
|
"available_for_use_date": "2017-01-02",
|
||||||
|
"location": "Main Location"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"asset_name": "Macbook Air - 1",
|
"asset_name": "Macbook Air - 1",
|
||||||
"item_code": "Computer",
|
"item_code": "Computer",
|
||||||
"gross_purchase_amount": 60000,
|
"gross_purchase_amount": 60000,
|
||||||
"asset_owner": "Company",
|
"asset_owner": "Company",
|
||||||
"available_for_use_date": "2017-10-02"
|
"available_for_use_date": "2017-10-02",
|
||||||
|
"location": "Avg Location"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"asset_name": "Conferrence Table",
|
"asset_name": "Conferrence Table",
|
||||||
"item_code": "Table",
|
"item_code": "Table",
|
||||||
"gross_purchase_amount": 30000,
|
"gross_purchase_amount": 30000,
|
||||||
"asset_owner": "Company",
|
"asset_owner": "Company",
|
||||||
"available_for_use_date": "2018-10-02"
|
"available_for_use_date": "2018-10-02",
|
||||||
|
"location": "Zany Location"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"asset_name": "Lunch Table",
|
"asset_name": "Lunch Table",
|
||||||
"item_code": "Table",
|
"item_code": "Table",
|
||||||
"gross_purchase_amount": 20000,
|
"gross_purchase_amount": 20000,
|
||||||
"asset_owner": "Company",
|
"asset_owner": "Company",
|
||||||
"available_for_use_date": "2018-06-02"
|
"available_for_use_date": "2018-06-02",
|
||||||
|
"location": "Fletcher Location"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"asset_name": "ERPNext",
|
"asset_name": "ERPNext",
|
||||||
"item_code": "ERP",
|
"item_code": "ERP",
|
||||||
"gross_purchase_amount": 100000,
|
"gross_purchase_amount": 100000,
|
||||||
"asset_owner": "Company",
|
"asset_owner": "Company",
|
||||||
"available_for_use_date": "2018-09-02"
|
"available_for_use_date": "2018-09-02",
|
||||||
|
"location":"Main Location"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"asset_name": "Chair 1",
|
"asset_name": "Chair 1",
|
||||||
"item_code": "Chair",
|
"item_code": "Chair",
|
||||||
"gross_purchase_amount": 10000,
|
"gross_purchase_amount": 10000,
|
||||||
"asset_owner": "Company",
|
"asset_owner": "Company",
|
||||||
"available_for_use_date": "2018-07-02"
|
"available_for_use_date": "2018-07-02",
|
||||||
|
"location": "Zany Location"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"asset_name": "Chair 2",
|
"asset_name": "Chair 2",
|
||||||
"item_code": "Chair",
|
"item_code": "Chair",
|
||||||
"gross_purchase_amount": 10000,
|
"gross_purchase_amount": 10000,
|
||||||
"asset_owner": "Company",
|
"asset_owner": "Company",
|
||||||
"available_for_use_date": "2018-07-02"
|
"available_for_use_date": "2018-07-02",
|
||||||
|
"location": "Avg Location"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
22
erpnext/demo/data/location.json
Normal file
22
erpnext/demo/data/location.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"location_name": "Main Location",
|
||||||
|
"latitude": 40.0,
|
||||||
|
"longitude": 20.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"location_name": "Avg Location",
|
||||||
|
"latitude": 63.0,
|
||||||
|
"longitude": 99.3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"location_name": "Zany Location",
|
||||||
|
"latitude": 47.5,
|
||||||
|
"longitude": 10.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"location_name": "Fletcher Location",
|
||||||
|
"latitude": 100.90,
|
||||||
|
"longitude": 80
|
||||||
|
}
|
||||||
|
]
|
@ -9,6 +9,7 @@ from erpnext.demo.domains import data
|
|||||||
from six import iteritems
|
from six import iteritems
|
||||||
|
|
||||||
def setup_data():
|
def setup_data():
|
||||||
|
import_json("Location")
|
||||||
import_json("Asset Category")
|
import_json("Asset Category")
|
||||||
setup_item()
|
setup_item()
|
||||||
setup_workstation()
|
setup_workstation()
|
||||||
|
@ -134,7 +134,7 @@ def setup_employee():
|
|||||||
salary_component = frappe.get_doc('Salary Component', d.name)
|
salary_component = frappe.get_doc('Salary Component', d.name)
|
||||||
salary_component.append('accounts', dict(
|
salary_component.append('accounts', dict(
|
||||||
company=erpnext.get_default_company(),
|
company=erpnext.get_default_company(),
|
||||||
default_account=frappe.get_value('Account', dict(account_name=('like', 'Salary%')))
|
account=frappe.get_value('Account', dict(account_name=('like', 'Salary%')))
|
||||||
))
|
))
|
||||||
salary_component.save()
|
salary_component.save()
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ def make_stock_reconciliation():
|
|||||||
if item.qty:
|
if item.qty:
|
||||||
item.qty = item.qty - round(random.randint(1, item.qty))
|
item.qty = item.qty - round(random.randint(1, item.qty))
|
||||||
try:
|
try:
|
||||||
stock_reco.insert(ignore_permissions=True)
|
stock_reco.insert(ignore_permissions=True, ignore_mandatory=True)
|
||||||
stock_reco.submit()
|
stock_reco.submit()
|
||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
except OpeningEntryAccountError:
|
except OpeningEntryAccountError:
|
||||||
|
@ -6,8 +6,10 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import get_link_to_form, getdate
|
from frappe.utils import get_link_to_form, getdate, formatdate
|
||||||
|
from erpnext import get_default_company
|
||||||
from erpnext.education.api import get_student_group_students
|
from erpnext.education.api import get_student_group_students
|
||||||
|
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
|
||||||
|
|
||||||
class StudentAttendance(Document):
|
class StudentAttendance(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
@ -17,6 +19,7 @@ class StudentAttendance(Document):
|
|||||||
self.set_student_group()
|
self.set_student_group()
|
||||||
self.validate_student()
|
self.validate_student()
|
||||||
self.validate_duplication()
|
self.validate_duplication()
|
||||||
|
self.validate_is_holiday()
|
||||||
|
|
||||||
def set_date(self):
|
def set_date(self):
|
||||||
if self.course_schedule:
|
if self.course_schedule:
|
||||||
@ -78,3 +81,18 @@ class StudentAttendance(Document):
|
|||||||
record = get_link_to_form('Student Attendance', attendance_record)
|
record = get_link_to_form('Student Attendance', attendance_record)
|
||||||
frappe.throw(_('Student Attendance record {0} already exists against the Student {1}')
|
frappe.throw(_('Student Attendance record {0} already exists against the Student {1}')
|
||||||
.format(record, frappe.bold(self.student)), title=_('Duplicate Entry'))
|
.format(record, frappe.bold(self.student)), title=_('Duplicate Entry'))
|
||||||
|
|
||||||
|
def validate_is_holiday(self):
|
||||||
|
holiday_list = get_holiday_list()
|
||||||
|
if is_holiday(holiday_list, self.date):
|
||||||
|
frappe.throw(_('Attendance cannot be marked for {0} as it is a holiday.').format(
|
||||||
|
frappe.bold(formatdate(self.date))))
|
||||||
|
|
||||||
|
def get_holiday_list(company=None):
|
||||||
|
if not company:
|
||||||
|
company = get_default_company() or frappe.get_all('Company')[0].name
|
||||||
|
|
||||||
|
holiday_list = frappe.get_cached_value('Company', company, 'default_holiday_list')
|
||||||
|
if not holiday_list:
|
||||||
|
frappe.throw(_('Please set a default Holiday List for Company {0}').format(frappe.bold(get_default_company())))
|
||||||
|
return holiday_list
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
"column_break_3",
|
"column_break_3",
|
||||||
"from_date",
|
"from_date",
|
||||||
"to_date",
|
"to_date",
|
||||||
|
"total_leave_days",
|
||||||
"section_break_5",
|
"section_break_5",
|
||||||
"attendance_based_on",
|
"attendance_based_on",
|
||||||
"student_group",
|
"student_group",
|
||||||
@ -110,11 +111,17 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "column_break_11",
|
"fieldname": "column_break_11",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "total_leave_days",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"label": "Total Leave Days",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-07-08 13:22:38.329002",
|
"modified": "2020-09-21 18:10:24.440669",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Education",
|
"module": "Education",
|
||||||
"name": "Student Leave Application",
|
"name": "Student Leave Application",
|
||||||
|
@ -6,11 +6,14 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from frappe.utils import get_link_to_form, getdate
|
from frappe.utils import get_link_to_form, getdate, date_diff, flt
|
||||||
|
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
|
||||||
|
from erpnext.education.doctype.student_attendance.student_attendance import get_holiday_list
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
class StudentLeaveApplication(Document):
|
class StudentLeaveApplication(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
self.validate_holiday_list()
|
||||||
self.validate_duplicate()
|
self.validate_duplicate()
|
||||||
self.validate_from_to_dates('from_date', 'to_date')
|
self.validate_from_to_dates('from_date', 'to_date')
|
||||||
|
|
||||||
@ -39,10 +42,19 @@ class StudentLeaveApplication(Document):
|
|||||||
frappe.throw(_('Leave application {0} already exists against the student {1}')
|
frappe.throw(_('Leave application {0} already exists against the student {1}')
|
||||||
.format(link, frappe.bold(self.student)), title=_('Duplicate Entry'))
|
.format(link, frappe.bold(self.student)), title=_('Duplicate Entry'))
|
||||||
|
|
||||||
|
def validate_holiday_list(self):
|
||||||
|
holiday_list = get_holiday_list()
|
||||||
|
self.total_leave_days = get_number_of_leave_days(self.from_date, self.to_date, holiday_list)
|
||||||
|
|
||||||
def update_attendance(self):
|
def update_attendance(self):
|
||||||
|
holiday_list = get_holiday_list()
|
||||||
|
|
||||||
for dt in daterange(getdate(self.from_date), getdate(self.to_date)):
|
for dt in daterange(getdate(self.from_date), getdate(self.to_date)):
|
||||||
date = dt.strftime('%Y-%m-%d')
|
date = dt.strftime('%Y-%m-%d')
|
||||||
|
|
||||||
|
if is_holiday(holiday_list, date):
|
||||||
|
continue
|
||||||
|
|
||||||
attendance = frappe.db.exists('Student Attendance', {
|
attendance = frappe.db.exists('Student Attendance', {
|
||||||
'student': self.student,
|
'student': self.student,
|
||||||
'date': date,
|
'date': date,
|
||||||
@ -89,3 +101,19 @@ class StudentLeaveApplication(Document):
|
|||||||
def daterange(start_date, end_date):
|
def daterange(start_date, end_date):
|
||||||
for n in range(int ((end_date - start_date).days)+1):
|
for n in range(int ((end_date - start_date).days)+1):
|
||||||
yield start_date + timedelta(n)
|
yield start_date + timedelta(n)
|
||||||
|
|
||||||
|
def get_number_of_leave_days(from_date, to_date, holiday_list):
|
||||||
|
number_of_days = date_diff(to_date, from_date) + 1
|
||||||
|
|
||||||
|
holidays = frappe.db.sql("""
|
||||||
|
SELECT
|
||||||
|
COUNT(DISTINCT holiday_date)
|
||||||
|
FROM `tabHoliday` h1,`tabHoliday List` h2
|
||||||
|
WHERE
|
||||||
|
h1.parent = h2.name and
|
||||||
|
h1.holiday_date between %s and %s and
|
||||||
|
h2.name = %s""", (from_date, to_date, holiday_list))[0][0]
|
||||||
|
|
||||||
|
number_of_days = flt(number_of_days) - flt(holidays)
|
||||||
|
|
||||||
|
return number_of_days
|
||||||
|
@ -5,13 +5,15 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
import unittest
|
import unittest
|
||||||
from frappe.utils import getdate, add_days
|
from frappe.utils import getdate, add_days, add_months
|
||||||
|
from erpnext import get_default_company
|
||||||
from erpnext.education.doctype.student_group.test_student_group import get_random_group
|
from erpnext.education.doctype.student_group.test_student_group import get_random_group
|
||||||
from erpnext.education.doctype.student.test_student import create_student
|
from erpnext.education.doctype.student.test_student import create_student
|
||||||
|
|
||||||
class TestStudentLeaveApplication(unittest.TestCase):
|
class TestStudentLeaveApplication(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
frappe.db.sql("""delete from `tabStudent Leave Application`""")
|
frappe.db.sql("""delete from `tabStudent Leave Application`""")
|
||||||
|
create_holiday_list()
|
||||||
|
|
||||||
def test_attendance_record_creation(self):
|
def test_attendance_record_creation(self):
|
||||||
leave_application = create_leave_application()
|
leave_application = create_leave_application()
|
||||||
@ -35,20 +37,45 @@ class TestStudentLeaveApplication(unittest.TestCase):
|
|||||||
attendance_status = frappe.db.get_value('Student Attendance', {'leave_application': leave_application.name}, 'docstatus')
|
attendance_status = frappe.db.get_value('Student Attendance', {'leave_application': leave_application.name}, 'docstatus')
|
||||||
self.assertTrue(attendance_status, 2)
|
self.assertTrue(attendance_status, 2)
|
||||||
|
|
||||||
|
def test_holiday(self):
|
||||||
|
today = getdate()
|
||||||
|
leave_application = create_leave_application(from_date=today, to_date= add_days(today, 1), submit=0)
|
||||||
|
|
||||||
def create_leave_application(from_date=None, to_date=None, mark_as_present=0):
|
# holiday list validation
|
||||||
|
company = get_default_company() or frappe.get_all('Company')[0].name
|
||||||
|
frappe.db.set_value('Company', company, 'default_holiday_list', '')
|
||||||
|
self.assertRaises(frappe.ValidationError, leave_application.save)
|
||||||
|
|
||||||
|
frappe.db.set_value('Company', company, 'default_holiday_list', 'Test Holiday List for Student')
|
||||||
|
leave_application.save()
|
||||||
|
|
||||||
|
leave_application.reload()
|
||||||
|
self.assertEqual(leave_application.total_leave_days, 1)
|
||||||
|
|
||||||
|
# check no attendance record created for a holiday
|
||||||
|
leave_application.submit()
|
||||||
|
self.assertIsNone(frappe.db.exists('Student Attendance', {'leave_application': leave_application.name, 'date': add_days(today, 1)}))
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
company = get_default_company() or frappe.get_all('Company')[0].name
|
||||||
|
frappe.db.set_value('Company', company, 'default_holiday_list', '_Test Holiday List')
|
||||||
|
|
||||||
|
|
||||||
|
def create_leave_application(from_date=None, to_date=None, mark_as_present=0, submit=1):
|
||||||
student = get_student()
|
student = get_student()
|
||||||
|
|
||||||
leave_application = frappe.get_doc({
|
leave_application = frappe.new_doc('Student Leave Application')
|
||||||
'doctype': 'Student Leave Application',
|
leave_application.student = student.name
|
||||||
'student': student.name,
|
leave_application.attendance_based_on = 'Student Group'
|
||||||
'attendance_based_on': 'Student Group',
|
leave_application.student_group = get_random_group().name
|
||||||
'student_group': get_random_group().name,
|
leave_application.from_date = from_date if from_date else getdate()
|
||||||
'from_date': from_date if from_date else getdate(),
|
leave_application.to_date = from_date if from_date else getdate()
|
||||||
'to_date': from_date if from_date else getdate(),
|
leave_application.mark_as_present = mark_as_present
|
||||||
'mark_as_present': mark_as_present
|
|
||||||
}).insert()
|
if submit:
|
||||||
leave_application.submit()
|
leave_application.insert()
|
||||||
|
leave_application.submit()
|
||||||
|
|
||||||
return leave_application
|
return leave_application
|
||||||
|
|
||||||
def create_student_attendance(date=None, status=None):
|
def create_student_attendance(date=None, status=None):
|
||||||
@ -68,3 +95,21 @@ def get_student():
|
|||||||
first_name='Test',
|
first_name='Test',
|
||||||
last_name='Student'
|
last_name='Student'
|
||||||
))
|
))
|
||||||
|
|
||||||
|
def create_holiday_list():
|
||||||
|
holiday_list = 'Test Holiday List for Student'
|
||||||
|
today = getdate()
|
||||||
|
if not frappe.db.exists('Holiday List', holiday_list):
|
||||||
|
frappe.get_doc(dict(
|
||||||
|
doctype = 'Holiday List',
|
||||||
|
holiday_list_name = holiday_list,
|
||||||
|
from_date = add_months(today, -6),
|
||||||
|
to_date = add_months(today, 6),
|
||||||
|
holidays = [
|
||||||
|
dict(holiday_date=add_days(today, 1), description = 'Test')
|
||||||
|
]
|
||||||
|
)).insert()
|
||||||
|
|
||||||
|
company = get_default_company() or frappe.get_all('Company')[0].name
|
||||||
|
frappe.db.set_value('Company', company, 'default_holiday_list', holiday_list)
|
||||||
|
return holiday_list
|
@ -3,8 +3,10 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import cstr, cint, getdate
|
from frappe.utils import formatdate
|
||||||
from frappe import msgprint, _
|
from frappe import msgprint, _
|
||||||
|
from erpnext.education.doctype.student_attendance.student_attendance import get_holiday_list
|
||||||
|
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
if not filters: filters = {}
|
if not filters: filters = {}
|
||||||
@ -15,6 +17,11 @@ def execute(filters=None):
|
|||||||
columns = get_columns(filters)
|
columns = get_columns(filters)
|
||||||
date = filters.get("date")
|
date = filters.get("date")
|
||||||
|
|
||||||
|
holiday_list = get_holiday_list()
|
||||||
|
if is_holiday(holiday_list, filters.get("date")):
|
||||||
|
msgprint(_("No attendance has been marked for {0} as it is a Holiday").format(frappe.bold(formatdate(filters.get("date")))))
|
||||||
|
|
||||||
|
|
||||||
absent_students = get_absent_students(date)
|
absent_students = get_absent_students(date)
|
||||||
leave_applicants = get_leave_applications(date)
|
leave_applicants = get_leave_applications(date)
|
||||||
if absent_students:
|
if absent_students:
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import cstr, cint, getdate
|
from frappe.utils import formatdate
|
||||||
from frappe import msgprint, _
|
from frappe import msgprint, _
|
||||||
|
from erpnext.education.doctype.student_attendance.student_attendance import get_holiday_list
|
||||||
|
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
if not filters: filters = {}
|
if not filters: filters = {}
|
||||||
@ -12,6 +14,10 @@ def execute(filters=None):
|
|||||||
if not filters.get("date"):
|
if not filters.get("date"):
|
||||||
msgprint(_("Please select date"), raise_exception=1)
|
msgprint(_("Please select date"), raise_exception=1)
|
||||||
|
|
||||||
|
holiday_list = get_holiday_list()
|
||||||
|
if is_holiday(holiday_list, filters.get("date")):
|
||||||
|
msgprint(_("No attendance has been marked for {0} as it is a Holiday").format(frappe.bold(formatdate(filters.get("date")))))
|
||||||
|
|
||||||
columns = get_columns(filters)
|
columns = get_columns(filters)
|
||||||
|
|
||||||
active_student_group = get_active_student_group()
|
active_student_group = get_active_student_group()
|
||||||
|
@ -7,6 +7,8 @@ from frappe.utils import cstr, cint, getdate, get_first_day, get_last_day, date_
|
|||||||
from frappe import msgprint, _
|
from frappe import msgprint, _
|
||||||
from calendar import monthrange
|
from calendar import monthrange
|
||||||
from erpnext.education.api import get_student_group_students
|
from erpnext.education.api import get_student_group_students
|
||||||
|
from erpnext.education.doctype.student_attendance.student_attendance import get_holiday_list
|
||||||
|
from erpnext.support.doctype.issue.issue import get_holidays
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
if not filters: filters = {}
|
if not filters: filters = {}
|
||||||
@ -19,26 +21,32 @@ def execute(filters=None):
|
|||||||
students_list = get_students_list(students)
|
students_list = get_students_list(students)
|
||||||
att_map = get_attendance_list(from_date, to_date, filters.get("student_group"), students_list)
|
att_map = get_attendance_list(from_date, to_date, filters.get("student_group"), students_list)
|
||||||
data = []
|
data = []
|
||||||
|
|
||||||
for stud in students:
|
for stud in students:
|
||||||
row = [stud.student, stud.student_name]
|
row = [stud.student, stud.student_name]
|
||||||
student_status = frappe.db.get_value("Student", stud.student, "enabled")
|
student_status = frappe.db.get_value("Student", stud.student, "enabled")
|
||||||
date = from_date
|
date = from_date
|
||||||
total_p = total_a = 0.0
|
total_p = total_a = 0.0
|
||||||
|
|
||||||
for day in range(total_days_in_month):
|
for day in range(total_days_in_month):
|
||||||
status="None"
|
status="None"
|
||||||
|
|
||||||
if att_map.get(stud.student):
|
if att_map.get(stud.student):
|
||||||
status = att_map.get(stud.student).get(date, "None")
|
status = att_map.get(stud.student).get(date, "None")
|
||||||
elif not student_status:
|
elif not student_status:
|
||||||
status = "Inactive"
|
status = "Inactive"
|
||||||
else:
|
else:
|
||||||
status = "None"
|
status = "None"
|
||||||
status_map = {"Present": "P", "Absent": "A", "None": "", "Inactive":"-"}
|
|
||||||
|
status_map = {"Present": "P", "Absent": "A", "None": "", "Inactive":"-", "Holiday":"H"}
|
||||||
row.append(status_map[status])
|
row.append(status_map[status])
|
||||||
|
|
||||||
if status == "Present":
|
if status == "Present":
|
||||||
total_p += 1
|
total_p += 1
|
||||||
elif status == "Absent":
|
elif status == "Absent":
|
||||||
total_a += 1
|
total_a += 1
|
||||||
date = add_days(date, 1)
|
date = add_days(date, 1)
|
||||||
|
|
||||||
row += [total_p, total_a]
|
row += [total_p, total_a]
|
||||||
data.append(row)
|
data.append(row)
|
||||||
return columns, data
|
return columns, data
|
||||||
@ -63,14 +71,19 @@ def get_attendance_list(from_date, to_date, student_group, students_list):
|
|||||||
and date between %s and %s
|
and date between %s and %s
|
||||||
order by student, date''',
|
order by student, date''',
|
||||||
(student_group, from_date, to_date), as_dict=1)
|
(student_group, from_date, to_date), as_dict=1)
|
||||||
|
|
||||||
att_map = {}
|
att_map = {}
|
||||||
students_with_leave_application = get_students_with_leave_application(from_date, to_date, students_list)
|
students_with_leave_application = get_students_with_leave_application(from_date, to_date, students_list)
|
||||||
for d in attendance_list:
|
for d in attendance_list:
|
||||||
att_map.setdefault(d.student, frappe._dict()).setdefault(d.date, "")
|
att_map.setdefault(d.student, frappe._dict()).setdefault(d.date, "")
|
||||||
|
|
||||||
if students_with_leave_application.get(d.date) and d.student in students_with_leave_application.get(d.date):
|
if students_with_leave_application.get(d.date) and d.student in students_with_leave_application.get(d.date):
|
||||||
att_map[d.student][d.date] = "Present"
|
att_map[d.student][d.date] = "Present"
|
||||||
else:
|
else:
|
||||||
att_map[d.student][d.date] = d.status
|
att_map[d.student][d.date] = d.status
|
||||||
|
|
||||||
|
att_map = mark_holidays(att_map, from_date, to_date, students_list)
|
||||||
|
|
||||||
return att_map
|
return att_map
|
||||||
|
|
||||||
def get_students_with_leave_application(from_date, to_date, students_list):
|
def get_students_with_leave_application(from_date, to_date, students_list):
|
||||||
@ -108,3 +121,14 @@ def get_attendance_years():
|
|||||||
if not year_list:
|
if not year_list:
|
||||||
year_list = [getdate().year]
|
year_list = [getdate().year]
|
||||||
return "\n".join(str(year) for year in year_list)
|
return "\n".join(str(year) for year in year_list)
|
||||||
|
|
||||||
|
def mark_holidays(att_map, from_date, to_date, students_list):
|
||||||
|
holiday_list = get_holiday_list()
|
||||||
|
holidays = get_holidays(holiday_list)
|
||||||
|
|
||||||
|
for dt in daterange(getdate(from_date), getdate(to_date)):
|
||||||
|
if dt in holidays:
|
||||||
|
for student in students_list:
|
||||||
|
att_map.setdefault(student, frappe._dict()).setdefault(dt, "Holiday")
|
||||||
|
|
||||||
|
return att_map
|
||||||
|
@ -2,12 +2,13 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
import json
|
import json
|
||||||
from frappe.utils import cstr, cint, nowdate, flt
|
from frappe.utils import cstr, cint, nowdate, getdate, flt, get_request_session, get_datetime
|
||||||
from erpnext.erpnext_integrations.utils import validate_webhooks_request
|
from erpnext.erpnext_integrations.utils import validate_webhooks_request
|
||||||
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note, make_sales_invoice
|
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note, make_sales_invoice
|
||||||
from erpnext.erpnext_integrations.doctype.shopify_settings.sync_product import sync_item_from_shopify
|
from erpnext.erpnext_integrations.doctype.shopify_settings.sync_product import sync_item_from_shopify
|
||||||
from erpnext.erpnext_integrations.doctype.shopify_settings.sync_customer import create_customer
|
from erpnext.erpnext_integrations.doctype.shopify_settings.sync_customer import create_customer
|
||||||
from erpnext.erpnext_integrations.doctype.shopify_log.shopify_log import make_shopify_log, dump_request_data
|
from erpnext.erpnext_integrations.doctype.shopify_log.shopify_log import make_shopify_log, dump_request_data
|
||||||
|
from erpnext.erpnext_integrations.doctype.shopify_settings.shopify_settings import get_shopify_url, get_header
|
||||||
|
|
||||||
@frappe.whitelist(allow_guest=True)
|
@frappe.whitelist(allow_guest=True)
|
||||||
@validate_webhooks_request("Shopify Settings", 'X-Shopify-Hmac-Sha256', secret_key='shared_secret')
|
@validate_webhooks_request("Shopify Settings", 'X-Shopify-Hmac-Sha256', secret_key='shared_secret')
|
||||||
@ -18,7 +19,7 @@ def store_request_data(order=None, event=None):
|
|||||||
|
|
||||||
dump_request_data(order, event)
|
dump_request_data(order, event)
|
||||||
|
|
||||||
def sync_sales_order(order, request_id=None):
|
def sync_sales_order(order, request_id=None, old_order_sync=False):
|
||||||
frappe.set_user('Administrator')
|
frappe.set_user('Administrator')
|
||||||
shopify_settings = frappe.get_doc("Shopify Settings")
|
shopify_settings = frappe.get_doc("Shopify Settings")
|
||||||
frappe.flags.request_id = request_id
|
frappe.flags.request_id = request_id
|
||||||
@ -27,7 +28,7 @@ def sync_sales_order(order, request_id=None):
|
|||||||
try:
|
try:
|
||||||
validate_customer(order, shopify_settings)
|
validate_customer(order, shopify_settings)
|
||||||
validate_item(order, shopify_settings)
|
validate_item(order, shopify_settings)
|
||||||
create_order(order, shopify_settings)
|
create_order(order, shopify_settings, old_order_sync=old_order_sync)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
make_shopify_log(status="Error", exception=e)
|
make_shopify_log(status="Error", exception=e)
|
||||||
|
|
||||||
@ -77,13 +78,13 @@ def validate_item(order, shopify_settings):
|
|||||||
if item.get("product_id") and not frappe.db.get_value("Item", {"shopify_product_id": item.get("product_id")}, "name"):
|
if item.get("product_id") and not frappe.db.get_value("Item", {"shopify_product_id": item.get("product_id")}, "name"):
|
||||||
sync_item_from_shopify(shopify_settings, item)
|
sync_item_from_shopify(shopify_settings, item)
|
||||||
|
|
||||||
def create_order(order, shopify_settings, company=None):
|
def create_order(order, shopify_settings, old_order_sync=False, company=None):
|
||||||
so = create_sales_order(order, shopify_settings, company)
|
so = create_sales_order(order, shopify_settings, company)
|
||||||
if so:
|
if so:
|
||||||
if order.get("financial_status") == "paid":
|
if order.get("financial_status") == "paid":
|
||||||
create_sales_invoice(order, shopify_settings, so)
|
create_sales_invoice(order, shopify_settings, so, old_order_sync=old_order_sync)
|
||||||
|
|
||||||
if order.get("fulfillments"):
|
if order.get("fulfillments") and not old_order_sync:
|
||||||
create_delivery_note(order, shopify_settings, so)
|
create_delivery_note(order, shopify_settings, so)
|
||||||
|
|
||||||
def create_sales_order(shopify_order, shopify_settings, company=None):
|
def create_sales_order(shopify_order, shopify_settings, company=None):
|
||||||
@ -92,7 +93,7 @@ def create_sales_order(shopify_order, shopify_settings, company=None):
|
|||||||
so = frappe.db.get_value("Sales Order", {"shopify_order_id": shopify_order.get("id")}, "name")
|
so = frappe.db.get_value("Sales Order", {"shopify_order_id": shopify_order.get("id")}, "name")
|
||||||
|
|
||||||
if not so:
|
if not so:
|
||||||
items = get_order_items(shopify_order.get("line_items"), shopify_settings)
|
items = get_order_items(shopify_order.get("line_items"), shopify_settings, getdate(shopify_order.get('created_at')))
|
||||||
|
|
||||||
if not items:
|
if not items:
|
||||||
message = 'Following items exists in the shopify order but relevant records were not found in the shopify Product master'
|
message = 'Following items exists in the shopify order but relevant records were not found in the shopify Product master'
|
||||||
@ -106,8 +107,10 @@ def create_sales_order(shopify_order, shopify_settings, company=None):
|
|||||||
"doctype": "Sales Order",
|
"doctype": "Sales Order",
|
||||||
"naming_series": shopify_settings.sales_order_series or "SO-Shopify-",
|
"naming_series": shopify_settings.sales_order_series or "SO-Shopify-",
|
||||||
"shopify_order_id": shopify_order.get("id"),
|
"shopify_order_id": shopify_order.get("id"),
|
||||||
|
"shopify_order_number": shopify_order.get("name"),
|
||||||
"customer": customer or shopify_settings.default_customer,
|
"customer": customer or shopify_settings.default_customer,
|
||||||
"delivery_date": nowdate(),
|
"transaction_date": getdate(shopify_order.get("created_at")) or nowdate(),
|
||||||
|
"delivery_date": getdate(shopify_order.get("created_at")) or nowdate(),
|
||||||
"company": shopify_settings.company,
|
"company": shopify_settings.company,
|
||||||
"selling_price_list": shopify_settings.price_list,
|
"selling_price_list": shopify_settings.price_list,
|
||||||
"ignore_pricing_rule": 1,
|
"ignore_pricing_rule": 1,
|
||||||
@ -132,32 +135,42 @@ def create_sales_order(shopify_order, shopify_settings, company=None):
|
|||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
return so
|
return so
|
||||||
|
|
||||||
def create_sales_invoice(shopify_order, shopify_settings, so):
|
def create_sales_invoice(shopify_order, shopify_settings, so, old_order_sync=False):
|
||||||
if not frappe.db.get_value("Sales Invoice", {"shopify_order_id": shopify_order.get("id")}, "name")\
|
if not frappe.db.get_value("Sales Invoice", {"shopify_order_id": shopify_order.get("id")}, "name")\
|
||||||
and so.docstatus==1 and not so.per_billed and cint(shopify_settings.sync_sales_invoice):
|
and so.docstatus==1 and not so.per_billed and cint(shopify_settings.sync_sales_invoice):
|
||||||
|
|
||||||
|
if old_order_sync:
|
||||||
|
posting_date = getdate(shopify_order.get('created_at'))
|
||||||
|
else:
|
||||||
|
posting_date = nowdate()
|
||||||
|
|
||||||
si = make_sales_invoice(so.name, ignore_permissions=True)
|
si = make_sales_invoice(so.name, ignore_permissions=True)
|
||||||
si.shopify_order_id = shopify_order.get("id")
|
si.shopify_order_id = shopify_order.get("id")
|
||||||
|
si.shopify_order_number = shopify_order.get("name")
|
||||||
|
si.set_posting_time = 1
|
||||||
|
si.posting_date = posting_date
|
||||||
|
si.due_date = posting_date
|
||||||
si.naming_series = shopify_settings.sales_invoice_series or "SI-Shopify-"
|
si.naming_series = shopify_settings.sales_invoice_series or "SI-Shopify-"
|
||||||
si.flags.ignore_mandatory = True
|
si.flags.ignore_mandatory = True
|
||||||
set_cost_center(si.items, shopify_settings.cost_center)
|
set_cost_center(si.items, shopify_settings.cost_center)
|
||||||
si.insert(ignore_mandatory=True)
|
si.insert(ignore_mandatory=True)
|
||||||
si.submit()
|
si.submit()
|
||||||
make_payament_entry_against_sales_invoice(si, shopify_settings)
|
make_payament_entry_against_sales_invoice(si, shopify_settings, posting_date)
|
||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
|
|
||||||
def set_cost_center(items, cost_center):
|
def set_cost_center(items, cost_center):
|
||||||
for item in items:
|
for item in items:
|
||||||
item.cost_center = cost_center
|
item.cost_center = cost_center
|
||||||
|
|
||||||
def make_payament_entry_against_sales_invoice(doc, shopify_settings):
|
def make_payament_entry_against_sales_invoice(doc, shopify_settings, posting_date=None):
|
||||||
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
||||||
payemnt_entry = get_payment_entry(doc.doctype, doc.name, bank_account=shopify_settings.cash_bank_account)
|
payment_entry = get_payment_entry(doc.doctype, doc.name, bank_account=shopify_settings.cash_bank_account)
|
||||||
payemnt_entry.flags.ignore_mandatory = True
|
payment_entry.flags.ignore_mandatory = True
|
||||||
payemnt_entry.reference_no = doc.name
|
payment_entry.reference_no = doc.name
|
||||||
payemnt_entry.reference_date = nowdate()
|
payment_entry.posting_date = posting_date or nowdate()
|
||||||
payemnt_entry.insert(ignore_permissions=True)
|
payment_entry.reference_date = posting_date or nowdate()
|
||||||
payemnt_entry.submit()
|
payment_entry.insert(ignore_permissions=True)
|
||||||
|
payment_entry.submit()
|
||||||
|
|
||||||
def create_delivery_note(shopify_order, shopify_settings, so):
|
def create_delivery_note(shopify_order, shopify_settings, so):
|
||||||
if not cint(shopify_settings.sync_delivery_note):
|
if not cint(shopify_settings.sync_delivery_note):
|
||||||
@ -169,6 +182,9 @@ def create_delivery_note(shopify_order, shopify_settings, so):
|
|||||||
|
|
||||||
dn = make_delivery_note(so.name)
|
dn = make_delivery_note(so.name)
|
||||||
dn.shopify_order_id = fulfillment.get("order_id")
|
dn.shopify_order_id = fulfillment.get("order_id")
|
||||||
|
dn.shopify_order_number = shopify_order.get("name")
|
||||||
|
dn.set_posting_time = 1
|
||||||
|
dn.posting_date = getdate(fulfillment.get("created_at"))
|
||||||
dn.shopify_fulfillment_id = fulfillment.get("id")
|
dn.shopify_fulfillment_id = fulfillment.get("id")
|
||||||
dn.naming_series = shopify_settings.delivery_note_series or "DN-Shopify-"
|
dn.naming_series = shopify_settings.delivery_note_series or "DN-Shopify-"
|
||||||
dn.items = get_fulfillment_items(dn.items, fulfillment.get("line_items"), shopify_settings)
|
dn.items = get_fulfillment_items(dn.items, fulfillment.get("line_items"), shopify_settings)
|
||||||
@ -187,7 +203,7 @@ def get_discounted_amount(order):
|
|||||||
discounted_amount += flt(discount.get("amount"))
|
discounted_amount += flt(discount.get("amount"))
|
||||||
return discounted_amount
|
return discounted_amount
|
||||||
|
|
||||||
def get_order_items(order_items, shopify_settings):
|
def get_order_items(order_items, shopify_settings, delivery_date):
|
||||||
items = []
|
items = []
|
||||||
all_product_exists = True
|
all_product_exists = True
|
||||||
product_not_exists = []
|
product_not_exists = []
|
||||||
@ -205,7 +221,7 @@ def get_order_items(order_items, shopify_settings):
|
|||||||
"item_code": item_code,
|
"item_code": item_code,
|
||||||
"item_name": shopify_item.get("name"),
|
"item_name": shopify_item.get("name"),
|
||||||
"rate": shopify_item.get("price"),
|
"rate": shopify_item.get("price"),
|
||||||
"delivery_date": nowdate(),
|
"delivery_date": delivery_date,
|
||||||
"qty": shopify_item.get("quantity"),
|
"qty": shopify_item.get("quantity"),
|
||||||
"stock_uom": shopify_item.get("uom") or _("Nos"),
|
"stock_uom": shopify_item.get("uom") or _("Nos"),
|
||||||
"warehouse": shopify_settings.warehouse
|
"warehouse": shopify_settings.warehouse
|
||||||
@ -265,3 +281,64 @@ def get_tax_account_head(tax):
|
|||||||
frappe.throw(_("Tax Account not specified for Shopify Tax {0}").format(tax.get("title")))
|
frappe.throw(_("Tax Account not specified for Shopify Tax {0}").format(tax.get("title")))
|
||||||
|
|
||||||
return tax_account
|
return tax_account
|
||||||
|
|
||||||
|
@frappe.whitelist(allow_guest=True)
|
||||||
|
def sync_old_orders():
|
||||||
|
frappe.set_user('Administrator')
|
||||||
|
shopify_settings = frappe.get_doc('Shopify Settings')
|
||||||
|
|
||||||
|
if not shopify_settings.sync_missing_orders:
|
||||||
|
return
|
||||||
|
|
||||||
|
url = get_url(shopify_settings)
|
||||||
|
session = get_request_session()
|
||||||
|
|
||||||
|
try:
|
||||||
|
res = session.get(url, headers=get_header(shopify_settings))
|
||||||
|
res.raise_for_status()
|
||||||
|
orders = res.json()["orders"]
|
||||||
|
|
||||||
|
for order in orders:
|
||||||
|
if is_sync_complete(shopify_settings, order):
|
||||||
|
stop_sync(shopify_settings)
|
||||||
|
return
|
||||||
|
|
||||||
|
sync_sales_order(order=order, old_order_sync=True)
|
||||||
|
last_order_id = order.get('id')
|
||||||
|
|
||||||
|
if last_order_id:
|
||||||
|
shopify_settings.load_from_db()
|
||||||
|
shopify_settings.last_order_id = last_order_id
|
||||||
|
shopify_settings.save()
|
||||||
|
frappe.db.commit()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
raise e
|
||||||
|
|
||||||
|
def stop_sync(shopify_settings):
|
||||||
|
shopify_settings.sync_missing_orders = 0
|
||||||
|
shopify_settings.last_order_id = ''
|
||||||
|
shopify_settings.save()
|
||||||
|
frappe.db.commit()
|
||||||
|
|
||||||
|
def get_url(shopify_settings):
|
||||||
|
last_order_id = shopify_settings.last_order_id
|
||||||
|
|
||||||
|
if not last_order_id:
|
||||||
|
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(
|
||||||
|
get_datetime(shopify_settings.from_date)), shopify_settings)
|
||||||
|
else:
|
||||||
|
url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&since_id={0}".format(
|
||||||
|
shopify_settings.from_order_id), shopify_settings)
|
||||||
|
else:
|
||||||
|
url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&since_id={0}".format(last_order_id), shopify_settings)
|
||||||
|
|
||||||
|
return url
|
||||||
|
|
||||||
|
def is_sync_complete(shopify_settings, order):
|
||||||
|
if shopify_settings.sync_based_on == 'Date':
|
||||||
|
return getdate(shopify_settings.to_date) < getdate(order.get('created_at'))
|
||||||
|
else:
|
||||||
|
return cstr(order.get('id')) == cstr(shopify_settings.to_order_id)
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
{
|
{
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"label": "Payments",
|
"label": "Payments",
|
||||||
"links": "[\n {\n \"description\": \"GoCardless payment gateway settings\",\n \"label\": \"GoCardless Settings\",\n \"name\": \"GoCardless Settings\",\n \"type\": \"doctype\"\n }\n]"
|
"links": "[\n {\n \"description\": \"GoCardless payment gateway settings\",\n \"label\": \"GoCardless Settings\",\n \"name\": \"GoCardless Settings\",\n \"type\": \"doctype\"\n }, {\n \"description\": \"M-Pesa payment gateway settings\",\n \"label\": \"M-Pesa Settings\",\n \"name\": \"Mpesa Settings\",\n \"type\": \"doctype\"\n }\n]"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -29,7 +29,7 @@
|
|||||||
"idx": 0,
|
"idx": 0,
|
||||||
"is_standard": 1,
|
"is_standard": 1,
|
||||||
"label": "ERPNext Integrations",
|
"label": "ERPNext Integrations",
|
||||||
"modified": "2020-08-23 16:30:51.494655",
|
"modified": "2020-10-29 19:54:46.228222",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "ERPNext Integrations",
|
"module": "ERPNext Integrations",
|
||||||
"name": "ERPNext Integrations",
|
"name": "ERPNext Integrations",
|
||||||
|
@ -9,11 +9,12 @@ frappe.ui.form.on('Mpesa Settings', {
|
|||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
frappe.realtime.on("refresh_mpesa_dashboard", function(){
|
frappe.realtime.on("refresh_mpesa_dashboard", function(){
|
||||||
frm.reload_doc();
|
frm.reload_doc();
|
||||||
|
frm.events.setup_account_balance_html(frm);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
get_account_balance: function(frm) {
|
get_account_balance: function(frm) {
|
||||||
if (!frm.initiator_name && !frm.security_credentials) {
|
if (!frm.doc.initiator_name && !frm.doc.security_credential) {
|
||||||
frappe.throw(__("Please set the initiator name and the security credential"));
|
frappe.throw(__("Please set the initiator name and the security credential"));
|
||||||
}
|
}
|
||||||
frappe.call({
|
frappe.call({
|
||||||
|
@ -147,7 +147,7 @@ def get_account_balance(request_payload):
|
|||||||
return response
|
return response
|
||||||
except Exception:
|
except Exception:
|
||||||
frappe.log_error(title=_("Account Balance Processing Error"))
|
frappe.log_error(title=_("Account Balance Processing Error"))
|
||||||
frappe.throw(title=_("Error"), message=_("Please check your configuration and try again"))
|
frappe.throw(_("Please check your configuration and try again"), title=_("Error"))
|
||||||
|
|
||||||
@frappe.whitelist(allow_guest=True)
|
@frappe.whitelist(allow_guest=True)
|
||||||
def process_balance_info(**kwargs):
|
def process_balance_info(**kwargs):
|
||||||
@ -173,7 +173,8 @@ def process_balance_info(**kwargs):
|
|||||||
ref_doc.db_set("account_balance", balance_info)
|
ref_doc.db_set("account_balance", balance_info)
|
||||||
|
|
||||||
request.handle_success(account_balance_response)
|
request.handle_success(account_balance_response)
|
||||||
frappe.publish_realtime("refresh_mpesa_dashboard")
|
frappe.publish_realtime("refresh_mpesa_dashboard", doctype="Mpesa Settings",
|
||||||
|
docname=transaction_data.reference_docname, user=transaction_data.owner)
|
||||||
except Exception:
|
except Exception:
|
||||||
request.handle_failure(account_balance_response)
|
request.handle_failure(account_balance_response)
|
||||||
frappe.log_error(title=_("Mpesa Account Balance Processing Error"), message=account_balance_response)
|
frappe.log_error(title=_("Mpesa Account Balance Processing Error"), message=account_balance_response)
|
||||||
|
@ -31,6 +31,7 @@ class PlaidConnector():
|
|||||||
return access_token
|
return access_token
|
||||||
|
|
||||||
def get_link_token(self):
|
def get_link_token(self):
|
||||||
|
country_codes = ["US", "CA", "FR", "IE", "NL", "ES", "GB"] if self.settings.enable_european_access else ["US", "CA"]
|
||||||
token_request = {
|
token_request = {
|
||||||
"client_name": self.client_name,
|
"client_name": self.client_name,
|
||||||
"client_id": self.settings.plaid_client_id,
|
"client_id": self.settings.plaid_client_id,
|
||||||
@ -38,7 +39,7 @@ class PlaidConnector():
|
|||||||
"products": self.products,
|
"products": self.products,
|
||||||
# only allow Plaid-supported languages and countries (LAST: Sep-19-2020)
|
# only allow Plaid-supported languages and countries (LAST: Sep-19-2020)
|
||||||
"language": frappe.local.lang if frappe.local.lang in ["en", "fr", "es", "nl"] else "en",
|
"language": frappe.local.lang if frappe.local.lang in ["en", "fr", "es", "nl"] else "en",
|
||||||
"country_codes": ["US", "CA", "FR", "IE", "NL", "ES", "GB"],
|
"country_codes": country_codes,
|
||||||
"user": {
|
"user": {
|
||||||
"client_user_id": frappe.generate_hash(frappe.session.user, length=32)
|
"client_user_id": frappe.generate_hash(frappe.session.user, length=32)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"creation": "2018-10-25 10:02:48.656165",
|
"creation": "2018-10-25 10:02:48.656165",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
@ -11,7 +12,8 @@
|
|||||||
"plaid_client_id",
|
"plaid_client_id",
|
||||||
"plaid_secret",
|
"plaid_secret",
|
||||||
"column_break_7",
|
"column_break_7",
|
||||||
"plaid_env"
|
"plaid_env",
|
||||||
|
"enable_european_access"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -58,10 +60,17 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "column_break_7",
|
"fieldname": "column_break_7",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "enable_european_access",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Enable European Access"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"modified": "2020-09-12 02:31:44.542385",
|
"links": [],
|
||||||
|
"modified": "2020-10-29 20:24:56.916104",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "ERPNext Integrations",
|
"module": "ERPNext Integrations",
|
||||||
"name": "Plaid Settings",
|
"name": "Plaid Settings",
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"creation": "2015-05-18 05:21:07.270859",
|
"creation": "2015-05-18 05:21:07.270859",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "System",
|
"document_type": "System",
|
||||||
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"status_html",
|
"status_html",
|
||||||
"enable_shopify",
|
"enable_shopify",
|
||||||
@ -40,7 +42,16 @@
|
|||||||
"sales_invoice_series",
|
"sales_invoice_series",
|
||||||
"section_break_22",
|
"section_break_22",
|
||||||
"html_16",
|
"html_16",
|
||||||
"taxes"
|
"taxes",
|
||||||
|
"syncing_details_section",
|
||||||
|
"sync_missing_orders",
|
||||||
|
"sync_based_on",
|
||||||
|
"column_break_41",
|
||||||
|
"from_date",
|
||||||
|
"to_date",
|
||||||
|
"from_order_id",
|
||||||
|
"to_order_id",
|
||||||
|
"last_order_id"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -255,10 +266,71 @@
|
|||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"label": "Shopify Tax Account",
|
"label": "Shopify Tax Account",
|
||||||
"options": "Shopify Tax Account"
|
"options": "Shopify Tax Account"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapsible": 1,
|
||||||
|
"fieldname": "syncing_details_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Syncing Missing Orders"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:doc.sync_missing_orders",
|
||||||
|
"fieldname": "last_order_id",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Last Order Id",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_41",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"description": "On checking this Order from the ",
|
||||||
|
"fieldname": "sync_missing_orders",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Sync Missing Old Shopify Orders"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:doc.sync_missing_orders",
|
||||||
|
"fieldname": "sync_based_on",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "Sync Based On",
|
||||||
|
"mandatory_depends_on": "eval:doc.sync_missing_orders",
|
||||||
|
"options": "\nDate\nShopify Order Id"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:doc.sync_based_on == 'Date' && doc.sync_missing_orders",
|
||||||
|
"fieldname": "from_date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"label": "From Date",
|
||||||
|
"mandatory_depends_on": "eval:doc.sync_based_on == 'Date' && doc.sync_missing_orders"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:doc.sync_based_on == 'Date' && doc.sync_missing_orders",
|
||||||
|
"fieldname": "to_date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"label": "To Date",
|
||||||
|
"mandatory_depends_on": "eval:doc.sync_based_on == 'Date' && doc.sync_missing_orders"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:doc.sync_based_on == 'Shopify Order Id' && doc.sync_missing_orders",
|
||||||
|
"fieldname": "from_order_id",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "From Order Id",
|
||||||
|
"mandatory_depends_on": "eval:doc.sync_based_on == 'Shopify Order Id' && doc.sync_missing_orders"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:doc.sync_based_on == 'Shopify Order Id' && doc.sync_missing_orders",
|
||||||
|
"fieldname": "to_order_id",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "To Order Id",
|
||||||
|
"mandatory_depends_on": "eval:doc.sync_based_on == 'Shopify Order Id' && doc.sync_missing_orders"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"modified": "2020-09-18 17:26:09.703215",
|
"links": [],
|
||||||
|
"modified": "2020-11-05 20:44:03.664891",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "ERPNext Integrations",
|
"module": "ERPNext Integrations",
|
||||||
"name": "Shopify Settings",
|
"name": "Shopify Settings",
|
||||||
|
@ -87,7 +87,7 @@ def get_shopify_url(path, settings):
|
|||||||
def get_header(settings):
|
def get_header(settings):
|
||||||
header = {'Content-Type': 'application/json'}
|
header = {'Content-Type': 'application/json'}
|
||||||
|
|
||||||
return header;
|
return header
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_series():
|
def get_series():
|
||||||
@ -121,17 +121,23 @@ def setup_custom_fields():
|
|||||||
],
|
],
|
||||||
"Sales Order": [
|
"Sales Order": [
|
||||||
dict(fieldname='shopify_order_id', label='Shopify Order Id',
|
dict(fieldname='shopify_order_id', label='Shopify Order Id',
|
||||||
fieldtype='Data', insert_after='title', read_only=1, print_hide=1)
|
fieldtype='Data', insert_after='title', read_only=1, print_hide=1),
|
||||||
|
dict(fieldname='shopify_order_number', label='Shopify Order Number',
|
||||||
|
fieldtype='Data', insert_after='shopify_order_id', read_only=1, print_hide=1)
|
||||||
],
|
],
|
||||||
"Delivery Note":[
|
"Delivery Note":[
|
||||||
dict(fieldname='shopify_order_id', label='Shopify Order Id',
|
dict(fieldname='shopify_order_id', label='Shopify Order Id',
|
||||||
fieldtype='Data', insert_after='title', read_only=1, print_hide=1),
|
fieldtype='Data', insert_after='title', read_only=1, print_hide=1),
|
||||||
|
dict(fieldname='shopify_order_number', label='Shopify Order Number',
|
||||||
|
fieldtype='Data', insert_after='shopify_order_id', read_only=1, print_hide=1),
|
||||||
dict(fieldname='shopify_fulfillment_id', label='Shopify Fulfillment Id',
|
dict(fieldname='shopify_fulfillment_id', label='Shopify Fulfillment Id',
|
||||||
fieldtype='Data', insert_after='title', read_only=1, print_hide=1)
|
fieldtype='Data', insert_after='title', read_only=1, print_hide=1)
|
||||||
],
|
],
|
||||||
"Sales Invoice": [
|
"Sales Invoice": [
|
||||||
dict(fieldname='shopify_order_id', label='Shopify Order Id',
|
dict(fieldname='shopify_order_id', label='Shopify Order Id',
|
||||||
fieldtype='Data', insert_after='title', read_only=1, print_hide=1)
|
fieldtype='Data', insert_after='title', read_only=1, print_hide=1),
|
||||||
|
dict(fieldname='shopify_order_number', label='Shopify Order Number',
|
||||||
|
fieldtype='Data', insert_after='shopify_order_id', read_only=1, print_hide=1)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user