Merge branch 'develop' of github.com:frappe/erpnext into refactor-call-popup
This commit is contained in:
commit
35c4b78e66
101
.travis.yml
101
.travis.yml
@ -1,51 +1,80 @@
|
||||
language: python
|
||||
dist: trusty
|
||||
|
||||
python:
|
||||
- "2.7"
|
||||
- "3.6"
|
||||
language: python
|
||||
|
||||
env:
|
||||
- TEST_TYPE="Server Side Test"
|
||||
- TEST_TYPE="Patch Test"
|
||||
git:
|
||||
depth: 1
|
||||
|
||||
services:
|
||||
- mysql
|
||||
cache:
|
||||
- pip
|
||||
|
||||
addons:
|
||||
hosts: test_site
|
||||
mariadb: 10.3
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- name: "Python 2.7 Server Side Test"
|
||||
python: 2.7
|
||||
script: bench --site test_site run-tests --app erpnext --coverage
|
||||
|
||||
- name: "Python 3.6 Server Side Test"
|
||||
python: 3.6
|
||||
script: bench --site test_site run-tests --app erpnext --coverage
|
||||
|
||||
- name: "Python 2.7 Patch Test"
|
||||
python: 2.7
|
||||
before_script:
|
||||
- wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
|
||||
- bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz
|
||||
script: bench --site test_site migrate
|
||||
|
||||
- name: "Python 3.6 Patch Test"
|
||||
python: 3.6
|
||||
before_script:
|
||||
- wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
|
||||
- bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz
|
||||
script: bench --site test_site migrate
|
||||
|
||||
install:
|
||||
# fix mongodb travis error
|
||||
- sudo rm /etc/apt/sources.list.d/mongodb*.list
|
||||
- pip install flake8==3.3.0
|
||||
- flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
|
||||
- sudo rm /etc/apt/sources.list.d/docker.list
|
||||
- sudo apt-get install hhvm && rm -rf /home/travis/.kiex/
|
||||
- sudo apt-get purge -y mysql-common mysql-server mysql-client
|
||||
- cd ~
|
||||
- nvm install 10
|
||||
- pip install python-coveralls
|
||||
- wget https://raw.githubusercontent.com/frappe/bench/master/playbooks/install.py
|
||||
- sudo python install.py --develop --user travis --without-bench-setup
|
||||
- sudo pip install -e ~/bench
|
||||
|
||||
- rm $TRAVIS_BUILD_DIR/.git/shallow
|
||||
- bash $TRAVIS_BUILD_DIR/travis/bench_init.sh
|
||||
- cp -r $TRAVIS_BUILD_DIR/test_sites/test_site ~/frappe-bench/sites/
|
||||
- git clone https://github.com/frappe/bench --depth 1
|
||||
- pip install -e ./bench
|
||||
|
||||
before_script:
|
||||
- mysql -u root -ptravis -e 'create database test_frappe'
|
||||
- echo "USE mysql;\nCREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe';\nFLUSH PRIVILEGES;\n" | mysql -u root -ptravis
|
||||
- echo "USE mysql;\nGRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost';\n" | mysql -u root -ptravis
|
||||
- git clone https://github.com/frappe/frappe --branch $TRAVIS_BRANCH --depth 1
|
||||
- bench init --skip-assets --frappe-path ~/frappe --python $(which python) frappe-bench
|
||||
|
||||
- mkdir ~/frappe-bench/sites/test_site
|
||||
- cp -r $TRAVIS_BUILD_DIR/.travis/site_config.json ~/frappe-bench/sites/test_site/
|
||||
|
||||
- mysql -u root -e "SET GLOBAL character_set_server = 'utf8mb4'"
|
||||
- mysql -u root -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'"
|
||||
|
||||
- mysql -u root -e "CREATE DATABASE test_frappe"
|
||||
- mysql -u root -e "CREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe'"
|
||||
- mysql -u root -e "GRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost'"
|
||||
|
||||
- mysql -u root -e "UPDATE mysql.user SET Password=PASSWORD('travis') WHERE User='root'"
|
||||
- mysql -u root -e "FLUSH PRIVILEGES"
|
||||
|
||||
- wget -O /tmp/wkhtmltox.tar.xz https://github.com/frappe/wkhtmltopdf/raw/master/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
|
||||
- tar -xf /tmp/wkhtmltox.tar.xz -C /tmp
|
||||
- sudo mv /tmp/wkhtmltox/bin/wkhtmltopdf /usr/local/bin/wkhtmltopdf
|
||||
- sudo chmod o+x /usr/local/bin/wkhtmltopdf
|
||||
|
||||
- cd ~/frappe-bench
|
||||
- bench get-app erpnext $TRAVIS_BUILD_DIR
|
||||
- bench use test_site
|
||||
- bench reinstall --mariadb-root-username root --mariadb-root-password travis --yes
|
||||
- bench scheduler disable
|
||||
- sed -i 's/9000/9001/g' sites/common_site_config.json
|
||||
- bench start &
|
||||
- sleep 10
|
||||
|
||||
script:
|
||||
- bash $TRAVIS_BUILD_DIR/travis/run-tests.sh
|
||||
- sed -i 's/watch:/# watch:/g' Procfile
|
||||
- sed -i 's/schedule:/# schedule:/g' Procfile
|
||||
- sed -i 's/socketio:/# socketio:/g' Procfile
|
||||
- sed -i 's/redis_socketio:/# redis_socketio:/g' Procfile
|
||||
|
||||
- bench get-app erpnext $TRAVIS_BUILD_DIR
|
||||
- bench start &
|
||||
- bench --site test_site reinstall --yes
|
||||
|
||||
after_script:
|
||||
- pip install python-coveralls
|
||||
- coveralls -b apps/erpnext -d ../../sites/.coverage
|
||||
|
@ -6,8 +6,8 @@
|
||||
"mail_login": "test@example.com",
|
||||
"mail_password": "test",
|
||||
"admin_password": "admin",
|
||||
"run_selenium_tests": 1,
|
||||
"root_login": "root",
|
||||
"root_password": "travis",
|
||||
"host_name": "http://localhost:8000",
|
||||
"host_name": "http://test_site:8000",
|
||||
"install_apps": ["erpnext"]
|
||||
}
|
@ -123,7 +123,9 @@ class Account(NestedSet):
|
||||
doc.flags.ignore_root_company_validation = True
|
||||
doc.update({
|
||||
"company": company,
|
||||
"account_currency": None,
|
||||
# parent account's currency should be passed down to child account's curreny
|
||||
# if it is None, it picks it up from default company currency, which might be unintended
|
||||
"account_currency": self.account_currency,
|
||||
"parent_account": parent_acc_name_map[company]
|
||||
})
|
||||
doc.save()
|
||||
|
@ -4,45 +4,52 @@
|
||||
frappe.ui.form.on('Accounting Dimension', {
|
||||
|
||||
refresh: function(frm) {
|
||||
if (!frm.is_new()) {
|
||||
frm.add_custom_button(__('Show {0}', [frm.doc.document_type]), function () {
|
||||
frappe.set_route("List", frm.doc.document_type);
|
||||
});
|
||||
}
|
||||
|
||||
frm.set_query('document_type', () => {
|
||||
return {
|
||||
filters: {
|
||||
name: ['not in', ['Accounting Dimension', 'Project', 'Cost Center']]
|
||||
name: ['not in', ['Accounting Dimension', 'Project', 'Cost Center', 'Accounting Dimension Detail']]
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
let button = frm.doc.disabled ? "Enable" : "Disable";
|
||||
|
||||
frm.add_custom_button(__(button), function() {
|
||||
|
||||
frm.set_value('disabled', 1 - frm.doc.disabled);
|
||||
|
||||
frappe.call({
|
||||
method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.disable_dimension",
|
||||
args: {
|
||||
doc: frm.doc
|
||||
},
|
||||
freeze: true,
|
||||
callback: function(r) {
|
||||
let message = frm.doc.disabled ? "Dimension Disabled" : "Dimension Enabled";
|
||||
frm.save();
|
||||
frappe.show_alert({message:__(message), indicator:'green'});
|
||||
}
|
||||
if (!frm.is_new()) {
|
||||
frm.add_custom_button(__('Show {0}', [frm.doc.document_type]), function () {
|
||||
frappe.set_route("List", frm.doc.document_type);
|
||||
});
|
||||
});
|
||||
|
||||
let button = frm.doc.disabled ? "Enable" : "Disable";
|
||||
|
||||
frm.add_custom_button(__(button), function() {
|
||||
|
||||
frm.set_value('disabled', 1 - frm.doc.disabled);
|
||||
|
||||
frappe.call({
|
||||
method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.disable_dimension",
|
||||
args: {
|
||||
doc: frm.doc
|
||||
},
|
||||
freeze: true,
|
||||
callback: function(r) {
|
||||
let message = frm.doc.disabled ? "Dimension Disabled" : "Dimension Enabled";
|
||||
frm.save();
|
||||
frappe.show_alert({message:__(message), indicator:'green'});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
document_type: function(frm) {
|
||||
|
||||
frm.set_value('label', frm.doc.document_type);
|
||||
frm.set_value('fieldname', frappe.model.scrub(frm.doc.document_type));
|
||||
|
||||
if (frm.is_new()){
|
||||
let row = frappe.model.add_child(frm.doc, "Accounting Dimension Detail", "dimension_defaults");
|
||||
row.reference_document = frm.doc.document_type;
|
||||
frm.refresh_fields("dimension_defaults");
|
||||
}
|
||||
|
||||
frappe.db.get_value('Accounting Dimension', {'document_type': frm.doc.document_type}, 'document_type', (r) => {
|
||||
if (r && r.document_type) {
|
||||
frm.set_df_property('document_type', 'description', "Document type is already set as dimension");
|
||||
@ -50,3 +57,10 @@ frappe.ui.form.on('Accounting Dimension', {
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
frappe.ui.form.on('Accounting Dimension Detail', {
|
||||
dimension_defaults_add: function(frm, cdt, cdn) {
|
||||
let row = locals[cdt][cdn];
|
||||
row.reference_document = frm.doc.document_type;
|
||||
}
|
||||
});
|
@ -1,6 +1,4 @@
|
||||
{
|
||||
"_comments": "[]",
|
||||
"_liked_by": "[]",
|
||||
"autoname": "field:label",
|
||||
"creation": "2019-05-04 18:13:37.002352",
|
||||
"doctype": "DocType",
|
||||
@ -9,8 +7,7 @@
|
||||
"document_type",
|
||||
"label",
|
||||
"fieldname",
|
||||
"mandatory_for_bs",
|
||||
"mandatory_for_pl",
|
||||
"dimension_defaults",
|
||||
"disabled"
|
||||
],
|
||||
"fields": [
|
||||
@ -43,19 +40,13 @@
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "mandatory_for_bs",
|
||||
"fieldtype": "Check",
|
||||
"label": "Mandatory For Balance Sheet"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "mandatory_for_pl",
|
||||
"fieldtype": "Check",
|
||||
"label": "Mandatory For Profit and Loss Account"
|
||||
"fieldname": "dimension_defaults",
|
||||
"fieldtype": "Table",
|
||||
"label": "Dimension Defaults",
|
||||
"options": "Accounting Dimension Detail"
|
||||
}
|
||||
],
|
||||
"modified": "2019-07-14 17:25:01.307948",
|
||||
"modified": "2019-07-17 16:49:31.134385",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounting Dimension",
|
||||
|
@ -96,13 +96,13 @@ def delete_accounting_dimension(doc):
|
||||
|
||||
frappe.db.sql("""
|
||||
DELETE FROM `tabCustom Field`
|
||||
WHERE fieldname = %s
|
||||
WHERE fieldname = %s
|
||||
AND dt IN (%s)""" % #nosec
|
||||
('%s', ', '.join(['%s']* len(doclist))), tuple([doc.fieldname] + doclist))
|
||||
|
||||
frappe.db.sql("""
|
||||
DELETE FROM `tabProperty Setter`
|
||||
WHERE field_name = %s
|
||||
WHERE field_name = %s
|
||||
AND doc_type IN (%s)""" % #nosec
|
||||
('%s', ', '.join(['%s']* len(doclist))), tuple([doc.fieldname] + doclist))
|
||||
|
||||
@ -150,14 +150,40 @@ def get_doctypes_with_dimensions():
|
||||
"Purchase Order Item", "Journal Entry Account", "Material Request Item", "Delivery Note Item", "Purchase Receipt Item",
|
||||
"Stock Entry Detail", "Payment Entry Deduction", "Sales Taxes and Charges", "Purchase Taxes and Charges", "Shipping Rule",
|
||||
"Landed Cost Item", "Asset Value Adjustment", "Loyalty Program", "Fee Schedule", "Fee Structure", "Stock Reconciliation",
|
||||
"Travel Request", "Fees", "POS Profile"]
|
||||
"Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool", "Opening Invoice Creation Tool Item", "Subscription",
|
||||
"Subscription Plan"]
|
||||
|
||||
return doclist
|
||||
|
||||
def get_accounting_dimensions(as_list=True):
|
||||
accounting_dimensions = frappe.get_all("Accounting Dimension", fields=["label", "fieldname", "mandatory_for_pl", "mandatory_for_bs", "disabled"], filters={"disabled": 0})
|
||||
accounting_dimensions = frappe.get_all("Accounting Dimension", fields=["label", "fieldname", "disabled"])
|
||||
|
||||
if as_list:
|
||||
return [d.fieldname for d in accounting_dimensions]
|
||||
else:
|
||||
return accounting_dimensions
|
||||
|
||||
def get_checks_for_pl_and_bs_accounts():
|
||||
dimensions = frappe.db.sql("""SELECT p.label, p.disabled, p.fieldname, c.company, c.mandatory_for_pl, c.mandatory_for_bs
|
||||
FROM `tabAccounting Dimension`p ,`tabAccounting Dimension Detail` c
|
||||
WHERE p.name = c.parent""", as_dict=1)
|
||||
|
||||
return dimensions
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_dimension_filters():
|
||||
dimension_filters = frappe.db.sql("""
|
||||
SELECT label, fieldname, document_type
|
||||
FROM `tabAccounting Dimension`
|
||||
WHERE disabled = 0
|
||||
""", as_dict=1)
|
||||
|
||||
default_dimensions = frappe.db.sql("""SELECT parent, company, default_dimension
|
||||
FROM `tabAccounting Dimension Detail`""", as_dict=1)
|
||||
|
||||
default_dimensions_map = {}
|
||||
for dimension in default_dimensions:
|
||||
default_dimensions_map.setdefault(dimension['company'], {})
|
||||
default_dimensions_map[dimension['company']][dimension['parent']] = dimension['default_dimension']
|
||||
|
||||
return dimension_filters, default_dimensions_map
|
||||
|
@ -27,12 +27,20 @@ class TestAccountingDimension(unittest.TestCase):
|
||||
dimension1 = frappe.get_doc({
|
||||
"doctype": "Accounting Dimension",
|
||||
"document_type": "Location",
|
||||
"mandatory_for_pl": 1
|
||||
}).insert()
|
||||
})
|
||||
|
||||
dimension1.append("dimension_defaults", {
|
||||
"company": "_Test Company",
|
||||
"reference_document": "Location",
|
||||
"default_dimension": "Block 1",
|
||||
"mandatory_for_bs": 1
|
||||
})
|
||||
|
||||
dimension1.insert()
|
||||
dimension1.save()
|
||||
else:
|
||||
dimension1 = frappe.get_doc("Accounting Dimension", "Location")
|
||||
dimension1.disabled = 0
|
||||
dimension1.mandatory_for_pl = 1
|
||||
dimension1.save()
|
||||
|
||||
def test_dimension_against_sales_invoice(self):
|
||||
@ -100,7 +108,6 @@ def disable_dimension():
|
||||
dimension1.save()
|
||||
|
||||
dimension2 = frappe.get_doc("Accounting Dimension", "Location")
|
||||
dimension2.mandatory_for_pl = 0
|
||||
dimension2.disabled = 1
|
||||
dimension2.save()
|
||||
|
||||
|
@ -0,0 +1,67 @@
|
||||
{
|
||||
"creation": "2019-07-16 17:53:18.718831",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"company",
|
||||
"reference_document",
|
||||
"default_dimension",
|
||||
"mandatory_for_bs",
|
||||
"mandatory_for_pl"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"columns": 2,
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "reference_document",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"label": "Reference Document",
|
||||
"options": "DocType",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"columns": 2,
|
||||
"fieldname": "default_dimension",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Default Dimension",
|
||||
"options": "reference_document",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"columns": 3,
|
||||
"default": "0",
|
||||
"fieldname": "mandatory_for_bs",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Mandatory For Balance Sheet"
|
||||
},
|
||||
{
|
||||
"columns": 3,
|
||||
"default": "0",
|
||||
"fieldname": "mandatory_for_pl",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Mandatory For Profit and Loss Account"
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"modified": "2019-07-17 23:34:33.026883",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounting Dimension Detail",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class AccountingDimensionDetail(Document):
|
||||
pass
|
@ -10,9 +10,6 @@ def get_data():
|
||||
{
|
||||
'label': _('Bank Deatils'),
|
||||
'items': ['Bank Account', 'Bank Guarantee']
|
||||
},
|
||||
{
|
||||
'items': ['Payment Order']
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ from erpnext.accounts.party import validate_party_gle_currency, validate_party_f
|
||||
from erpnext.accounts.utils import get_account_currency
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
from erpnext.exceptions import InvalidAccountCurrency
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_checks_for_pl_and_bs_accounts
|
||||
|
||||
exclude_from_linked_with = True
|
||||
class GLEntry(Document):
|
||||
@ -86,16 +86,16 @@ class GLEntry(Document):
|
||||
|
||||
account_type = frappe.db.get_value("Account", self.account, "report_type")
|
||||
|
||||
for dimension in get_accounting_dimensions(as_list=False):
|
||||
for dimension in get_checks_for_pl_and_bs_accounts():
|
||||
|
||||
if account_type == "Profit and Loss" \
|
||||
and dimension.mandatory_for_pl and not dimension.disabled:
|
||||
and self.company == dimension.company and dimension.mandatory_for_pl and not dimension.disabled:
|
||||
if not self.get(dimension.fieldname):
|
||||
frappe.throw(_("Accounting Dimension <b>{0}</b> is required for 'Profit and Loss' account {1}.")
|
||||
.format(dimension.label, self.account))
|
||||
|
||||
if account_type == "Balance Sheet" \
|
||||
and dimension.mandatory_for_bs and not dimension.disabled:
|
||||
and self.company == dimension.company and dimension.mandatory_for_bs and not dimension.disabled:
|
||||
if not self.get(dimension.fieldname):
|
||||
frappe.throw(_("Accounting Dimension <b>{0}</b> is required for 'Balance Sheet' account {1}.")
|
||||
.format(dimension.label, self.account))
|
||||
|
@ -258,6 +258,7 @@
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "accounting_dimensions_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Accounting Dimensions"
|
||||
@ -269,12 +270,13 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2019-05-25 22:14:02.715509",
|
||||
"modified": "2019-07-16 17:12:08.238334",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Journal Entry Account",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
@ -10,7 +10,9 @@
|
||||
"create_missing_party",
|
||||
"column_break_3",
|
||||
"invoice_type",
|
||||
"accounting_dimensions_section",
|
||||
"cost_center",
|
||||
"dimension_col_break",
|
||||
"section_break_4",
|
||||
"invoices"
|
||||
],
|
||||
@ -59,11 +61,21 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "Cost Center",
|
||||
"options": "Cost Center"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "accounting_dimensions_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Accounting Dimensions"
|
||||
},
|
||||
{
|
||||
"fieldname": "dimension_col_break",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"hide_toolbar": 1,
|
||||
"issingle": 1,
|
||||
"modified": "2019-06-13 11:45:31.405267",
|
||||
"modified": "2019-07-25 14:57:33.187689",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Opening Invoice Creation Tool",
|
||||
|
@ -7,6 +7,7 @@ import frappe
|
||||
from frappe import _, scrub
|
||||
from frappe.utils import flt, nowdate
|
||||
from frappe.model.document import Document
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
||||
|
||||
|
||||
class OpeningInvoiceCreationTool(Document):
|
||||
@ -173,6 +174,13 @@ class OpeningInvoiceCreationTool(Document):
|
||||
"currency": frappe.get_cached_value('Company', self.company, "default_currency")
|
||||
})
|
||||
|
||||
accounting_dimension = get_accounting_dimensions()
|
||||
|
||||
for dimension in accounting_dimension:
|
||||
args.update({
|
||||
dimension: item.get(dimension)
|
||||
})
|
||||
|
||||
if self.invoice_type == "Sales":
|
||||
args["is_pos"] = 0
|
||||
|
||||
|
@ -15,7 +15,9 @@
|
||||
"outstanding_amount",
|
||||
"column_break_4",
|
||||
"qty",
|
||||
"cost_center"
|
||||
"accounting_dimensions_section",
|
||||
"cost_center",
|
||||
"dimension_col_break"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@ -92,10 +94,19 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "Cost Center",
|
||||
"options": "Cost Center"
|
||||
},
|
||||
{
|
||||
"fieldname": "accounting_dimensions_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Accounting Dimensions"
|
||||
},
|
||||
{
|
||||
"fieldname": "dimension_col_break",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"modified": "2019-06-13 11:48:08.324063",
|
||||
"modified": "2019-07-25 15:00:00.460695",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Opening Invoice Creation Tool Item",
|
||||
|
@ -20,11 +20,13 @@ test_dependencies = ["Item", "Cost Center", "Payment Term", "Payment Terms Templ
|
||||
test_ignore = ["Serial No"]
|
||||
|
||||
class TestPurchaseInvoice(unittest.TestCase):
|
||||
def setUp(self):
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
unlink_payment_on_cancel_of_invoice()
|
||||
frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1)
|
||||
|
||||
def tearDown(self):
|
||||
@classmethod
|
||||
def tearDownClass(self):
|
||||
unlink_payment_on_cancel_of_invoice(0)
|
||||
|
||||
def test_gl_entries_without_perpetual_inventory(self):
|
||||
@ -91,6 +93,7 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
pi_doc = frappe.get_doc('Purchase Invoice', pi_doc.name)
|
||||
|
||||
self.assertRaises(frappe.LinkExistsError, pi_doc.cancel)
|
||||
unlink_payment_on_cancel_of_invoice()
|
||||
|
||||
def test_purchase_invoice_for_blocked_supplier(self):
|
||||
supplier = frappe.get_doc('Supplier', '_Test Supplier')
|
||||
|
@ -44,6 +44,10 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
|
||||
this.frm.toggle_reqd("due_date", !this.frm.doc.is_return);
|
||||
|
||||
if (this.frm.doc.is_return) {
|
||||
this.frm.return_print_format = "Sales Invoice Return";
|
||||
}
|
||||
|
||||
this.show_general_ledger();
|
||||
|
||||
if(doc.update_stock) this.show_stock_ledger();
|
||||
@ -148,16 +152,24 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
},
|
||||
|
||||
set_default_print_format: function() {
|
||||
// set default print format to POS type
|
||||
// set default print format to POS type or Credit Note
|
||||
if(cur_frm.doc.is_pos) {
|
||||
if(cur_frm.pos_print_format) {
|
||||
cur_frm.meta._default_print_format = cur_frm.meta.default_print_format;
|
||||
cur_frm.meta.default_print_format = cur_frm.pos_print_format;
|
||||
}
|
||||
} else if(cur_frm.doc.is_return) {
|
||||
if(cur_frm.return_print_format) {
|
||||
cur_frm.meta._default_print_format = cur_frm.meta.default_print_format;
|
||||
cur_frm.meta.default_print_format = cur_frm.return_print_format;
|
||||
}
|
||||
} else {
|
||||
if(cur_frm.meta._default_print_format) {
|
||||
cur_frm.meta.default_print_format = cur_frm.meta._default_print_format;
|
||||
cur_frm.meta._default_print_format = null;
|
||||
} else if(in_list([cur_frm.pos_print_format, cur_frm.return_print_format], cur_frm.meta.default_print_format)) {
|
||||
cur_frm.meta.default_print_format = null;
|
||||
cur_frm.meta._default_print_format = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -29,10 +29,12 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
w.submit()
|
||||
return w
|
||||
|
||||
def setUp(self):
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
unlink_payment_on_cancel_of_invoice()
|
||||
|
||||
def tearDown(self):
|
||||
@classmethod
|
||||
def tearDownClass(self):
|
||||
unlink_payment_on_cancel_of_invoice(0)
|
||||
|
||||
def test_timestamp_change(self):
|
||||
@ -135,6 +137,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
unlink_payment_on_cancel_of_invoice(0)
|
||||
si = frappe.get_doc('Sales Invoice', si.name)
|
||||
self.assertRaises(frappe.LinkExistsError, si.cancel)
|
||||
unlink_payment_on_cancel_of_invoice()
|
||||
|
||||
def test_sales_invoice_calculation_export_currency(self):
|
||||
si = frappe.copy_doc(test_records[2])
|
||||
|
@ -764,6 +764,7 @@
|
||||
"label": "Image"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "accounting_dimensions_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Accounting Dimensions"
|
||||
@ -782,7 +783,7 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2019-06-28 17:30:12.156086",
|
||||
"modified": "2019-07-16 16:36:46.527606",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice Item",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,6 +9,7 @@ from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils.data import nowdate, getdate, cint, add_days, date_diff, get_last_day, add_to_date, flt
|
||||
from erpnext.accounts.doctype.subscription_plan.subscription_plan import get_plan_rate
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
||||
|
||||
|
||||
class Subscription(Document):
|
||||
@ -241,6 +242,15 @@ class Subscription(Document):
|
||||
invoice.posting_date = self.current_invoice_start
|
||||
invoice.customer = self.customer
|
||||
|
||||
## Add dimesnions in invoice for subscription:
|
||||
accounting_dimensions = get_accounting_dimensions()
|
||||
|
||||
for dimension in accounting_dimensions:
|
||||
if self.get(dimension):
|
||||
invoice.update({
|
||||
dimension: self.get(dimension)
|
||||
})
|
||||
|
||||
# Subscription is better suited for service items. I won't update `update_stock`
|
||||
# for that reason
|
||||
items_list = self.get_items_from_plans(self.plans, prorate)
|
||||
|
@ -1,612 +1,163 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:plan_name",
|
||||
"beta": 0,
|
||||
"creation": "2018-02-24 11:31:23.066506",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:plan_name",
|
||||
"creation": "2018-02-24 11:31:23.066506",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"plan_name",
|
||||
"currency",
|
||||
"column_break_3",
|
||||
"item",
|
||||
"section_break_5",
|
||||
"price_determination",
|
||||
"column_break_7",
|
||||
"cost",
|
||||
"price_list",
|
||||
"section_break_11",
|
||||
"billing_interval",
|
||||
"column_break_13",
|
||||
"billing_interval_count",
|
||||
"payment_plan_section",
|
||||
"payment_plan_id",
|
||||
"column_break_16",
|
||||
"payment_gateway",
|
||||
"accounting_dimensions_section",
|
||||
"dimension_col_break"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "plan_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Plan Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"fieldname": "plan_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Plan Name",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "currency",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Currency",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Currency",
|
||||
"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
|
||||
},
|
||||
"fieldname": "currency",
|
||||
"fieldtype": "Link",
|
||||
"label": "Currency",
|
||||
"options": "Currency"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "item",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Item",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Item",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "item",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Item",
|
||||
"options": "Item",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "",
|
||||
"fieldname": "price_determination",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Price Determination",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "\nFixed rate\nBased on price list",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "price_determination",
|
||||
"fieldtype": "Select",
|
||||
"label": "Price Determination",
|
||||
"options": "\nFixed rate\nBased on price list",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_7",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "column_break_7",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.price_determination==\"Fixed rate\"",
|
||||
"fieldname": "cost",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Cost",
|
||||
"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
|
||||
},
|
||||
"depends_on": "eval:doc.price_determination==\"Fixed rate\"",
|
||||
"fieldname": "cost",
|
||||
"fieldtype": "Currency",
|
||||
"in_list_view": 1,
|
||||
"label": "Cost"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.price_determination==\"Based on price list\"",
|
||||
"fieldname": "price_list",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Price List",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Price List",
|
||||
"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
|
||||
},
|
||||
"depends_on": "eval:doc.price_determination==\"Based on price list\"",
|
||||
"fieldname": "price_list",
|
||||
"fieldtype": "Link",
|
||||
"label": "Price List",
|
||||
"options": "Price List"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_11",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "section_break_11",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Day",
|
||||
"fieldname": "billing_interval",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Billing Interval",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Day\nWeek\nMonth\nYear",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"default": "Day",
|
||||
"fieldname": "billing_interval",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Billing Interval",
|
||||
"options": "Day\nWeek\nMonth\nYear",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_13",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "column_break_13",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "1",
|
||||
"description": "Number of intervals for the interval field e.g if Interval is 'Days' and Billing Interval Count is 3, invoices will be generated every 3 days",
|
||||
"fieldname": "billing_interval_count",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Billing Interval Count",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"default": "1",
|
||||
"description": "Number of intervals for the interval field e.g if Interval is 'Days' and Billing Interval Count is 3, invoices will be generated every 3 days",
|
||||
"fieldname": "billing_interval_count",
|
||||
"fieldtype": "Int",
|
||||
"label": "Billing Interval Count",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "payment_plan_section",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Payment Plan",
|
||||
"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
|
||||
},
|
||||
"fieldname": "payment_plan_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Payment Plan"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "payment_plan_id",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Payment Plan",
|
||||
"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
|
||||
},
|
||||
"fieldname": "payment_plan_id",
|
||||
"fieldtype": "Data",
|
||||
"label": "Payment Plan"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_16",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "column_break_16",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "payment_gateway",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Payment Gateway",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Payment Gateway Account",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldname": "payment_gateway",
|
||||
"fieldtype": "Link",
|
||||
"label": "Payment Gateway",
|
||||
"options": "Payment Gateway Account"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "accounting_dimensions_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Accounting Dimensions"
|
||||
},
|
||||
{
|
||||
"fieldname": "dimension_col_break",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-06-20 16:59:54.082358",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Subscription Plan",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"modified": "2019-07-25 18:35:04.362556",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Subscription Plan",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
{%- from "templates/print_formats/standard_macros.html" import add_header, render_field, print_value, fieldmeta,
|
||||
get_width, get_align_class -%}
|
||||
|
||||
{%- macro render_currency(df, doc) -%}
|
||||
<div class="row {% if df.bold %}important{% endif %} data-field">
|
||||
<div class="col-xs-{{ "9" if df.fieldtype=="Check" else "5" }}
|
||||
{%- if doc._align_labels_right %} text-right{%- endif -%}">
|
||||
<label>{{ _(df.label) }}</label>
|
||||
</div>
|
||||
<div class="col-xs-{{ "3" if df.fieldtype=="Check" else "7" }} value">
|
||||
{% if doc.get(df.fieldname) != None -%}
|
||||
{{ frappe.utils.fmt_money((doc[df.fieldname])|int|abs, currency=doc.currency) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{%- endmacro -%}
|
||||
|
||||
{%- macro render_taxes(df, doc) -%}
|
||||
{%- set data = doc.get(df.fieldname)[df.start:df.end] -%}
|
||||
<div class="row">
|
||||
<div class="col-xs-6"></div>
|
||||
<div class="col-xs-6">
|
||||
{%- for charge in data -%}
|
||||
{%- if (charge.tax_amount or doc.flags.print_taxes_with_zero_amount) and (not charge.included_in_print_rate or doc.flags.show_inclusive_tax_in_print) -%}
|
||||
<div class="row">
|
||||
<div class="col-xs-5 {%- if doc._align_labels_right %} text-right{%- endif -%}">
|
||||
<label>{{ charge.get_formatted("description") }}</label></div>
|
||||
<div class="col-xs-7 text-right">
|
||||
{{ frappe.utils.fmt_money((charge.tax_amount)|int|abs, currency=doc.currency) }}
|
||||
</div>
|
||||
</div>
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
</div>
|
||||
</div>
|
||||
{%- endmacro -%}
|
||||
|
||||
{%- macro render_table(df, doc) -%}
|
||||
{%- set table_meta = frappe.get_meta(df.options) -%}
|
||||
{%- set data = doc.get(df.fieldname)[df.start:df.end] -%}
|
||||
{%- if doc.print_templates and
|
||||
doc.print_templates.get(df.fieldname) -%}
|
||||
{% include doc.print_templates[df.fieldname] %}
|
||||
{%- else -%}
|
||||
{%- if data -%}
|
||||
{%- set visible_columns = get_visible_columns(doc.get(df.fieldname),
|
||||
table_meta, df) -%}
|
||||
<div {{ fieldmeta(df) }}>
|
||||
<table class="table table-bordered table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 40px" class="table-sr">{{ _("Sr") }}</th>
|
||||
{% for tdf in visible_columns %}
|
||||
{% if (data and not data[0].flags.compact_item_print) or tdf.fieldname in doc.get(df.fieldname)[0].flags.compact_item_fields %}
|
||||
<th style="width: {{ get_width(tdf) }};" class="{{ get_align_class(tdf) }}" {{ fieldmeta(df) }}>
|
||||
{{ _(tdf.label) }}</th>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for d in data %}
|
||||
<tr>
|
||||
<td class="table-sr">{{ d.idx }}</td>
|
||||
{% for tdf in visible_columns %}
|
||||
{% if not d.flags.compact_item_print or tdf.fieldname in doc.get(df.fieldname)[0].flags.compact_item_fields %}
|
||||
<td class="{{ get_align_class(tdf) }}" {{ fieldmeta(df) }}>
|
||||
{% if tdf.fieldtype == 'Currency' %}
|
||||
<div class="value">{{ frappe.utils.fmt_money((d[tdf.fieldname])|int|abs, currency=doc.currency) }}</div></td>
|
||||
{% else %}
|
||||
<div class="value">{{ print_value(tdf, d, doc, visible_columns) }}</div></td>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
{%- endmacro -%}
|
||||
|
||||
{% for page in layout %}
|
||||
<div class="page-break">
|
||||
<div {% if print_settings.repeat_header_footer %} id="header-html" class="hidden-pdf" {% endif %}>
|
||||
{{ add_header(loop.index, layout|len, doc, letter_head, no_letterhead, footer, print_settings) }}
|
||||
</div>
|
||||
|
||||
{% if print_settings.repeat_header_footer %}
|
||||
<div id="footer-html" class="visible-pdf">
|
||||
{% if not no_letterhead and footer %}
|
||||
<div class="letter-head-footer">
|
||||
{{ footer }}
|
||||
</div>
|
||||
{% endif %}
|
||||
<p class="text-center small page-number visible-pdf">
|
||||
{{ _("Page {0} of {1}").format('<span class="page"></span>', '<span class="topage"></span>') }}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% for section in page %}
|
||||
<div class="row section-break">
|
||||
{% if section.columns.fields %}
|
||||
{%- if doc._line_breaks and loop.index != 1 -%}<hr>{%- endif -%}
|
||||
{%- if doc._show_section_headings and section.label and section.has_data -%}
|
||||
<h4 class='col-sm-12'>{{ _(section.label) }}</h4>
|
||||
{% endif %}
|
||||
{%- endif -%}
|
||||
{% for column in section.columns %}
|
||||
<div class="col-xs-{{ (12 / section.columns|len)|int }} column-break">
|
||||
{% for df in column.fields %}
|
||||
{% if df.fieldname == 'taxes' %}
|
||||
{{ render_taxes(df, doc) }}
|
||||
{% elif df.fieldtype == 'Currency' %}
|
||||
{{ render_currency(df, doc) }}
|
||||
{% elif df.fieldtype =='Table' %}
|
||||
{{ render_table(df, doc)}}
|
||||
{% elif doc[df.fieldname] %}
|
||||
{{ render_field(df, doc) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
@ -0,0 +1,24 @@
|
||||
{
|
||||
"align_labels_right": 1,
|
||||
"creation": "2019-07-24 20:13:30.259953",
|
||||
"custom_format": 0,
|
||||
"default_print_language": "en-US",
|
||||
"disabled": 0,
|
||||
"doc_type": "Sales Invoice",
|
||||
"docstatus": 0,
|
||||
"doctype": "Print Format",
|
||||
"font": "Default",
|
||||
"html": "",
|
||||
"idx": 0,
|
||||
"line_breaks": 1,
|
||||
"modified": "2019-07-24 20:13:30.259953",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice Return",
|
||||
"owner": "Administrator",
|
||||
"print_format_builder": 0,
|
||||
"print_format_type": "Jinja",
|
||||
"raw_printing": 0,
|
||||
"show_section_headings": 1,
|
||||
"standard": "Yes"
|
||||
}
|
@ -115,13 +115,12 @@ frappe.query_reports["Accounts Payable"] = {
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.dimension_filters.then((dimensions) => {
|
||||
dimensions.forEach((dimension) => {
|
||||
frappe.query_reports["Accounts Payable"].filters.splice(9, 0 ,{
|
||||
"fieldname": dimension["fieldname"],
|
||||
"label": __(dimension["label"]),
|
||||
"fieldtype": "Link",
|
||||
"options": dimension["document_type"]
|
||||
});
|
||||
erpnext.dimension_filters.forEach((dimension) => {
|
||||
frappe.query_reports["Accounts Payable"].filters.splice(9, 0 ,{
|
||||
"fieldname": dimension["fieldname"],
|
||||
"label": __(dimension["label"]),
|
||||
"fieldtype": "Link",
|
||||
"options": dimension["document_type"]
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -99,13 +99,12 @@ frappe.query_reports["Accounts Payable Summary"] = {
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.dimension_filters.then((dimensions) => {
|
||||
dimensions.forEach((dimension) => {
|
||||
frappe.query_reports["Accounts Payable Summary"].filters.splice(9, 0 ,{
|
||||
"fieldname": dimension["fieldname"],
|
||||
"label": __(dimension["label"]),
|
||||
"fieldtype": "Link",
|
||||
"options": dimension["document_type"]
|
||||
});
|
||||
erpnext.dimension_filters.forEach((dimension) => {
|
||||
frappe.query_reports["Accounts Payable Summary"].filters.splice(9, 0 ,{
|
||||
"fieldname": dimension["fieldname"],
|
||||
"label": __(dimension["label"]),
|
||||
"fieldtype": "Link",
|
||||
"options": dimension["document_type"]
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -173,13 +173,12 @@ frappe.query_reports["Accounts Receivable"] = {
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.dimension_filters.then((dimensions) => {
|
||||
dimensions.forEach((dimension) => {
|
||||
frappe.query_reports["Accounts Receivable"].filters.splice(9, 0 ,{
|
||||
"fieldname": dimension["fieldname"],
|
||||
"label": __(dimension["label"]),
|
||||
"fieldtype": "Link",
|
||||
"options": dimension["document_type"]
|
||||
});
|
||||
erpnext.dimension_filters.forEach((dimension) => {
|
||||
frappe.query_reports["Accounts Receivable"].filters.splice(9, 0 ,{
|
||||
"fieldname": dimension["fieldname"],
|
||||
"label": __(dimension["label"]),
|
||||
"fieldtype": "Link",
|
||||
"options": dimension["document_type"]
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -117,13 +117,11 @@ frappe.query_reports["Accounts Receivable Summary"] = {
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.dimension_filters.then((dimensions) => {
|
||||
dimensions.forEach((dimension) => {
|
||||
frappe.query_reports["Accounts Receivable Summary"].filters.splice(9, 0 ,{
|
||||
"fieldname": dimension["fieldname"],
|
||||
"label": __(dimension["label"]),
|
||||
"fieldtype": "Link",
|
||||
"options": dimension["document_type"]
|
||||
});
|
||||
erpnext.dimension_filters.forEach((dimension) => {
|
||||
frappe.query_reports["Accounts Receivable Summary"].filters.splice(9, 0 ,{
|
||||
"fieldname": dimension["fieldname"],
|
||||
"label": __(dimension["label"]),
|
||||
"fieldtype": "Link",
|
||||
"options": dimension["document_type"]
|
||||
});
|
||||
});
|
||||
|
@ -58,8 +58,7 @@ def get_columns():
|
||||
{
|
||||
"fieldname": "payment_document",
|
||||
"label": _("Payment Document Type"),
|
||||
"fieldtype": "Link",
|
||||
"options": "DocType",
|
||||
"fieldtype": "Data",
|
||||
"width": 220
|
||||
},
|
||||
{
|
||||
|
@ -63,8 +63,7 @@ frappe.query_reports["Budget Variance Report"] = {
|
||||
]
|
||||
}
|
||||
|
||||
erpnext.dimension_filters.then((dimensions) => {
|
||||
dimensions.forEach((dimension) => {
|
||||
frappe.query_reports["Budget Variance Report"].filters[4].options.push(dimension["document_type"]);
|
||||
});
|
||||
erpnext.dimension_filters.forEach((dimension) => {
|
||||
frappe.query_reports["Budget Variance Report"].filters[4].options.push(dimension["document_type"]);
|
||||
});
|
||||
|
||||
|
@ -159,13 +159,12 @@ frappe.query_reports["General Ledger"] = {
|
||||
]
|
||||
}
|
||||
|
||||
erpnext.dimension_filters.then((dimensions) => {
|
||||
dimensions.forEach((dimension) => {
|
||||
frappe.query_reports["General Ledger"].filters.splice(15, 0 ,{
|
||||
"fieldname": dimension["fieldname"],
|
||||
"label": __(dimension["label"]),
|
||||
"fieldtype": "Link",
|
||||
"options": dimension["document_type"]
|
||||
});
|
||||
erpnext.dimension_filters.forEach((dimension) => {
|
||||
frappe.query_reports["General Ledger"].filters.splice(15, 0 ,{
|
||||
"fieldname": dimension["fieldname"],
|
||||
"label": __(dimension["label"]),
|
||||
"fieldtype": "Link",
|
||||
"options": dimension["document_type"]
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -105,9 +105,8 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
||||
"initial_depth": 3
|
||||
}
|
||||
|
||||
erpnext.dimension_filters.then((dimensions) => {
|
||||
dimensions.forEach((dimension) => {
|
||||
frappe.query_reports["Profitability Analysis"].filters[1].options.push(dimension["document_type"]);
|
||||
});
|
||||
erpnext.dimension_filters.forEach((dimension) => {
|
||||
frappe.query_reports["Profitability Analysis"].filters[1].options.push(dimension["document_type"]);
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -68,13 +68,12 @@ frappe.query_reports["Sales Register"] = {
|
||||
]
|
||||
}
|
||||
|
||||
erpnext.dimension_filters.then((dimensions) => {
|
||||
dimensions.forEach((dimension) => {
|
||||
frappe.query_reports["Sales Register"].filters.splice(7, 0 ,{
|
||||
"fieldname": dimension["fieldname"],
|
||||
"label": __(dimension["label"]),
|
||||
"fieldtype": "Link",
|
||||
"options": dimension["document_type"]
|
||||
});
|
||||
erpnext.dimension_filters.forEach((dimension) => {
|
||||
frappe.query_reports["Sales Register"].filters.splice(7, 0 ,{
|
||||
"fieldname": dimension["fieldname"],
|
||||
"label": __(dimension["label"]),
|
||||
"fieldtype": "Link",
|
||||
"options": dimension["document_type"]
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -94,10 +94,8 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
||||
"parent_field": "parent_account",
|
||||
"initial_depth": 3
|
||||
}
|
||||
});
|
||||
|
||||
erpnext.dimension_filters.then((dimensions) => {
|
||||
dimensions.forEach((dimension) => {
|
||||
erpnext.dimension_filters.forEach((dimension) => {
|
||||
frappe.query_reports["Trial Balance"].filters.splice(5, 0 ,{
|
||||
"fieldname": dimension["fieldname"],
|
||||
"label": __(dimension["label"]),
|
||||
@ -107,3 +105,5 @@ erpnext.dimension_filters.then((dimensions) => {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
@ -123,11 +123,12 @@ def get_rootwise_opening_balances(filters, report_type):
|
||||
|
||||
if accounting_dimensions:
|
||||
for dimension in accounting_dimensions:
|
||||
additional_conditions += """ and {0} in (%({0})s) """.format(dimension)
|
||||
if filters.get(dimension):
|
||||
additional_conditions += """ and {0} in (%({0})s) """.format(dimension)
|
||||
|
||||
query_filters.update({
|
||||
dimension: filters.get(dimension)
|
||||
})
|
||||
query_filters.update({
|
||||
dimension: filters.get(dimension)
|
||||
})
|
||||
|
||||
gle = frappe.db.sql("""
|
||||
select
|
||||
|
@ -30,7 +30,7 @@ class TestProcurementTracker(unittest.TestCase):
|
||||
company_name="_Test Procurement Company",
|
||||
abbr="_TPC",
|
||||
default_currency="INR",
|
||||
country="India"
|
||||
country="Pakistan"
|
||||
)).insert()
|
||||
warehouse = create_warehouse("_Test Procurement Warehouse", company="_Test Procurement Company")
|
||||
mr = make_material_request(company="_Test Procurement Company", warehouse=warehouse)
|
||||
|
@ -60,7 +60,9 @@ class AccountsController(TransactionBase):
|
||||
|
||||
def validate(self):
|
||||
|
||||
self.validate_qty_is_not_zero()
|
||||
if not self.get('is_return'):
|
||||
self.validate_qty_is_not_zero()
|
||||
|
||||
if self.get("_action") and self._action != "update_after_submit":
|
||||
self.set_missing_values(for_validate=True)
|
||||
|
||||
|
@ -81,7 +81,12 @@ class calculate_taxes_and_totals(object):
|
||||
item.discount_amount = item.price_list_rate - item.rate
|
||||
|
||||
item.net_rate = item.rate
|
||||
item.amount = flt(item.rate * item.qty, item.precision("amount"))
|
||||
|
||||
if not item.qty and self.doc.get("is_return"):
|
||||
item.amount = flt(-1 * item.rate, item.precision("amount"))
|
||||
else:
|
||||
item.amount = flt(item.rate * item.qty, item.precision("amount"))
|
||||
|
||||
item.net_amount = item.amount
|
||||
|
||||
self._set_in_company_currency(item, ["price_list_rate", "rate", "net_rate", "amount", "net_amount"])
|
||||
|
@ -92,5 +92,5 @@ def make_company():
|
||||
company.abbr = "_TC10"
|
||||
company.parent_company = "_Test Company"
|
||||
company.default_currency = "INR"
|
||||
company.country = "India"
|
||||
company.country = "Pakistan"
|
||||
company.insert()
|
@ -624,4 +624,5 @@ erpnext.patches.v11_1.update_default_supplier_in_item_defaults
|
||||
erpnext.patches.v12_0.update_due_date_in_gle
|
||||
erpnext.patches.v12_0.add_default_buying_selling_terms_in_company
|
||||
erpnext.patches.v12_0.update_ewaybill_field_position
|
||||
erpnext.patches.v12_0.create_accounting_dimensions_in_missing_doctypes
|
||||
erpnext.patches.v11_1.set_status_for_material_request_type_manufacture
|
||||
|
@ -0,0 +1,41 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
|
||||
|
||||
def execute():
|
||||
|
||||
frappe.reload_doc('accounts', 'doctype', 'accounting_dimension')
|
||||
|
||||
accounting_dimensions = frappe.db.sql("""select fieldname, label, document_type, disabled from
|
||||
`tabAccounting Dimension`""", as_dict=1)
|
||||
|
||||
if not accounting_dimensions:
|
||||
return
|
||||
|
||||
count = 1
|
||||
for d in accounting_dimensions:
|
||||
|
||||
if count%2 == 0:
|
||||
insert_after_field = 'dimension_col_break'
|
||||
else:
|
||||
insert_after_field = 'accounting_dimensions_section'
|
||||
|
||||
for doctype in ["Subscription Plan", "Subscription", "Opening Invoice Creation Tool", "Opening Invoice Creation Tool Item"]:
|
||||
|
||||
field = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": d.fieldname})
|
||||
|
||||
if field:
|
||||
continue
|
||||
|
||||
df = {
|
||||
"fieldname": d.fieldname,
|
||||
"label": d.label,
|
||||
"fieldtype": "Link",
|
||||
"options": d.document_type,
|
||||
"insert_after": insert_after_field
|
||||
}
|
||||
|
||||
create_custom_field(doctype, df)
|
||||
frappe.clear_cache(doctype=doctype)
|
||||
|
||||
count += 1
|
@ -10,18 +10,19 @@ def execute():
|
||||
|
||||
field = frappe.db.get_value("Custom Field", {"dt": "Sales Invoice", "fieldname": "ewaybill"})
|
||||
|
||||
ewaybill_field = frappe.get_doc("Custom Field", field)
|
||||
if field:
|
||||
ewaybill_field = frappe.get_doc("Custom Field", field)
|
||||
|
||||
ewaybill_field.flags.ignore_validate = True
|
||||
ewaybill_field.flags.ignore_validate = True
|
||||
|
||||
ewaybill_field.update({
|
||||
'fieldname': 'ewaybill',
|
||||
'label': 'e-Way Bill No.',
|
||||
'fieldtype': 'Data',
|
||||
'depends_on': 'eval:(doc.docstatus === 1)',
|
||||
'allow_on_submit': 1,
|
||||
'insert_after': 'tax_id',
|
||||
'translatable': 0
|
||||
})
|
||||
ewaybill_field.update({
|
||||
'fieldname': 'ewaybill',
|
||||
'label': 'e-Way Bill No.',
|
||||
'fieldtype': 'Data',
|
||||
'depends_on': 'eval:(doc.docstatus === 1)',
|
||||
'allow_on_submit': 1,
|
||||
'insert_after': 'tax_id',
|
||||
'translatable': 0
|
||||
})
|
||||
|
||||
ewaybill_field.save()
|
||||
ewaybill_field.save()
|
@ -145,7 +145,7 @@ class Task(NestedSet):
|
||||
|
||||
def populate_depends_on(self):
|
||||
if self.parent_task:
|
||||
parent = frappe.get_cached_doc('Task', self.parent_task)
|
||||
parent = frappe.get_doc('Task', self.parent_task)
|
||||
if not self.name in [row.task for row in parent.depends_on]:
|
||||
parent.append("depends_on", {
|
||||
"doctype": "Task Depends On",
|
||||
|
@ -92,7 +92,13 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
|
||||
$.each(this.frm.doc["items"] || [], function(i, item) {
|
||||
frappe.model.round_floats_in(item);
|
||||
item.net_rate = item.rate;
|
||||
item.amount = flt(item.rate * item.qty, precision("amount", item));
|
||||
|
||||
if ((!item.qty) && me.frm.doc.is_return) {
|
||||
item.amount = flt(item.rate * -1, precision("amount", item));
|
||||
} else {
|
||||
item.amount = flt(item.rate * item.qty, precision("amount", item));
|
||||
}
|
||||
|
||||
item.net_amount = item.amount;
|
||||
item.item_tax_amount = 0.0;
|
||||
item.total_weight = flt(item.weight_per_unit * item.stock_qty);
|
||||
|
@ -129,14 +129,12 @@ function get_filters(){
|
||||
}
|
||||
]
|
||||
|
||||
erpnext.dimension_filters.then((dimensions) => {
|
||||
dimensions.forEach((dimension) => {
|
||||
filters.push({
|
||||
"fieldname": dimension["fieldname"],
|
||||
"label": __(dimension["label"]),
|
||||
"fieldtype": "Link",
|
||||
"options": dimension["document_type"]
|
||||
});
|
||||
erpnext.dimension_filters.forEach((dimension) => {
|
||||
filters.push({
|
||||
"fieldname": dimension["fieldname"],
|
||||
"label": __(dimension["label"]),
|
||||
"fieldtype": "Link",
|
||||
"options": dimension["document_type"]
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -63,20 +63,6 @@ $.extend(erpnext, {
|
||||
me.show_serial_batch_selector(grid_row.frm, grid_row.doc);
|
||||
});
|
||||
},
|
||||
|
||||
get_dimension_filters: async function() {
|
||||
if (!frappe.model.can_read('Accounting Dimension')) {
|
||||
return [];
|
||||
}
|
||||
let dimensions = await frappe.db.get_list('Accounting Dimension', {
|
||||
fields: ['label', 'fieldname', 'document_type'],
|
||||
filters: {
|
||||
disabled: 0
|
||||
}
|
||||
});
|
||||
|
||||
return dimensions;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
@ -5,24 +5,54 @@ erpnext.doctypes_with_dimensions = ["GL Entry", "Sales Invoice", "Purchase Invoi
|
||||
"Purchase Order Item", "Journal Entry Account", "Material Request Item", "Delivery Note Item", "Purchase Receipt Item",
|
||||
"Stock Entry Detail", "Payment Entry Deduction", "Sales Taxes and Charges", "Purchase Taxes and Charges", "Shipping Rule",
|
||||
"Landed Cost Item", "Asset Value Adjustment", "Loyalty Program", "Fee Schedule", "Fee Structure", "Stock Reconciliation",
|
||||
"Travel Request", "Fees", "POS Profile"];
|
||||
"Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool", "Opening Invoice Creation Tool Item", "Subscription",
|
||||
"Subscription Plan"];
|
||||
|
||||
erpnext.dimension_filters = erpnext.get_dimension_filters();
|
||||
frappe.call({
|
||||
method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.get_dimension_filters",
|
||||
callback: function(r){
|
||||
erpnext.dimension_filters = r.message[0];
|
||||
erpnext.default_dimensions = r.message[1];
|
||||
}
|
||||
});
|
||||
|
||||
erpnext.doctypes_with_dimensions.forEach((doctype) => {
|
||||
frappe.ui.form.on(doctype, {
|
||||
onload: function(frm) {
|
||||
erpnext.dimension_filters.then((dimensions) => {
|
||||
dimensions.forEach((dimension) => {
|
||||
frappe.model.with_doctype(dimension['document_type'], () => {
|
||||
if (frappe.meta.has_field(dimension['document_type'], 'is_group')) {
|
||||
frm.set_query(dimension['fieldname'], {
|
||||
"is_group": 0
|
||||
});
|
||||
}
|
||||
});
|
||||
erpnext.dimension_filters.forEach((dimension) => {
|
||||
frappe.model.with_doctype(dimension['document_type'], () => {
|
||||
if (frappe.meta.has_field(dimension['document_type'], 'is_group')) {
|
||||
frm.set_query(dimension['fieldname'], {
|
||||
"is_group": 0
|
||||
});
|
||||
}
|
||||
if (frm.is_new() && frappe.meta.has_field(doctype, 'company') && frm.doc.company) {
|
||||
frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
company: function(frm) {
|
||||
if(frm.doc.company) {
|
||||
erpnext.dimension_filters.forEach((dimension) => {
|
||||
frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
items_add: function(frm, cdt, cdn) {
|
||||
erpnext.dimension_filters.forEach((dimension) => {
|
||||
var row = frappe.get_doc(cdt, cdn);
|
||||
frm.script_manager.copy_from_first_row("items", row, [dimension['fieldname']]);
|
||||
});
|
||||
},
|
||||
|
||||
accounts_add: function(frm, cdt, cdn) {
|
||||
erpnext.dimension_filters.forEach((dimension) => {
|
||||
var row = frappe.get_doc(cdt, cdn);
|
||||
frm.script_manager.copy_from_first_row("accounts", row, [dimension['fieldname']]);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
@ -161,8 +161,9 @@ class Gstr1Report(object):
|
||||
"gst_category": ["in", ["Registered Regular", "Deemed Export", "SEZ"]]
|
||||
})
|
||||
|
||||
conditions += """ and ifnull(gst_category, '') != 'Overseas' and is_return != 1
|
||||
and customer in ({0})""".format(", ".join([frappe.db.escape(c.name) for c in customers]))
|
||||
if customers:
|
||||
conditions += """ and ifnull(gst_category, '') != 'Overseas' and is_return != 1
|
||||
and customer in ({0})""".format(", ".join([frappe.db.escape(c.name) for c in customers]))
|
||||
|
||||
if self.filters.get("type_of_business") in ("B2C Large", "B2C Small"):
|
||||
b2c_limit = frappe.db.get_single_value('GST Settings', 'b2c_limit')
|
||||
@ -174,11 +175,11 @@ class Gstr1Report(object):
|
||||
"gst_category": ["in", ["Unregistered"]]
|
||||
})
|
||||
|
||||
if self.filters.get("type_of_business") == "B2C Large":
|
||||
if self.filters.get("type_of_business") == "B2C Large" and customers:
|
||||
conditions += """ and SUBSTR(place_of_supply, 1, 2) != SUBSTR(company_gstin, 1, 2)
|
||||
and grand_total > {0} and is_return != 1 and customer in ({1})""".\
|
||||
format(flt(b2c_limit), ", ".join([frappe.db.escape(c.name) for c in customers]))
|
||||
elif self.filters.get("type_of_business") == "B2C Small":
|
||||
elif self.filters.get("type_of_business") == "B2C Small" and customers:
|
||||
conditions += """ and (
|
||||
SUBSTR(place_of_supply, 1, 2) = SUBSTR(company_gstin, 1, 2)
|
||||
or grand_total <= {0}) and is_return != 1 and customer in ({1})""".\
|
||||
|
@ -255,27 +255,44 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
var fields = [
|
||||
{fieldtype:'Table', fieldname: 'items',
|
||||
description: __('Select BOM and Qty for Production'),
|
||||
fields: [
|
||||
{fieldtype:'Read Only', fieldname:'item_code',
|
||||
label: __('Item Code'), in_list_view:1},
|
||||
{fieldtype:'Link', fieldname:'bom', options: 'BOM', reqd: 1,
|
||||
label: __('Select BOM'), in_list_view:1, get_query: function(doc) {
|
||||
return {filters: {item: doc.item_code}};
|
||||
}},
|
||||
{fieldtype:'Float', fieldname:'pending_qty', reqd: 1,
|
||||
label: __('Qty'), in_list_view:1},
|
||||
{fieldtype:'Data', fieldname:'sales_order_item', reqd: 1,
|
||||
label: __('Sales Order Item'), hidden:1}
|
||||
],
|
||||
data: r.message,
|
||||
get_data: function() {
|
||||
return r.message
|
||||
const fields = [{
|
||||
label: 'Items',
|
||||
fieldtype: 'Table',
|
||||
fieldname: 'items',
|
||||
description: __('Select BOM and Qty for Production'),
|
||||
fields: [{
|
||||
fieldtype: 'Read Only',
|
||||
fieldname: 'item_code',
|
||||
label: __('Item Code'),
|
||||
in_list_view: 1
|
||||
}, {
|
||||
fieldtype: 'Link',
|
||||
fieldname: 'bom',
|
||||
options: 'BOM',
|
||||
reqd: 1,
|
||||
label: __('Select BOM'),
|
||||
in_list_view: 1,
|
||||
get_query: function (doc) {
|
||||
return { filters: { item: doc.item_code } };
|
||||
}
|
||||
}, {
|
||||
fieldtype: 'Float',
|
||||
fieldname: 'pending_qty',
|
||||
reqd: 1,
|
||||
label: __('Qty'),
|
||||
in_list_view: 1
|
||||
}, {
|
||||
fieldtype: 'Data',
|
||||
fieldname: 'sales_order_item',
|
||||
reqd: 1,
|
||||
label: __('Sales Order Item'),
|
||||
hidden: 1
|
||||
}],
|
||||
data: r.message,
|
||||
get_data: () => {
|
||||
return r.message
|
||||
}
|
||||
]
|
||||
}]
|
||||
var d = new frappe.ui.Dialog({
|
||||
title: __('Select Items to Manufacture'),
|
||||
fields: fields,
|
||||
|
@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
/* eslint-disable */
|
||||
|
||||
frappe.query_reports["Customer-wise Item Price"] = {
|
||||
"filters": [
|
||||
{
|
||||
"label": __("Customer"),
|
||||
"fieldname": "customer",
|
||||
"fieldtype": "Link",
|
||||
"options": "Customer",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"label": __("Item"),
|
||||
"fieldname": "item",
|
||||
"fieldtype": "Link",
|
||||
"options": "Item",
|
||||
"get_query": () => {
|
||||
return {
|
||||
query: "erpnext.controllers.queries.item_query",
|
||||
filters: { 'is_sales_item': 1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
{
|
||||
"add_total_row": 0,
|
||||
"creation": "2019-06-12 03:25:36.263179",
|
||||
"disable_prepared_report": 0,
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"letter_head": "Delta9",
|
||||
"modified": "2019-06-12 03:25:36.263179",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Customer-wise Item Price",
|
||||
"owner": "Administrator",
|
||||
"prepared_report": 0,
|
||||
"ref_doctype": "Customer",
|
||||
"report_name": "Customer-wise Item Price",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
||||
"role": "Sales User"
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager"
|
||||
},
|
||||
{
|
||||
"role": "Accounts User"
|
||||
},
|
||||
{
|
||||
"role": "Accounts Manager"
|
||||
},
|
||||
{
|
||||
"role": "Sales Manager"
|
||||
},
|
||||
{
|
||||
"role": "Sales Master Manager"
|
||||
},
|
||||
{
|
||||
"role": "Stock User"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
from erpnext import get_default_company
|
||||
from erpnext.accounts.party import get_party_details
|
||||
from erpnext.stock.get_item_details import get_price_list_rate_for
|
||||
from frappe import _
|
||||
|
||||
|
||||
def execute(filters=None):
|
||||
if not filters:
|
||||
filters = {}
|
||||
|
||||
if not filters.get("customer"):
|
||||
frappe.throw(_("Please select a Customer"))
|
||||
|
||||
columns = get_columns(filters)
|
||||
data = get_data(filters)
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
def get_columns(filters=None):
|
||||
return [
|
||||
{
|
||||
"label": _("Item Code"),
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Link",
|
||||
"options": "Item",
|
||||
"width": 150
|
||||
},
|
||||
{
|
||||
"label": _("Item Name"),
|
||||
"fieldname": "item_name",
|
||||
"fieldtype": "Data",
|
||||
"width": 200
|
||||
},
|
||||
{
|
||||
"label": _("Selling Rate"),
|
||||
"fieldname": "selling_rate",
|
||||
"fieldtype": "Currency"
|
||||
},
|
||||
{
|
||||
"label": _("Available Stock"),
|
||||
"fieldname": "available_stock",
|
||||
"fieldtype": "Float",
|
||||
"width": 150
|
||||
},
|
||||
{
|
||||
"label": _("Price List"),
|
||||
"fieldname": "price_list",
|
||||
"fieldtype": "Link",
|
||||
"options": "Price List",
|
||||
"width": 120
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
def get_data(filters=None):
|
||||
data = []
|
||||
customer_details = get_customer_details(filters)
|
||||
|
||||
items = get_selling_items(filters)
|
||||
item_stock_map = frappe.get_all("Bin", fields=["item_code", "sum(actual_qty) AS available"], group_by="item_code")
|
||||
item_stock_map = {item.item_code: item.available for item in item_stock_map}
|
||||
|
||||
for item in items:
|
||||
price_list_rate = get_price_list_rate_for(customer_details, item.item_code) or 0.0
|
||||
available_stock = item_stock_map.get(item.item_code)
|
||||
|
||||
data.append({
|
||||
"item_code": item.item_code,
|
||||
"item_name": item.item_name,
|
||||
"selling_rate": price_list_rate,
|
||||
"price_list": customer_details.get("price_list"),
|
||||
"available_stock": available_stock,
|
||||
})
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def get_customer_details(filters):
|
||||
customer_details = get_party_details(party=filters.get("customer"), party_type="Customer")
|
||||
customer_details.update({
|
||||
"company": get_default_company(),
|
||||
"price_list": customer_details.get("selling_price_list")
|
||||
})
|
||||
|
||||
return customer_details
|
||||
|
||||
|
||||
def get_selling_items(filters):
|
||||
if filters.get("item"):
|
||||
item_filters = {"item_code": filters.get("item"), "is_sales_item": 1, "disabled": 0}
|
||||
else:
|
||||
item_filters = {"is_sales_item": 1, "disabled": 0}
|
||||
|
||||
items = frappe.get_all("Item", filters=item_filters, fields=["item_code", "item_name"], order_by="item_name")
|
||||
|
||||
return items
|
@ -802,13 +802,13 @@ class StockEntry(StockController):
|
||||
|
||||
self.add_to_stock_entry_detail(item_dict)
|
||||
|
||||
if self.purpose != "Send to Subcontractor":
|
||||
scrap_item_dict = self.get_bom_scrap_material(self.fg_completed_qty)
|
||||
for item in itervalues(scrap_item_dict):
|
||||
if self.pro_doc and self.pro_doc.scrap_warehouse:
|
||||
item["to_warehouse"] = self.pro_doc.scrap_warehouse
|
||||
if self.purpose != "Send to Subcontractor" and self.purpose == "Manufacture":
|
||||
scrap_item_dict = self.get_bom_scrap_material(self.fg_completed_qty)
|
||||
for item in itervalues(scrap_item_dict):
|
||||
if self.pro_doc and self.pro_doc.scrap_warehouse:
|
||||
item["to_warehouse"] = self.pro_doc.scrap_warehouse
|
||||
|
||||
self.add_to_stock_entry_detail(scrap_item_dict, bom_no=self.bom_no)
|
||||
self.add_to_stock_entry_detail(scrap_item_dict, bom_no=self.bom_no)
|
||||
|
||||
# fetch the serial_no of the first stock entry for the second stock entry
|
||||
if self.work_order and self.purpose == "Manufacture":
|
||||
|
@ -327,7 +327,8 @@ class StockReconciliation(StockController):
|
||||
|
||||
if sl_entries:
|
||||
sl_entries.reverse()
|
||||
self.make_sl_entries(sl_entries)
|
||||
allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock")
|
||||
self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock)
|
||||
|
||||
# repost future entries for selected item_code, warehouse
|
||||
for entries in existing_entries:
|
||||
|
@ -17,10 +17,11 @@ from erpnext.stock.utils import get_stock_balance, get_incoming_rate, get_availa
|
||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||
|
||||
class TestStockReconciliation(unittest.TestCase):
|
||||
def setUp(self):
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
create_batch_or_serial_no_items()
|
||||
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
|
||||
self.insert_existing_sle()
|
||||
insert_existing_sle()
|
||||
|
||||
def test_reco_for_fifo(self):
|
||||
self._test_reco_sle_gle("FIFO")
|
||||
@ -97,18 +98,6 @@ class TestStockReconciliation(unittest.TestCase):
|
||||
self.assertEqual(["_Test Stock Reco Item", "_Test Warehouse Ledger 1 - _TC", 100],
|
||||
[items[0]["item_code"], items[0]["warehouse"], items[0]["qty"]])
|
||||
|
||||
def insert_existing_sle(self):
|
||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
||||
|
||||
make_stock_entry(posting_date="2012-12-15", posting_time="02:00", item_code="_Test Item",
|
||||
target="_Test Warehouse - _TC", qty=10, basic_rate=700)
|
||||
|
||||
make_stock_entry(posting_date="2012-12-25", posting_time="03:00", item_code="_Test Item",
|
||||
source="_Test Warehouse - _TC", qty=15)
|
||||
|
||||
make_stock_entry(posting_date="2013-01-05", posting_time="07:00", item_code="_Test Item",
|
||||
target="_Test Warehouse - _TC", qty=15, basic_rate=1200)
|
||||
|
||||
def test_stock_reco_for_serialized_item(self):
|
||||
set_perpetual_inventory()
|
||||
|
||||
@ -218,6 +207,18 @@ class TestStockReconciliation(unittest.TestCase):
|
||||
for d in to_delete_records:
|
||||
frappe.delete_doc("Stock Reconciliation", d)
|
||||
|
||||
def insert_existing_sle():
|
||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
||||
|
||||
make_stock_entry(posting_date="2012-12-15", posting_time="02:00", item_code="_Test Item",
|
||||
target="_Test Warehouse - _TC", qty=10, basic_rate=700)
|
||||
|
||||
make_stock_entry(posting_date="2012-12-25", posting_time="03:00", item_code="_Test Item",
|
||||
source="_Test Warehouse - _TC", qty=15)
|
||||
|
||||
make_stock_entry(posting_date="2013-01-05", posting_time="07:00", item_code="_Test Item",
|
||||
target="_Test Warehouse - _TC", qty=15, basic_rate=1200)
|
||||
|
||||
def create_batch_or_serial_no_items():
|
||||
create_warehouse("_Test Warehouse for Stock Reco1",
|
||||
{"is_group": 0, "parent_warehouse": "_Test Warehouse Group - _TC"})
|
||||
|
@ -8,16 +8,7 @@ import unittest
|
||||
|
||||
class TestStockSettings(unittest.TestCase):
|
||||
def setUp(self):
|
||||
settings = frappe.get_single('Stock Settings')
|
||||
settings.clean_description_html = 0
|
||||
settings.save()
|
||||
|
||||
frappe.delete_doc('Item', 'Item for description test')
|
||||
|
||||
def tearDown(self):
|
||||
settings = frappe.get_single('Stock Settings')
|
||||
settings.clean_description_html = 1
|
||||
settings.save()
|
||||
frappe.db.set_value("Stock Settings", None, "clean_description_html", 0)
|
||||
|
||||
def test_settings(self):
|
||||
item = frappe.get_doc(dict(
|
||||
|
@ -37,8 +37,8 @@ frappe.query_reports["Stock Ageing"] = {
|
||||
"options": "Brand"
|
||||
},
|
||||
{
|
||||
"fieldname":"show_ageing_warehouse_wise",
|
||||
"label": __("Show Ageing Warehouse-wise"),
|
||||
"fieldname":"show_warehouse_wise_stock",
|
||||
"label": __("Show Warehouse-wise Stock"),
|
||||
"fieldtype": "Check",
|
||||
"default": 0
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import date_diff, flt
|
||||
from six import iteritems
|
||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||
|
||||
def execute(filters=None):
|
||||
|
||||
@ -14,9 +15,9 @@ def execute(filters=None):
|
||||
to_date = filters["to_date"]
|
||||
data = []
|
||||
for item, item_dict in iteritems(item_details):
|
||||
fifo_queue = item_dict["fifo_queue"]
|
||||
fifo_queue = sorted(item_dict["fifo_queue"], key=lambda x: x[1])
|
||||
details = item_dict["details"]
|
||||
if not fifo_queue: continue
|
||||
if not fifo_queue or (not item_dict.get("total_qty")): continue
|
||||
|
||||
average_age = get_average_age(fifo_queue, to_date)
|
||||
earliest_age = date_diff(to_date, fifo_queue[0][1])
|
||||
@ -25,7 +26,7 @@ def execute(filters=None):
|
||||
row = [details.name, details.item_name,
|
||||
details.description, details.item_group, details.brand]
|
||||
|
||||
if filters.get("show_ageing_warehouse_wise"):
|
||||
if filters.get("show_warehouse_wise_stock"):
|
||||
row.append(details.warehouse)
|
||||
|
||||
row.extend([item_dict.get("total_qty"), average_age,
|
||||
@ -39,48 +40,150 @@ def get_average_age(fifo_queue, to_date):
|
||||
batch_age = age_qty = total_qty = 0.0
|
||||
for batch in fifo_queue:
|
||||
batch_age = date_diff(to_date, batch[1])
|
||||
age_qty += batch_age * batch[0]
|
||||
total_qty += batch[0]
|
||||
|
||||
if type(batch[0]) in ['int', 'float']:
|
||||
age_qty += batch_age * batch[0]
|
||||
total_qty += batch[0]
|
||||
else:
|
||||
age_qty += batch_age * 1
|
||||
total_qty += 1
|
||||
|
||||
return (age_qty / total_qty) if total_qty else 0.0
|
||||
|
||||
def get_columns(filters):
|
||||
columns = [_("Item Code") + ":Link/Item:100", _("Item Name") + "::100", _("Description") + "::200",
|
||||
_("Item Group") + ":Link/Item Group:100", _("Brand") + ":Link/Brand:100"]
|
||||
columns = [
|
||||
{
|
||||
"label": _("Item Code"),
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Link",
|
||||
"options": "Item",
|
||||
"width": 100
|
||||
},
|
||||
{
|
||||
"label": _("Item Name"),
|
||||
"fieldname": "item_name",
|
||||
"fieldtype": "Data",
|
||||
"width": 100
|
||||
},
|
||||
{
|
||||
"label": _("Description"),
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Data",
|
||||
"width": 200
|
||||
},
|
||||
{
|
||||
"label": _("Item Group"),
|
||||
"fieldname": "item_group",
|
||||
"fieldtype": "Link",
|
||||
"options": "Item Group",
|
||||
"width": 100
|
||||
},
|
||||
{
|
||||
"label": _("Brand"),
|
||||
"fieldname": "brand",
|
||||
"fieldtype": "Link",
|
||||
"options": "Brand",
|
||||
"width": 100
|
||||
}]
|
||||
|
||||
if filters.get("show_ageing_warehouse_wise"):
|
||||
columns.extend([_("Warehouse") + ":Link/Warehouse:100"])
|
||||
if filters.get("show_warehouse_wise_stock"):
|
||||
columns +=[{
|
||||
"label": _("Warehouse"),
|
||||
"fieldname": "warehouse",
|
||||
"fieldtype": "Link",
|
||||
"options": "Warehouse",
|
||||
"width": 100
|
||||
}]
|
||||
|
||||
columns.extend([_("Available Qty") + ":Float:100", _("Average Age") + ":Float:100",
|
||||
_("Earliest") + ":Int:80", _("Latest") + ":Int:80", _("UOM") + ":Link/UOM:100"])
|
||||
columns.extend([
|
||||
{
|
||||
"label": _("Available Qty"),
|
||||
"fieldname": "qty",
|
||||
"fieldtype": "Float",
|
||||
"width": 100
|
||||
},
|
||||
{
|
||||
"label": _("Average Age"),
|
||||
"fieldname": "average_age",
|
||||
"fieldtype": "Float",
|
||||
"width": 100
|
||||
},
|
||||
{
|
||||
"label": _("Earliest"),
|
||||
"fieldname": "earliest",
|
||||
"fieldtype": "Int",
|
||||
"width": 80
|
||||
},
|
||||
{
|
||||
"label": _("Latest"),
|
||||
"fieldname": "latest",
|
||||
"fieldtype": "Int",
|
||||
"width": 80
|
||||
},
|
||||
{
|
||||
"label": _("UOM"),
|
||||
"fieldname": "uom",
|
||||
"fieldtype": "Link",
|
||||
"options": "UOM",
|
||||
"width": 100
|
||||
}
|
||||
])
|
||||
|
||||
return columns
|
||||
|
||||
def get_fifo_queue(filters):
|
||||
item_details = {}
|
||||
for d in get_stock_ledger_entries(filters):
|
||||
key = (d.name, d.warehouse) if filters.get('show_ageing_warehouse_wise') else d.name
|
||||
transfered_item_details = {}
|
||||
serial_no_batch_purchase_details = {}
|
||||
|
||||
sle = get_stock_ledger_entries(filters)
|
||||
|
||||
for d in sle:
|
||||
key = (d.name, d.warehouse) if filters.get('show_warehouse_wise_stock') else d.name
|
||||
item_details.setdefault(key, {"details": d, "fifo_queue": []})
|
||||
fifo_queue = item_details[key]["fifo_queue"]
|
||||
|
||||
transfered_item_details.setdefault((d.voucher_no, d.name), [])
|
||||
|
||||
if d.voucher_type == "Stock Reconciliation":
|
||||
d.actual_qty = flt(d.qty_after_transaction) - flt(item_details[key].get("qty_after_transaction", 0))
|
||||
|
||||
serial_no_list = get_serial_nos(d.serial_no) if d.serial_no else []
|
||||
|
||||
if d.actual_qty > 0:
|
||||
fifo_queue.append([d.actual_qty, d.posting_date])
|
||||
else:
|
||||
qty_to_pop = abs(d.actual_qty)
|
||||
while qty_to_pop:
|
||||
batch = fifo_queue[0] if fifo_queue else [0, None]
|
||||
if 0 < batch[0] <= qty_to_pop:
|
||||
# if batch qty > 0
|
||||
# not enough or exactly same qty in current batch, clear batch
|
||||
qty_to_pop -= batch[0]
|
||||
fifo_queue.pop(0)
|
||||
if transfered_item_details.get((d.voucher_no, d.name)):
|
||||
batch = transfered_item_details[(d.voucher_no, d.name)][0]
|
||||
fifo_queue.append(batch)
|
||||
transfered_item_details[((d.voucher_no, d.name))].pop(0)
|
||||
else:
|
||||
if serial_no_list:
|
||||
for serial_no in serial_no_list:
|
||||
if serial_no_batch_purchase_details.get(serial_no):
|
||||
fifo_queue.append([serial_no, serial_no_batch_purchase_details.get(serial_no)])
|
||||
else:
|
||||
serial_no_batch_purchase_details.setdefault(serial_no, d.posting_date)
|
||||
fifo_queue.append([serial_no, d.posting_date])
|
||||
else:
|
||||
# all from current batch
|
||||
batch[0] -= qty_to_pop
|
||||
qty_to_pop = 0
|
||||
fifo_queue.append([d.actual_qty, d.posting_date])
|
||||
else:
|
||||
if serial_no_list:
|
||||
for serial_no in fifo_queue:
|
||||
if serial_no[0] in serial_no_list:
|
||||
fifo_queue.remove(serial_no)
|
||||
else:
|
||||
qty_to_pop = abs(d.actual_qty)
|
||||
while qty_to_pop:
|
||||
batch = fifo_queue[0] if fifo_queue else [0, None]
|
||||
if 0 < batch[0] <= qty_to_pop:
|
||||
# if batch qty > 0
|
||||
# not enough or exactly same qty in current batch, clear batch
|
||||
qty_to_pop -= batch[0]
|
||||
transfered_item_details[(d.voucher_no, d.name)].append(fifo_queue.pop(0))
|
||||
else:
|
||||
# all from current batch
|
||||
batch[0] -= qty_to_pop
|
||||
transfered_item_details[(d.voucher_no, d.name)].append([qty_to_pop, batch[1]])
|
||||
qty_to_pop = 0
|
||||
|
||||
item_details[key]["qty_after_transaction"] = d.qty_after_transaction
|
||||
|
||||
@ -94,7 +197,7 @@ def get_fifo_queue(filters):
|
||||
def get_stock_ledger_entries(filters):
|
||||
return frappe.db.sql("""select
|
||||
item.name, item.item_name, item_group, brand, description, item.stock_uom,
|
||||
actual_qty, posting_date, voucher_type, qty_after_transaction, warehouse
|
||||
actual_qty, posting_date, voucher_type, voucher_no, serial_no, batch_no, qty_after_transaction, warehouse
|
||||
from `tabStock Ledger Entry` sle,
|
||||
(select name, item_name, description, stock_uom, brand, item_group
|
||||
from `tabItem` {item_conditions}) item
|
||||
@ -102,7 +205,7 @@ def get_stock_ledger_entries(filters):
|
||||
company = %(company)s and
|
||||
posting_date <= %(to_date)s
|
||||
{sle_conditions}
|
||||
order by posting_date, posting_time, sle.creation"""\
|
||||
order by posting_date, posting_time, sle.creation, actual_qty""" #nosec
|
||||
.format(item_conditions=get_item_conditions(filters),
|
||||
sle_conditions=get_sle_conditions(filters)), filters, as_dict=True)
|
||||
|
||||
|
@ -363,8 +363,17 @@ class update_entries_after(object):
|
||||
self.stock_queue.append([0, sle.incoming_rate or sle.outgoing_rate or self.valuation_rate])
|
||||
|
||||
def check_if_allow_zero_valuation_rate(self, voucher_type, voucher_detail_no):
|
||||
ref_item_dt = voucher_type + (" Detail" if voucher_type == "Stock Entry" else " Item")
|
||||
return frappe.db.get_value(ref_item_dt, voucher_detail_no, "allow_zero_valuation_rate")
|
||||
ref_item_dt = ""
|
||||
|
||||
if voucher_type == "Stock Entry":
|
||||
ref_item_dt = voucher_type + " Detail"
|
||||
elif voucher_type in ["Purchase Invoice", "Sales Invoice", "Delivery Note", "Purchase Receipt"]:
|
||||
ref_item_dt = voucher_type + " Item"
|
||||
|
||||
if ref_item_dt:
|
||||
return frappe.db.get_value(ref_item_dt, voucher_detail_no, "allow_zero_valuation_rate")
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_sle_before_datetime(self):
|
||||
"""get previous stock ledger entry before current time-bucket"""
|
||||
|
@ -210,6 +210,7 @@ class Issue(Document):
|
||||
|
||||
self.service_level_agreement_creation = now_datetime()
|
||||
self.set_response_and_resolution_time(priority=self.priority, service_level_agreement=self.service_level_agreement)
|
||||
self.agreement_fulfilled = "Ongoing"
|
||||
self.save()
|
||||
|
||||
def get_expected_time_for(parameter, service_level, start_date_time):
|
||||
|
@ -2,45 +2,31 @@
|
||||
# MIT License. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
from frappe.desk import notifications
|
||||
from frappe.test_runner import make_test_objects
|
||||
|
||||
class TestNotifications(unittest.TestCase):
|
||||
def setUp(self):
|
||||
test_records_company = [
|
||||
{
|
||||
"abbr": "_TC6",
|
||||
"company_name": "_Test Company 6",
|
||||
"country": "India",
|
||||
"default_currency": "INR",
|
||||
"doctype": "Company",
|
||||
"domain": "Manufacturing",
|
||||
"monthly_sales_target": 2000,
|
||||
"chart_of_accounts": "Standard"
|
||||
},
|
||||
{
|
||||
"abbr": "_TC7",
|
||||
"company_name": "_Test Company 7",
|
||||
"country": "United States",
|
||||
"default_currency": "USD",
|
||||
"doctype": "Company",
|
||||
"domain": "Retail",
|
||||
"monthly_sales_target": 10000,
|
||||
"total_monthly_sales": 1000,
|
||||
"chart_of_accounts": "Standard"
|
||||
},
|
||||
]
|
||||
|
||||
make_test_objects('Company', test_records=test_records_company, reset=True)
|
||||
|
||||
def test_get_notifications_for_targets(self):
|
||||
'''
|
||||
Test notification config entries for targets as percentages
|
||||
'''
|
||||
|
||||
company = frappe.get_all("Company")[0]
|
||||
frappe.db.set_value("Company", company.name, "monthly_sales_target", 10000)
|
||||
frappe.db.set_value("Company", company.name, "total_monthly_sales", 1000)
|
||||
|
||||
config = notifications.get_notification_config()
|
||||
doc_target_percents = notifications.get_notifications_for_targets(config, {})
|
||||
self.assertEqual(doc_target_percents['Company']['_Test Company 7'], 10)
|
||||
self.assertEqual(doc_target_percents['Company']['_Test Company 6'], 0)
|
||||
|
||||
self.assertEqual(doc_target_percents['Company'][company.name], 10)
|
||||
|
||||
frappe.db.set_value("Company", company.name, "monthly_sales_target", 2000)
|
||||
frappe.db.set_value("Company", company.name, "total_monthly_sales", 0)
|
||||
|
||||
config = notifications.get_notification_config()
|
||||
doc_target_percents = notifications.get_notifications_for_targets(config, {})
|
||||
|
||||
self.assertEqual(doc_target_percents['Company'][company.name], 0)
|
||||
|
@ -1 +0,0 @@
|
||||
erpnext
|
@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd ~/
|
||||
curl -I https://github.com/frappe/frappe/tree/$TRAVIS_BRANCH | head -n 1 | cut -d $' ' -f2 | (
|
||||
read response;
|
||||
[ $response == '200' ] && branch=$TRAVIS_BRANCH || branch='develop';
|
||||
bench init frappe-bench --frappe-path https://github.com/frappe/frappe.git --frappe-branch $branch --python $(which python)
|
||||
)
|
@ -1,12 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
if [[ $TEST_TYPE == 'Server Side Test' ]]; then
|
||||
bench run-tests --app erpnext --coverage
|
||||
|
||||
elif [[ $TEST_TYPE == 'Patch Test' ]]; then
|
||||
wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
|
||||
bench --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz --mariadb-root-password travis
|
||||
bench migrate
|
||||
fi
|
Loading…
x
Reference in New Issue
Block a user