fix: conflicts
This commit is contained in:
parent
e29d5c1d5b
commit
99321cd538
16
.github/workflows/backport.yml
vendored
Normal file
16
.github/workflows/backport.yml
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
name: Backport
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types:
|
||||||
|
- closed
|
||||||
|
- labeled
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
backport:
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
name: Backport
|
||||||
|
steps:
|
||||||
|
- name: Backport
|
||||||
|
uses: tibdex/backport@v1
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
8
.snyk
Normal file
8
.snyk
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
|
||||||
|
version: v1.14.0
|
||||||
|
ignore: {}
|
||||||
|
# patches apply the minimum changes required to fix a vulnerability
|
||||||
|
patch:
|
||||||
|
SNYK-JS-LODASH-450202:
|
||||||
|
- cypress > getos > async > lodash:
|
||||||
|
patched: '2020-01-31T01:35:12.802Z'
|
@ -77,5 +77,6 @@ install:
|
|||||||
- bench --site test_site reinstall --yes
|
- bench --site test_site reinstall --yes
|
||||||
|
|
||||||
after_script:
|
after_script:
|
||||||
|
- pip install coverage==4.5.4
|
||||||
- pip install python-coveralls
|
- pip install python-coveralls
|
||||||
- coveralls -b apps/erpnext -d ../../sites/.coverage
|
- coveralls -b apps/erpnext -d ../../sites/.coverage
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"baseUrl": "http://test_site_ui:8000"
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Using fixtures to represent data",
|
|
||||||
"email": "hello@cypress.io",
|
|
||||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
context('Form', () => {
|
|
||||||
before(() => {
|
|
||||||
cy.login('Administrator', 'qwe');
|
|
||||||
cy.visit('/desk');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('create a new opportunity', () => {
|
|
||||||
cy.visit('/desk#Form/Opportunity/New Opportunity 1');
|
|
||||||
cy.get('.page-title').should('contain', 'Not Saved');
|
|
||||||
cy.fill_field('opportunity_from', 'Customer', 'Select');
|
|
||||||
cy.fill_field('party_name', 'Test Customer', 'Link').blur();
|
|
||||||
cy.get('.primary-action').click();
|
|
||||||
cy.get('.page-title').should('contain', 'Open');
|
|
||||||
cy.get('.form-inner-toolbar button:contains("Lost")').click({ force: true });
|
|
||||||
cy.get('.modal input[data-fieldname="lost_reason"]').as('input');
|
|
||||||
cy.get('@input').focus().type('Higher', { delay: 200 });
|
|
||||||
cy.get('.modal .awesomplete ul')
|
|
||||||
.should('be.visible')
|
|
||||||
.get('li:contains("Higher Price")')
|
|
||||||
.click({ force: true });
|
|
||||||
cy.get('@input').focus().type('No Followup', { delay: 200 });
|
|
||||||
cy.get('.modal .awesomplete ul')
|
|
||||||
.should('be.visible')
|
|
||||||
.get('li:contains("No Followup")')
|
|
||||||
.click();
|
|
||||||
|
|
||||||
cy.fill_field('detailed_reason', 'Test Detailed Reason', 'Text');
|
|
||||||
cy.get('.modal button:contains("Declare Lost")').click({ force: true });
|
|
||||||
cy.get('.page-title').should('contain', 'Lost');
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,17 +0,0 @@
|
|||||||
// ***********************************************************
|
|
||||||
// This example plugins/index.js can be used to load plugins
|
|
||||||
//
|
|
||||||
// You can change the location of this file or turn off loading
|
|
||||||
// the plugins file with the 'pluginsFile' configuration option.
|
|
||||||
//
|
|
||||||
// You can read more here:
|
|
||||||
// https://on.cypress.io/plugins-guide
|
|
||||||
// ***********************************************************
|
|
||||||
|
|
||||||
// This function is called when a project is opened or re-opened (e.g. due to
|
|
||||||
// the project's config changing)
|
|
||||||
|
|
||||||
// module.exports = (on, config) => {
|
|
||||||
// `on` is used to hook into various events Cypress emits
|
|
||||||
// `config` is the resolved Cypress config
|
|
||||||
// }
|
|
@ -1,25 +0,0 @@
|
|||||||
// ***********************************************
|
|
||||||
// This example commands.js shows you how to
|
|
||||||
// create various custom commands and overwrite
|
|
||||||
// existing commands.
|
|
||||||
//
|
|
||||||
// For more comprehensive examples of custom
|
|
||||||
// commands please read more here:
|
|
||||||
// https://on.cypress.io/custom-commands
|
|
||||||
// ***********************************************
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This is a parent command --
|
|
||||||
// Cypress.Commands.add("login", (email, password) => { ... })
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This is a child command --
|
|
||||||
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This is a dual command --
|
|
||||||
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This is will overwrite an existing command --
|
|
||||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
|
@ -1,22 +0,0 @@
|
|||||||
// ***********************************************************
|
|
||||||
// This example support/index.js is processed and
|
|
||||||
// loaded automatically before your test files.
|
|
||||||
//
|
|
||||||
// This is a great place to put global configuration and
|
|
||||||
// behavior that modifies Cypress.
|
|
||||||
//
|
|
||||||
// You can change the location of this file or turn off
|
|
||||||
// automatically serving support files with the
|
|
||||||
// 'supportFile' configuration option.
|
|
||||||
//
|
|
||||||
// You can read more here:
|
|
||||||
// https://on.cypress.io/configuration
|
|
||||||
// ***********************************************************
|
|
||||||
|
|
||||||
// import frappe commands
|
|
||||||
import '../../../frappe/cypress/support/index';
|
|
||||||
// Import commands.js using ES2015 syntax:
|
|
||||||
import './commands';
|
|
||||||
|
|
||||||
// Alternatively you can use CommonJS syntax:
|
|
||||||
// require('./commands')
|
|
@ -4,7 +4,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe, json
|
import frappe, json
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import add_to_date, date_diff, getdate, nowdate, get_last_day, formatdate
|
from frappe.utils import add_to_date, date_diff, getdate, nowdate, get_last_day, formatdate, get_link_to_form
|
||||||
from erpnext.accounts.report.general_ledger.general_ledger import execute
|
from erpnext.accounts.report.general_ledger.general_ledger import execute
|
||||||
from frappe.core.page.dashboard.dashboard import cache_source, get_from_date_from_timespan
|
from frappe.core.page.dashboard.dashboard import cache_source, get_from_date_from_timespan
|
||||||
from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_period_ending
|
from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_period_ending
|
||||||
@ -30,8 +30,13 @@ def get(chart_name = None, chart = None, no_cache = None, from_date = None, to_d
|
|||||||
account = filters.get("account")
|
account = filters.get("account")
|
||||||
company = filters.get("company")
|
company = filters.get("company")
|
||||||
|
|
||||||
if not account and chart:
|
if not account and chart_name:
|
||||||
frappe.throw(_("Account is not set for the dashboard chart {0}").format(chart))
|
frappe.throw(_("Account is not set for the dashboard chart {0}")
|
||||||
|
.format(get_link_to_form("Dashboard Chart", chart_name)))
|
||||||
|
|
||||||
|
if not frappe.db.exists("Account", account) and chart_name:
|
||||||
|
frappe.throw(_("Account {0} does not exists in the dashboard chart {1}")
|
||||||
|
.format(account, get_link_to_form("Dashboard Chart", chart_name)))
|
||||||
|
|
||||||
if not to_date:
|
if not to_date:
|
||||||
to_date = nowdate()
|
to_date = nowdate()
|
||||||
|
@ -30,7 +30,7 @@ def validate_service_stop_date(doc):
|
|||||||
frappe.throw(_("Service Stop Date cannot be after Service End Date"))
|
frappe.throw(_("Service Stop Date cannot be after Service End Date"))
|
||||||
|
|
||||||
if old_stop_dates and old_stop_dates.get(item.name) and item.service_stop_date!=old_stop_dates.get(item.name):
|
if old_stop_dates and old_stop_dates.get(item.name) and item.service_stop_date!=old_stop_dates.get(item.name):
|
||||||
frappe.throw(_("Cannot change Service Stop Date for item in row {0}".format(item.idx)))
|
frappe.throw(_("Cannot change Service Stop Date for item in row {0}").format(item.idx))
|
||||||
|
|
||||||
def convert_deferred_expense_to_expense(start_date=None, end_date=None):
|
def convert_deferred_expense_to_expense(start_date=None, end_date=None):
|
||||||
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
|
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
|
||||||
|
@ -0,0 +1,526 @@
|
|||||||
|
{
|
||||||
|
"country_code": "de",
|
||||||
|
"name": "SKR03 mit Kontonummern",
|
||||||
|
"tree": {
|
||||||
|
"Aktiva": {
|
||||||
|
"is_group": 1,
|
||||||
|
"root_type": "Asset",
|
||||||
|
"A - Anlagevermögen": {
|
||||||
|
"is_group": 1,
|
||||||
|
"EDV-Software": {
|
||||||
|
"account_number": "0027",
|
||||||
|
"account_type": "Fixed Asset"
|
||||||
|
},
|
||||||
|
"Gesch\u00e4ftsausstattung": {
|
||||||
|
"account_number": "0410",
|
||||||
|
"account_type": "Fixed Asset"
|
||||||
|
},
|
||||||
|
"B\u00fcroeinrichtung": {
|
||||||
|
"account_number": "0420",
|
||||||
|
"account_type": "Fixed Asset"
|
||||||
|
},
|
||||||
|
"Darlehen": {
|
||||||
|
"account_number": "0565"
|
||||||
|
},
|
||||||
|
"Maschinen": {
|
||||||
|
"account_number": "0210",
|
||||||
|
"account_type": "Fixed Asset"
|
||||||
|
},
|
||||||
|
"Betriebsausstattung": {
|
||||||
|
"account_number": "0400",
|
||||||
|
"account_type": "Fixed Asset"
|
||||||
|
},
|
||||||
|
"Ladeneinrichtung": {
|
||||||
|
"account_number": "0430",
|
||||||
|
"account_type": "Fixed Asset"
|
||||||
|
},
|
||||||
|
"Accumulated Depreciation": {
|
||||||
|
"account_type": "Accumulated Depreciation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"B - Umlaufvermögen": {
|
||||||
|
"is_group": 1,
|
||||||
|
"I. Vorräte": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Roh-, Hilfs- und Betriebsstoffe (Bestand)": {
|
||||||
|
"account_number": "3970",
|
||||||
|
"account_type": "Stock"
|
||||||
|
},
|
||||||
|
"Waren (Bestand)": {
|
||||||
|
"account_number": "3980",
|
||||||
|
"account_type": "Stock"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"II. Forderungen und sonstige Vermögensgegenstände": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Ford. a. Lieferungen und Leistungen": {
|
||||||
|
"account_number": "1400",
|
||||||
|
"account_type": "Receivable"
|
||||||
|
},
|
||||||
|
"Durchlaufende Posten": {
|
||||||
|
"account_number": "1590"
|
||||||
|
},
|
||||||
|
"Gewinnermittlung \u00a74/3 nicht Ergebniswirksam": {
|
||||||
|
"account_number": "1371"
|
||||||
|
},
|
||||||
|
"Abziehbare VSt. 7%": {
|
||||||
|
"account_number": "1571"
|
||||||
|
},
|
||||||
|
"Abziehbare VSt. 19%": {
|
||||||
|
"account_number": "1576"
|
||||||
|
},
|
||||||
|
"Abziehbare VStr. nach \u00a713b UStG 19%": {
|
||||||
|
"account_number": "1577"
|
||||||
|
},
|
||||||
|
"Leistungen \u00a713b UStG 19% Vorsteuer, 19% Umsatzsteuer": {
|
||||||
|
"account_number": "3120"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"III. Wertpapiere": {
|
||||||
|
"is_group": 1
|
||||||
|
},
|
||||||
|
"IV. Kassenbestand, Bundesbankguthaben, Guthaben bei Kreditinstituten und Schecks.": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Kasse": {
|
||||||
|
"account_type": "Cash",
|
||||||
|
"is_group": 1,
|
||||||
|
"Kasse": {
|
||||||
|
"is_group": 1,
|
||||||
|
"account_number": "1000",
|
||||||
|
"account_type": "Cash"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Bank": {
|
||||||
|
"is_group": 1,
|
||||||
|
"account_type": "Bank",
|
||||||
|
"Postbank": {
|
||||||
|
"account_number": "1100",
|
||||||
|
"account_type": "Bank"
|
||||||
|
},
|
||||||
|
"Bankkonto": {
|
||||||
|
"account_number": "1200",
|
||||||
|
"account_type": "Bank"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"C - Rechnungsabgrenzungsposten": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Aktive Rechnungsabgrenzung": {
|
||||||
|
"account_number": "0980"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"D - Aktive latente Steuern": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Aktive latente Steuern": {
|
||||||
|
"account_number": "0983"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"E - Aktiver Unterschiedsbetrag aus der Vermögensverrechnung": {
|
||||||
|
"is_group": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Passiva": {
|
||||||
|
"is_group": 1,
|
||||||
|
"root_type": "Liability",
|
||||||
|
"A. Eigenkapital": {
|
||||||
|
"is_group": 1,
|
||||||
|
"I. Gezeichnetes Kapital": {
|
||||||
|
"is_group": 1
|
||||||
|
},
|
||||||
|
"II. Kapitalrücklage": {
|
||||||
|
"is_group": 1
|
||||||
|
},
|
||||||
|
"III. Gewinnrücklagen": {
|
||||||
|
"is_group": 1
|
||||||
|
},
|
||||||
|
"IV. Gewinnvortrag/Verlustvortrag": {
|
||||||
|
"is_group": 1
|
||||||
|
},
|
||||||
|
"V. Jahresüberschuß/Jahresfehlbetrag": {
|
||||||
|
"is_group": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"B. Rückstellungen": {
|
||||||
|
"is_group": 1,
|
||||||
|
"I. Rückstellungen für Pensionen und ähnliche Verpflichtungen": {
|
||||||
|
"is_group": 1
|
||||||
|
},
|
||||||
|
"II. Steuerrückstellungen": {
|
||||||
|
"is_group": 1
|
||||||
|
},
|
||||||
|
"III. sonstige Rückstellungen": {
|
||||||
|
"is_group": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"C. Verbindlichkeiten": {
|
||||||
|
"is_group": 1,
|
||||||
|
"I. Anleihen": {
|
||||||
|
"is_group": 1
|
||||||
|
},
|
||||||
|
"II. Verbindlichkeiten gegenüber Kreditinstituten": {
|
||||||
|
"is_group": 1
|
||||||
|
},
|
||||||
|
"III. Erhaltene Anzahlungen auf Bestellungen": {
|
||||||
|
"is_group": 1
|
||||||
|
},
|
||||||
|
"IV. Verbindlichkeiten aus Lieferungen und Leistungen": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Verbindlichkeiten aus Lieferungen u. Leistungen": {
|
||||||
|
"account_number": "1600",
|
||||||
|
"account_type": "Payable"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"V. Verbindlichkeiten aus der Annahme gezogener Wechsel und der Ausstellung eigener Wechsel": {
|
||||||
|
"is_group": 1
|
||||||
|
},
|
||||||
|
"VI. Verbindlichkeiten gegenüber verbundenen Unternehmen": {
|
||||||
|
"is_group": 1
|
||||||
|
},
|
||||||
|
"VII. Verbindlichkeiten gegenüber Unternehmen, mit denen ein Beteiligungsverhältnis besteht": {
|
||||||
|
"is_group": 1
|
||||||
|
},
|
||||||
|
"VIII. sonstige Verbindlichkeiten": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Sonstige Verbindlichkeiten": {
|
||||||
|
"account_number": "1700",
|
||||||
|
"account_type": "Asset Received But Not Billed"
|
||||||
|
},
|
||||||
|
"Sonstige Verbindlichkeiten (1 bis 5 Jahre)": {
|
||||||
|
"account_number": "1702",
|
||||||
|
"account_type": "Stock Received But Not Billed"
|
||||||
|
},
|
||||||
|
"Verbindlichkeiten aus Lohn und Gehalt": {
|
||||||
|
"account_number": "1740",
|
||||||
|
"account_type": "Payable"
|
||||||
|
},
|
||||||
|
"Umsatzsteuer": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Umsatzsteuer 7%": {
|
||||||
|
"account_number": "1771"
|
||||||
|
},
|
||||||
|
"Umsatzsteuer 19%": {
|
||||||
|
"account_number": "1776"
|
||||||
|
},
|
||||||
|
"Umsatzsteuer-Vorauszahlung": {
|
||||||
|
"account_number": "1780"
|
||||||
|
},
|
||||||
|
"Umsatzsteuer-Vorauszahlung 1/11": {
|
||||||
|
"account_number": "1781"
|
||||||
|
},
|
||||||
|
"Umsatzsteuer \u00a7 13b UStG 19%": {
|
||||||
|
"account_number": "1787"
|
||||||
|
},
|
||||||
|
"Umsatzsteuer Vorjahr": {
|
||||||
|
"account_number": "1790"
|
||||||
|
},
|
||||||
|
"Umsatzsteuer fr\u00fchere Jahre": {
|
||||||
|
"account_number": "1791"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"D. Rechnungsabgrenzungsposten": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Passive Rechnungsabgrenzung": {
|
||||||
|
"account_number": "0990"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"E. Passive latente Steuern": {
|
||||||
|
"is_group": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Erl\u00f6se u. Ertr\u00e4ge 2/8": {
|
||||||
|
"is_group": 1,
|
||||||
|
"root_type": "Income",
|
||||||
|
"Erl\u00f6skonten 8": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Erl\u00f6se": {
|
||||||
|
"account_number": "8200",
|
||||||
|
"account_type": "Income Account"
|
||||||
|
},
|
||||||
|
"Erl\u00f6se USt. 19%": {
|
||||||
|
"account_number": "8400",
|
||||||
|
"account_type": "Income Account"
|
||||||
|
},
|
||||||
|
"Erl\u00f6se USt. 7%": {
|
||||||
|
"account_number": "8300",
|
||||||
|
"account_type": "Income Account"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Ertragskonten 2": {
|
||||||
|
"is_group": 1,
|
||||||
|
"sonstige Zinsen und \u00e4hnliche Ertr\u00e4ge": {
|
||||||
|
"account_number": "2650",
|
||||||
|
"account_type": "Income Account"
|
||||||
|
},
|
||||||
|
"Au\u00dferordentliche Ertr\u00e4ge": {
|
||||||
|
"account_number": "2500",
|
||||||
|
"account_type": "Income Account"
|
||||||
|
},
|
||||||
|
"Sonstige Ertr\u00e4ge": {
|
||||||
|
"account_number": "2700",
|
||||||
|
"account_type": "Income Account"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Aufwendungen 2/4": {
|
||||||
|
"is_group": 1,
|
||||||
|
"root_type": "Expense",
|
||||||
|
"Wareneingang": {
|
||||||
|
"account_number": "3200"
|
||||||
|
},
|
||||||
|
"Bezugsnebenkosten": {
|
||||||
|
"account_number": "3800",
|
||||||
|
"account_type": "Expenses Included In Asset Valuation"
|
||||||
|
},
|
||||||
|
"Herstellungskosten": {
|
||||||
|
"account_number": "4996",
|
||||||
|
"account_type": "Cost of Goods Sold"
|
||||||
|
},
|
||||||
|
"Verluste aus dem Abgang von Gegenständen des Anlagevermögens": {
|
||||||
|
"account_number": "2320",
|
||||||
|
"account_type": "Stock Adjustment"
|
||||||
|
},
|
||||||
|
"Verwaltungskosten": {
|
||||||
|
"account_number": "4997",
|
||||||
|
"account_type": "Expenses Included In Valuation"
|
||||||
|
},
|
||||||
|
"Vertriebskosten": {
|
||||||
|
"account_number": "4998",
|
||||||
|
"account_type": "Expenses Included In Valuation"
|
||||||
|
},
|
||||||
|
"Gegenkonto 4996-4998": {
|
||||||
|
"account_number": "4999"
|
||||||
|
},
|
||||||
|
"Abschreibungen": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Abschreibungen auf Sachanlagen (ohne AfA auf Kfz und Gebäude)": {
|
||||||
|
"account_number": "4830",
|
||||||
|
"account_type": "Accumulated Depreciation"
|
||||||
|
},
|
||||||
|
"Abschreibungen auf Gebäude": {
|
||||||
|
"account_number": "4831",
|
||||||
|
"account_type": "Depreciation"
|
||||||
|
},
|
||||||
|
"Abschreibungen auf Kfz": {
|
||||||
|
"account_number": "4832",
|
||||||
|
"account_type": "Depreciation"
|
||||||
|
},
|
||||||
|
"Sofortabschreibung GWG": {
|
||||||
|
"account_number": "4855",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Kfz-Kosten": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Kfz-Steuer": {
|
||||||
|
"account_number": "4510",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Kfz-Versicherungen": {
|
||||||
|
"account_number": "4520",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"laufende Kfz-Betriebskosten": {
|
||||||
|
"account_number": "4530",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Kfz-Reparaturen": {
|
||||||
|
"account_number": "4540",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Fremdfahrzeuge": {
|
||||||
|
"account_number": "4570",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"sonstige Kfz-Kosten": {
|
||||||
|
"account_number": "4580",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Personalkosten": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Geh\u00e4lter": {
|
||||||
|
"account_number": "4120",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"gesetzliche soziale Aufwendungen": {
|
||||||
|
"account_number": "4130",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Aufwendungen f\u00fcr Altersvorsorge": {
|
||||||
|
"account_number": "4165",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Verm\u00f6genswirksame Leistungen": {
|
||||||
|
"account_number": "4170",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Aushilfsl\u00f6hne": {
|
||||||
|
"account_number": "4190",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Raumkosten": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Miete und Nebenkosten": {
|
||||||
|
"account_number": "4210",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Gas, Wasser, Strom (Verwaltung, Vertrieb)": {
|
||||||
|
"account_number": "4240",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Reinigung": {
|
||||||
|
"account_number": "4250",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Reparatur/Instandhaltung": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Reparatur u. Instandh. von Anlagen/Maschinen u. Betriebs- u. Gesch\u00e4ftsausst.": {
|
||||||
|
"account_number": "4805",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Versicherungsbeitr\u00e4ge": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Versicherungen": {
|
||||||
|
"account_number": "4360",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Beitr\u00e4ge": {
|
||||||
|
"account_number": "4380",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"sonstige Ausgaben": {
|
||||||
|
"account_number": "4390",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"steuerlich abzugsf\u00e4hige Versp\u00e4tungszuschl\u00e4ge und Zwangsgelder": {
|
||||||
|
"account_number": "4396",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Werbe-/Reisekosten": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Werbekosten": {
|
||||||
|
"account_number": "4610",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Aufmerksamkeiten": {
|
||||||
|
"account_number": "4653",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"nicht abzugsf\u00e4hige Betriebsausg. aus Werbe-, Repr\u00e4s.- u. Reisekosten": {
|
||||||
|
"account_number": "4665",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Reisekosten Unternehmer": {
|
||||||
|
"account_number": "4670",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"verschiedene Kosten": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Porto": {
|
||||||
|
"account_number": "4910",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Telekom": {
|
||||||
|
"account_number": "4920",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Mobilfunk D2": {
|
||||||
|
"account_number": "4921",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Internet": {
|
||||||
|
"account_number": "4922",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"B\u00fcrobedarf": {
|
||||||
|
"account_number": "4930",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Zeitschriften, B\u00fccher": {
|
||||||
|
"account_number": "4940",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Fortbildungskosten": {
|
||||||
|
"account_number": "4945",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Buchf\u00fchrungskosten": {
|
||||||
|
"account_number": "4955",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Abschlu\u00df- u. Pr\u00fcfungskosten": {
|
||||||
|
"account_number": "4957",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Nebenkosten des Geldverkehrs": {
|
||||||
|
"account_number": "4970",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Werkzeuge und Kleinger\u00e4te": {
|
||||||
|
"account_number": "4985",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Zinsaufwendungen": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Zinsaufwendungen f\u00fcr kurzfristige Verbindlichkeiten": {
|
||||||
|
"account_number": "2110",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
},
|
||||||
|
"Zinsaufwendungen f\u00fcr KFZ Finanzierung": {
|
||||||
|
"account_number": "2121",
|
||||||
|
"account_type": "Expense Account"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Anfangsbestand 9": {
|
||||||
|
"is_group": 1,
|
||||||
|
"root_type": "Equity",
|
||||||
|
"Saldenvortragskonten": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Saldenvortrag Sachkonten": {
|
||||||
|
"account_number": "9000"
|
||||||
|
},
|
||||||
|
"Saldenvortr\u00e4ge Debitoren": {
|
||||||
|
"account_number": "9008"
|
||||||
|
},
|
||||||
|
"Saldenvortr\u00e4ge Kreditoren": {
|
||||||
|
"account_number": "9009"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Privatkonten 1": {
|
||||||
|
"is_group": 1,
|
||||||
|
"root_type": "Equity",
|
||||||
|
"Privatentnahmen/-einlagen": {
|
||||||
|
"is_group": 1,
|
||||||
|
"Privatentnahme allgemein": {
|
||||||
|
"account_number": "1800"
|
||||||
|
},
|
||||||
|
"Privatsteuern": {
|
||||||
|
"account_number": "1810"
|
||||||
|
},
|
||||||
|
"Sonderausgaben beschr\u00e4nkt abzugsf\u00e4hig": {
|
||||||
|
"account_number": "1820"
|
||||||
|
},
|
||||||
|
"Sonderausgaben unbeschr\u00e4nkt abzugsf\u00e4hig": {
|
||||||
|
"account_number": "1830"
|
||||||
|
},
|
||||||
|
"Au\u00dfergew\u00f6hnliche Belastungen": {
|
||||||
|
"account_number": "1850"
|
||||||
|
},
|
||||||
|
"Privateinlagen": {
|
||||||
|
"account_number": "1890"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 1,
|
"allow_rename": 1,
|
||||||
"creation": "2017-05-29 21:35:13.136357",
|
"creation": "2017-05-29 21:35:13.136357",
|
||||||
@ -82,7 +83,7 @@
|
|||||||
"default": "0",
|
"default": "0",
|
||||||
"fieldname": "is_default",
|
"fieldname": "is_default",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Is the Default Account"
|
"label": "Is Default Account"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
@ -211,7 +212,8 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2019-10-02 01:34:12.417601",
|
"links": [],
|
||||||
|
"modified": "2020-01-29 20:42:26.458316",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Bank Account",
|
"name": "Bank Account",
|
||||||
|
@ -31,7 +31,7 @@ class TestBankAccount(unittest.TestCase):
|
|||||||
try:
|
try:
|
||||||
bank_account.validate_iban()
|
bank_account.validate_iban()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
msg = _('BankAccount.validate_iban() failed for empty IBAN')
|
msg = 'BankAccount.validate_iban() failed for empty IBAN'
|
||||||
self.fail(msg=msg)
|
self.fail(msg=msg)
|
||||||
|
|
||||||
for iban in valid_ibans:
|
for iban in valid_ibans:
|
||||||
@ -39,11 +39,11 @@ class TestBankAccount(unittest.TestCase):
|
|||||||
try:
|
try:
|
||||||
bank_account.validate_iban()
|
bank_account.validate_iban()
|
||||||
except ValidationError:
|
except ValidationError:
|
||||||
msg = _('BankAccount.validate_iban() failed for valid IBAN {}'.format(iban))
|
msg = 'BankAccount.validate_iban() failed for valid IBAN {}'.format(iban)
|
||||||
self.fail(msg=msg)
|
self.fail(msg=msg)
|
||||||
|
|
||||||
for not_iban in invalid_ibans:
|
for not_iban in invalid_ibans:
|
||||||
bank_account.iban = not_iban
|
bank_account.iban = not_iban
|
||||||
msg = _('BankAccount.validate_iban() accepted invalid IBAN {}'.format(not_iban))
|
msg = 'BankAccount.validate_iban() accepted invalid IBAN {}'.format(not_iban)
|
||||||
with self.assertRaises(ValidationError, msg=msg):
|
with self.assertRaises(ValidationError, msg=msg):
|
||||||
bank_account.validate_iban()
|
bank_account.validate_iban()
|
||||||
|
@ -3,16 +3,16 @@
|
|||||||
|
|
||||||
frappe.ui.form.on("Bank Reconciliation", {
|
frappe.ui.form.on("Bank Reconciliation", {
|
||||||
setup: function(frm) {
|
setup: function(frm) {
|
||||||
frm.add_fetch("bank_account", "account_currency", "account_currency");
|
frm.add_fetch("account", "account_currency", "account_currency");
|
||||||
},
|
},
|
||||||
|
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
|
|
||||||
let default_bank_account = frappe.defaults.get_user_default("Company")?
|
let default_bank_account = frappe.defaults.get_user_default("Company")?
|
||||||
locals[":Company"][frappe.defaults.get_user_default("Company")]["default_bank_account"]: "";
|
locals[":Company"][frappe.defaults.get_user_default("Company")]["default_bank_account"]: "";
|
||||||
frm.set_value("bank_account", default_bank_account);
|
frm.set_value("account", default_bank_account);
|
||||||
|
|
||||||
frm.set_query("bank_account", function() {
|
frm.set_query("account", function() {
|
||||||
return {
|
return {
|
||||||
"filters": {
|
"filters": {
|
||||||
"account_type": ["in",["Bank","Cash"]],
|
"account_type": ["in",["Bank","Cash"]],
|
||||||
|
@ -19,10 +19,9 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"description": "Select account head of the bank where cheque was deposited.",
|
"fetch_from": "bank_account.account",
|
||||||
"fetch_from": "bank_account_no.account",
|
|
||||||
"fetch_if_empty": 1,
|
"fetch_if_empty": 1,
|
||||||
"fieldname": "bank_account",
|
"fieldname": "account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
@ -31,7 +30,7 @@
|
|||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Bank Account",
|
"label": "Account",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"options": "Account",
|
"options": "Account",
|
||||||
@ -164,7 +163,6 @@
|
|||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
@ -183,8 +181,9 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"description": "Select the Bank Account to reconcile.",
|
||||||
"fetch_if_empty": 0,
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "bank_account_no",
|
"fieldname": "bank_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
@ -193,12 +192,11 @@
|
|||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Bank Account No",
|
"label": "Bank Account",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"options": "Bank Account",
|
"options": "Bank Account",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
@ -450,7 +448,7 @@
|
|||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"menu_index": 0,
|
"menu_index": 0,
|
||||||
"modified": "2019-04-09 18:41:06.110453",
|
"modified": "2020-01-22 00:00:00.000000",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Bank Reconciliation",
|
"name": "Bank Reconciliation",
|
||||||
|
@ -13,18 +13,16 @@ form_grid_templates = {
|
|||||||
|
|
||||||
class BankReconciliation(Document):
|
class BankReconciliation(Document):
|
||||||
def get_payment_entries(self):
|
def get_payment_entries(self):
|
||||||
if not (self.bank_account and self.from_date and self.to_date):
|
if not (self.from_date and self.to_date):
|
||||||
msgprint(_("Bank Account, From Date and To Date are Mandatory"))
|
frappe.throw(_("From Date and To Date are Mandatory"))
|
||||||
return
|
|
||||||
|
if not self.account:
|
||||||
|
frappe.throw(_("Account is mandatory to get payment entries"))
|
||||||
|
|
||||||
condition = ""
|
condition = ""
|
||||||
if not self.include_reconciled_entries:
|
if not self.include_reconciled_entries:
|
||||||
condition = " and (clearance_date is null or clearance_date='0000-00-00')"
|
condition = " and (clearance_date is null or clearance_date='0000-00-00')"
|
||||||
|
|
||||||
account_cond = ""
|
|
||||||
if self.bank_account_no:
|
|
||||||
account_cond = " and t2.bank_account_no = {0}".format(frappe.db.escape(self.bank_account_no))
|
|
||||||
|
|
||||||
journal_entries = frappe.db.sql("""
|
journal_entries = frappe.db.sql("""
|
||||||
select
|
select
|
||||||
"Journal Entry" as payment_document, t1.name as payment_entry,
|
"Journal Entry" as payment_document, t1.name as payment_entry,
|
||||||
@ -34,15 +32,17 @@ class BankReconciliation(Document):
|
|||||||
from
|
from
|
||||||
`tabJournal Entry` t1, `tabJournal Entry Account` t2
|
`tabJournal Entry` t1, `tabJournal Entry Account` t2
|
||||||
where
|
where
|
||||||
t2.parent = t1.name and t2.account = %s and t1.docstatus=1
|
t2.parent = t1.name and t2.account = %(account)s and t1.docstatus=1
|
||||||
and t1.posting_date >= %s and t1.posting_date <= %s
|
and t1.posting_date >= %(from)s and t1.posting_date <= %(to)s
|
||||||
and ifnull(t1.is_opening, 'No') = 'No' {0} {1}
|
and ifnull(t1.is_opening, 'No') = 'No' %(condition)s
|
||||||
group by t2.account, t1.name
|
group by t2.account, t1.name
|
||||||
order by t1.posting_date ASC, t1.name DESC
|
order by t1.posting_date ASC, t1.name DESC
|
||||||
""".format(condition, account_cond), (self.bank_account, self.from_date, self.to_date), as_dict=1)
|
""", {"condition":condition, "account": self.account, "from": self.from_date, "to": self.to_date}, as_dict=1)
|
||||||
|
|
||||||
if self.bank_account_no:
|
condition = ''
|
||||||
condition = " and bank_account = %(bank_account_no)s"
|
|
||||||
|
if self.bank_account:
|
||||||
|
condition += 'and bank_account = %(bank_account)s'
|
||||||
|
|
||||||
payment_entries = frappe.db.sql("""
|
payment_entries = frappe.db.sql("""
|
||||||
select
|
select
|
||||||
@ -55,12 +55,12 @@ class BankReconciliation(Document):
|
|||||||
from `tabPayment Entry`
|
from `tabPayment Entry`
|
||||||
where
|
where
|
||||||
(paid_from=%(account)s or paid_to=%(account)s) and docstatus=1
|
(paid_from=%(account)s or paid_to=%(account)s) and docstatus=1
|
||||||
and posting_date >= %(from)s and posting_date <= %(to)s {0}
|
and posting_date >= %(from)s and posting_date <= %(to)s
|
||||||
|
{condition}
|
||||||
order by
|
order by
|
||||||
posting_date ASC, name DESC
|
posting_date ASC, name DESC
|
||||||
""".format(condition),
|
""".format(condition=condition), {"account": self.account, "from":self.from_date,
|
||||||
{"account":self.bank_account, "from":self.from_date,
|
"to": self.to_date, "bank_account": self.bank_account}, as_dict=1)
|
||||||
"to":self.to_date, "bank_account_no": self.bank_account_no}, as_dict=1)
|
|
||||||
|
|
||||||
pos_entries = []
|
pos_entries = []
|
||||||
if self.include_pos_transactions:
|
if self.include_pos_transactions:
|
||||||
@ -72,11 +72,10 @@ class BankReconciliation(Document):
|
|||||||
from `tabSales Invoice Payment` sip, `tabSales Invoice` si, `tabAccount` account
|
from `tabSales Invoice Payment` sip, `tabSales Invoice` si, `tabAccount` account
|
||||||
where
|
where
|
||||||
sip.account=%(account)s and si.docstatus=1 and sip.parent = si.name
|
sip.account=%(account)s and si.docstatus=1 and sip.parent = si.name
|
||||||
and account.name = sip.account and si.posting_date >= %(from)s and si.posting_date <= %(to)s {0}
|
and account.name = sip.account and si.posting_date >= %(from)s and si.posting_date <= %(to)s
|
||||||
order by
|
order by
|
||||||
si.posting_date ASC, si.name DESC
|
si.posting_date ASC, si.name DESC
|
||||||
""".format(condition),
|
""", {"account":self.account, "from":self.from_date, "to":self.to_date}, as_dict=1)
|
||||||
{"account":self.bank_account, "from":self.from_date, "to":self.to_date}, as_dict=1)
|
|
||||||
|
|
||||||
entries = sorted(list(payment_entries)+list(journal_entries+list(pos_entries)),
|
entries = sorted(list(payment_entries)+list(journal_entries+list(pos_entries)),
|
||||||
key=lambda k: k['posting_date'] or getdate(nowdate()))
|
key=lambda k: k['posting_date'] or getdate(nowdate()))
|
||||||
|
@ -314,7 +314,7 @@ class BankStatementTransactionEntry(Document):
|
|||||||
try:
|
try:
|
||||||
reconcile_against_document(lst)
|
reconcile_against_document(lst)
|
||||||
except:
|
except:
|
||||||
frappe.throw(_("Exception occurred while reconciling {0}".format(payment.reference_name)))
|
frappe.throw(_("Exception occurred while reconciling {0}").format(payment.reference_name))
|
||||||
|
|
||||||
def submit_payment_entries(self):
|
def submit_payment_entries(self):
|
||||||
for payment in self.new_transaction_items:
|
for payment in self.new_transaction_items:
|
||||||
|
@ -49,7 +49,7 @@ class BankTransaction(StatusUpdater):
|
|||||||
|
|
||||||
if paid_amount and allocated_amount:
|
if paid_amount and allocated_amount:
|
||||||
if flt(allocated_amount[0]["allocated_amount"]) > flt(paid_amount):
|
if flt(allocated_amount[0]["allocated_amount"]) > flt(paid_amount):
|
||||||
frappe.throw(_("The total allocated amount ({0}) is greated than the paid amount ({1}).".format(flt(allocated_amount[0]["allocated_amount"]), flt(paid_amount))))
|
frappe.throw(_("The total allocated amount ({0}) is greated than the paid amount ({1}).").format(flt(allocated_amount[0]["allocated_amount"]), flt(paid_amount)))
|
||||||
else:
|
else:
|
||||||
if payment_entry.payment_document in ["Payment Entry", "Journal Entry", "Purchase Invoice", "Expense Claim"]:
|
if payment_entry.payment_document in ["Payment Entry", "Journal Entry", "Purchase Invoice", "Expense Claim"]:
|
||||||
self.clear_simple_entry(payment_entry)
|
self.clear_simple_entry(payment_entry)
|
||||||
|
@ -110,6 +110,15 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:doc.docstatus==1",
|
||||||
|
"fieldname": "clearance_date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"label": "Clearance Date",
|
||||||
|
"no_copy": 1,
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"has_web_view": 0,
|
||||||
@ -122,7 +131,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2018-12-06 10:57:02.635141",
|
"modified": "2020-01-22 00:00:00.000000",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Bank Transaction Payments",
|
"name": "Bank Transaction Payments",
|
||||||
|
@ -210,10 +210,10 @@ def get_requested_amount(args, budget):
|
|||||||
item_code = args.get('item_code')
|
item_code = args.get('item_code')
|
||||||
condition = get_other_condition(args, budget, 'Material Request')
|
condition = get_other_condition(args, budget, 'Material Request')
|
||||||
|
|
||||||
data = frappe.db.sql(""" select ifnull((sum(mri.stock_qty - mri.ordered_qty) * rate), 0) as amount
|
data = frappe.db.sql(""" select ifnull((sum(child.stock_qty - child.ordered_qty) * rate), 0) as amount
|
||||||
from `tabMaterial Request Item` mri, `tabMaterial Request` mr where mr.name = mri.parent and
|
from `tabMaterial Request Item` child, `tabMaterial Request` parent where parent.name = child.parent and
|
||||||
mri.item_code = %s and mr.docstatus = 1 and mri.stock_qty > mri.ordered_qty and {0} and
|
child.item_code = %s and parent.docstatus = 1 and child.stock_qty > child.ordered_qty and {0} and
|
||||||
mr.material_request_type = 'Purchase' and mr.status != 'Stopped'""".format(condition), item_code, as_list=1)
|
parent.material_request_type = 'Purchase' and parent.status != 'Stopped'""".format(condition), item_code, as_list=1)
|
||||||
|
|
||||||
return data[0][0] if data else 0
|
return data[0][0] if data else 0
|
||||||
|
|
||||||
@ -221,10 +221,10 @@ def get_ordered_amount(args, budget):
|
|||||||
item_code = args.get('item_code')
|
item_code = args.get('item_code')
|
||||||
condition = get_other_condition(args, budget, 'Purchase Order')
|
condition = get_other_condition(args, budget, 'Purchase Order')
|
||||||
|
|
||||||
data = frappe.db.sql(""" select ifnull(sum(poi.amount - poi.billed_amt), 0) as amount
|
data = frappe.db.sql(""" select ifnull(sum(child.amount - child.billed_amt), 0) as amount
|
||||||
from `tabPurchase Order Item` poi, `tabPurchase Order` po where
|
from `tabPurchase Order Item` child, `tabPurchase Order` parent where
|
||||||
po.name = poi.parent and poi.item_code = %s and po.docstatus = 1 and poi.amount > poi.billed_amt
|
parent.name = child.parent and child.item_code = %s and parent.docstatus = 1 and child.amount > child.billed_amt
|
||||||
and po.status != 'Closed' and {0}""".format(condition), item_code, as_list=1)
|
and parent.status != 'Closed' and {0}""".format(condition), item_code, as_list=1)
|
||||||
|
|
||||||
return data[0][0] if data else 0
|
return data[0][0] if data else 0
|
||||||
|
|
||||||
@ -233,16 +233,15 @@ def get_other_condition(args, budget, for_doc):
|
|||||||
budget_against_field = frappe.scrub(args.get("budget_against_field"))
|
budget_against_field = frappe.scrub(args.get("budget_against_field"))
|
||||||
|
|
||||||
if budget_against_field and args.get(budget_against_field):
|
if budget_against_field and args.get(budget_against_field):
|
||||||
condition += " and %s = '%s'" %(budget_against_field, args.get(budget_against_field))
|
condition += " and child.%s = '%s'" %(budget_against_field, args.get(budget_against_field))
|
||||||
|
|
||||||
if args.get('fiscal_year'):
|
if args.get('fiscal_year'):
|
||||||
date_field = 'schedule_date' if for_doc == 'Material Request' else 'transaction_date'
|
date_field = 'schedule_date' if for_doc == 'Material Request' else 'transaction_date'
|
||||||
start_date, end_date = frappe.db.get_value('Fiscal Year', args.get('fiscal_year'),
|
start_date, end_date = frappe.db.get_value('Fiscal Year', args.get('fiscal_year'),
|
||||||
['year_start_date', 'year_end_date'])
|
['year_start_date', 'year_end_date'])
|
||||||
|
|
||||||
alias = 'mr' if for_doc == 'Material Request' else 'po'
|
condition += """ and parent.%s
|
||||||
condition += """ and %s.%s
|
between '%s' and '%s' """ %(date_field, start_date, end_date)
|
||||||
between '%s' and '%s' """ %(alias, date_field, start_date, end_date)
|
|
||||||
|
|
||||||
return condition
|
return condition
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ class CForm(Document):
|
|||||||
`tabSales Invoice` where name = %s and docstatus = 1""", d.invoice_no)
|
`tabSales Invoice` where name = %s and docstatus = 1""", d.invoice_no)
|
||||||
|
|
||||||
if inv and inv[0][0] != 'Yes':
|
if inv and inv[0][0] != 'Yes':
|
||||||
frappe.throw(_("C-form is not applicable for Invoice: {0}".format(d.invoice_no)))
|
frappe.throw(_("C-form is not applicable for Invoice: {0}").format(d.invoice_no))
|
||||||
|
|
||||||
elif inv and inv[0][1] and inv[0][1] != self.name:
|
elif inv and inv[0][1] and inv[0][1] != self.name:
|
||||||
frappe.throw(_("""Invoice {0} is tagged in another C-form: {1}.
|
frappe.throw(_("""Invoice {0} is tagged in another C-form: {1}.
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"allow_copy": 1,
|
"allow_copy": 1,
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 1,
|
"allow_rename": 1,
|
||||||
@ -123,7 +124,8 @@
|
|||||||
],
|
],
|
||||||
"icon": "fa fa-money",
|
"icon": "fa fa-money",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"modified": "2019-09-16 14:44:17.103548",
|
"links": [],
|
||||||
|
"modified": "2020-01-28 13:50:23.430434",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Cost Center",
|
"name": "Cost Center",
|
||||||
@ -162,7 +164,6 @@
|
|||||||
"role": "Purchase User"
|
"role": "Purchase User"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 1,
|
|
||||||
"search_fields": "parent_cost_center, is_group",
|
"search_fields": "parent_cost_center, is_group",
|
||||||
"show_name_in_global_search": 1,
|
"show_name_in_global_search": 1,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,6 @@ from erpnext.controllers.accounts_controller import AccountsController
|
|||||||
from erpnext.accounts.utils import get_balance_on, get_account_currency
|
from erpnext.accounts.utils import get_balance_on, get_account_currency
|
||||||
from erpnext.accounts.party import get_party_account
|
from erpnext.accounts.party import get_party_account
|
||||||
from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
|
from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
|
||||||
from erpnext.hr.doctype.loan.loan import update_disbursement_status, update_total_amount_paid
|
|
||||||
from erpnext.accounts.doctype.invoice_discounting.invoice_discounting import get_party_account_based_on_invoice_discounting
|
from erpnext.accounts.doctype.invoice_discounting.invoice_discounting import get_party_account_based_on_invoice_discounting
|
||||||
|
|
||||||
from six import string_types, iteritems
|
from six import string_types, iteritems
|
||||||
@ -50,7 +49,6 @@ class JournalEntry(AccountsController):
|
|||||||
self.make_gl_entries()
|
self.make_gl_entries()
|
||||||
self.update_advance_paid()
|
self.update_advance_paid()
|
||||||
self.update_expense_claim()
|
self.update_expense_claim()
|
||||||
self.update_loan()
|
|
||||||
self.update_inter_company_jv()
|
self.update_inter_company_jv()
|
||||||
self.update_invoice_discounting()
|
self.update_invoice_discounting()
|
||||||
|
|
||||||
@ -62,7 +60,6 @@ class JournalEntry(AccountsController):
|
|||||||
self.make_gl_entries(1)
|
self.make_gl_entries(1)
|
||||||
self.update_advance_paid()
|
self.update_advance_paid()
|
||||||
self.update_expense_claim()
|
self.update_expense_claim()
|
||||||
self.update_loan()
|
|
||||||
self.unlink_advance_entry_reference()
|
self.unlink_advance_entry_reference()
|
||||||
self.unlink_asset_reference()
|
self.unlink_asset_reference()
|
||||||
self.unlink_inter_company_jv()
|
self.unlink_inter_company_jv()
|
||||||
@ -597,17 +594,6 @@ class JournalEntry(AccountsController):
|
|||||||
doc = frappe.get_doc("Expense Claim", d.reference_name)
|
doc = frappe.get_doc("Expense Claim", d.reference_name)
|
||||||
update_reimbursed_amount(doc)
|
update_reimbursed_amount(doc)
|
||||||
|
|
||||||
def update_loan(self):
|
|
||||||
if self.paid_loan:
|
|
||||||
paid_loan = json.loads(self.paid_loan)
|
|
||||||
value = 1 if self.docstatus < 2 else 0
|
|
||||||
for name in paid_loan:
|
|
||||||
frappe.db.set_value("Repayment Schedule", name, "paid", value)
|
|
||||||
for d in self.accounts:
|
|
||||||
if d.reference_type=="Loan" and flt(d.debit) > 0:
|
|
||||||
doc = frappe.get_doc("Loan", d.reference_name)
|
|
||||||
update_disbursement_status(doc)
|
|
||||||
update_total_amount_paid(doc)
|
|
||||||
|
|
||||||
def validate_expense_claim(self):
|
def validate_expense_claim(self):
|
||||||
for d in self.accounts:
|
for d in self.accounts:
|
||||||
@ -616,7 +602,7 @@ class JournalEntry(AccountsController):
|
|||||||
d.reference_name, ("total_sanctioned_amount", "total_amount_reimbursed"))
|
d.reference_name, ("total_sanctioned_amount", "total_amount_reimbursed"))
|
||||||
pending_amount = flt(sanctioned_amount) - flt(reimbursed_amount)
|
pending_amount = flt(sanctioned_amount) - flt(reimbursed_amount)
|
||||||
if d.debit > pending_amount:
|
if d.debit > pending_amount:
|
||||||
frappe.throw(_("Row No {0}: Amount cannot be greater than Pending Amount against Expense Claim {1}. Pending Amount is {2}".format(d.idx, d.reference_name, pending_amount)))
|
frappe.throw(_("Row No {0}: Amount cannot be greater than Pending Amount against Expense Claim {1}. Pending Amount is {2}").format(d.idx, d.reference_name, pending_amount))
|
||||||
|
|
||||||
def validate_credit_debit_note(self):
|
def validate_credit_debit_note(self):
|
||||||
if self.stock_entry:
|
if self.stock_entry:
|
||||||
@ -624,7 +610,7 @@ class JournalEntry(AccountsController):
|
|||||||
frappe.throw(_("Stock Entry {0} is not submitted").format(self.stock_entry))
|
frappe.throw(_("Stock Entry {0} is not submitted").format(self.stock_entry))
|
||||||
|
|
||||||
if frappe.db.exists({"doctype": "Journal Entry", "stock_entry": self.stock_entry, "docstatus":1}):
|
if frappe.db.exists({"doctype": "Journal Entry", "stock_entry": self.stock_entry, "docstatus":1}):
|
||||||
frappe.msgprint(_("Warning: Another {0} # {1} exists against stock entry {2}".format(self.voucher_type, self.name, self.stock_entry)))
|
frappe.msgprint(_("Warning: Another {0} # {1} exists against stock entry {2}").format(self.voucher_type, self.name, self.stock_entry))
|
||||||
|
|
||||||
def validate_empty_accounts_table(self):
|
def validate_empty_accounts_table(self):
|
||||||
if not self.get('accounts'):
|
if not self.get('accounts'):
|
||||||
|
@ -11,6 +11,7 @@ class ModeofPayment(Document):
|
|||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_accounts()
|
self.validate_accounts()
|
||||||
self.validate_repeating_companies()
|
self.validate_repeating_companies()
|
||||||
|
self.validate_pos_mode_of_payment()
|
||||||
|
|
||||||
def validate_repeating_companies(self):
|
def validate_repeating_companies(self):
|
||||||
"""Error when Same Company is entered multiple times in accounts"""
|
"""Error when Same Company is entered multiple times in accounts"""
|
||||||
@ -27,3 +28,15 @@ class ModeofPayment(Document):
|
|||||||
if frappe.db.get_value("Account", entry.default_account, "company") != entry.company:
|
if frappe.db.get_value("Account", entry.default_account, "company") != entry.company:
|
||||||
frappe.throw(_("Account {0} does not match with Company {1} in Mode of Account: {2}")
|
frappe.throw(_("Account {0} does not match with Company {1} in Mode of Account: {2}")
|
||||||
.format(entry.default_account, entry.company, self.name))
|
.format(entry.default_account, entry.company, self.name))
|
||||||
|
|
||||||
|
def validate_pos_mode_of_payment(self):
|
||||||
|
if not self.enabled:
|
||||||
|
pos_profiles = frappe.db.sql("""SELECT sip.parent FROM `tabSales Invoice Payment` sip
|
||||||
|
WHERE sip.parenttype = 'POS Profile' and sip.mode_of_payment = %s""", (self.name))
|
||||||
|
pos_profiles = list(map(lambda x: x[0], pos_profiles))
|
||||||
|
|
||||||
|
if pos_profiles:
|
||||||
|
message = "POS Profile " + frappe.bold(", ".join(pos_profiles)) + " contains \
|
||||||
|
Mode of Payment " + frappe.bold(str(self.name)) + ". Please remove them to disable this mode."
|
||||||
|
frappe.throw(_(message), title="Not Allowed")
|
||||||
|
|
||||||
|
@ -253,6 +253,19 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
frappe.throw(__("Party can only be one of "+ party_types.join(", ")));
|
frappe.throw(__("Party can only be one of "+ party_types.join(", ")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frm.set_query("party", function() {
|
||||||
|
if(frm.doc.party_type == 'Employee'){
|
||||||
|
return {
|
||||||
|
query: "erpnext.controllers.queries.employee_query"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(frm.doc.party_type == 'Customer'){
|
||||||
|
return {
|
||||||
|
query: "erpnext.controllers.queries.customer_query"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if(frm.doc.party) {
|
if(frm.doc.party) {
|
||||||
$.each(["party", "party_balance", "paid_from", "paid_to",
|
$.each(["party", "party_balance", "paid_from", "paid_to",
|
||||||
"paid_from_account_currency", "paid_from_account_balance",
|
"paid_from_account_currency", "paid_from_account_balance",
|
||||||
|
@ -102,6 +102,8 @@ class PaymentEntry(AccountsController):
|
|||||||
|
|
||||||
self.bank = bank_data.bank
|
self.bank = bank_data.bank
|
||||||
self.bank_account_no = bank_data.bank_account_no
|
self.bank_account_no = bank_data.bank_account_no
|
||||||
|
|
||||||
|
if not self.get(field):
|
||||||
self.set(field, bank_data.account)
|
self.set(field, bank_data.account)
|
||||||
|
|
||||||
def validate_allocated_amount(self):
|
def validate_allocated_amount(self):
|
||||||
@ -1003,7 +1005,7 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
|||||||
|
|
||||||
# only Purchase Invoice can be blocked individually
|
# only Purchase Invoice can be blocked individually
|
||||||
if doc.doctype == "Purchase Invoice" and doc.invoice_is_blocked():
|
if doc.doctype == "Purchase Invoice" and doc.invoice_is_blocked():
|
||||||
frappe.msgprint(_('{0} is on hold till {1}'.format(doc.name, doc.release_date)))
|
frappe.msgprint(_('{0} is on hold till {1}').format(doc.name, doc.release_date))
|
||||||
else:
|
else:
|
||||||
pe.append("references", {
|
pe.append("references", {
|
||||||
'reference_doctype': dt,
|
'reference_doctype': dt,
|
||||||
|
@ -92,6 +92,7 @@ class PaymentReconciliation(Document):
|
|||||||
FROM `tab{doc}`, `tabGL Entry`
|
FROM `tab{doc}`, `tabGL Entry`
|
||||||
WHERE
|
WHERE
|
||||||
(`tab{doc}`.name = `tabGL Entry`.against_voucher or `tab{doc}`.name = `tabGL Entry`.voucher_no)
|
(`tab{doc}`.name = `tabGL Entry`.against_voucher or `tab{doc}`.name = `tabGL Entry`.voucher_no)
|
||||||
|
and `tab{doc}`.{party_type_field} = %(party)s
|
||||||
and `tab{doc}`.is_return = 1 and `tab{doc}`.return_against IS NULL
|
and `tab{doc}`.is_return = 1 and `tab{doc}`.return_against IS NULL
|
||||||
and `tabGL Entry`.against_voucher_type = %(voucher_type)s
|
and `tabGL Entry`.against_voucher_type = %(voucher_type)s
|
||||||
and `tab{doc}`.docstatus = 1 and `tabGL Entry`.party = %(party)s
|
and `tab{doc}`.docstatus = 1 and `tabGL Entry`.party = %(party)s
|
||||||
@ -99,7 +100,12 @@ class PaymentReconciliation(Document):
|
|||||||
GROUP BY `tab{doc}`.name
|
GROUP BY `tab{doc}`.name
|
||||||
Having
|
Having
|
||||||
amount > 0
|
amount > 0
|
||||||
""".format(doc=voucher_type, dr_or_cr=dr_or_cr, reconciled_dr_or_cr=reconciled_dr_or_cr), {
|
""".format(
|
||||||
|
doc=voucher_type,
|
||||||
|
dr_or_cr=dr_or_cr,
|
||||||
|
reconciled_dr_or_cr=reconciled_dr_or_cr,
|
||||||
|
party_type_field=frappe.scrub(self.party_type)),
|
||||||
|
{
|
||||||
'party': self.party,
|
'party': self.party,
|
||||||
'party_type': self.party_type,
|
'party_type': self.party_type,
|
||||||
'voucher_type': voucher_type,
|
'voucher_type': voucher_type,
|
||||||
|
@ -39,8 +39,8 @@ class PaymentRequest(Document):
|
|||||||
ref_amount = get_amount(ref_doc)
|
ref_amount = get_amount(ref_doc)
|
||||||
|
|
||||||
if existing_payment_request_amount + flt(self.grand_total)> ref_amount:
|
if existing_payment_request_amount + flt(self.grand_total)> ref_amount:
|
||||||
frappe.throw(_("Total Payment Request amount cannot be greater than {0} amount"
|
frappe.throw(_("Total Payment Request amount cannot be greater than {0} amount")
|
||||||
.format(self.reference_doctype)))
|
.format(self.reference_doctype))
|
||||||
|
|
||||||
def validate_currency(self):
|
def validate_currency(self):
|
||||||
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
|
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
|
||||||
@ -53,14 +53,14 @@ class PaymentRequest(Document):
|
|||||||
for subscription_plan in self.subscription_plans:
|
for subscription_plan in self.subscription_plans:
|
||||||
payment_gateway = frappe.db.get_value("Subscription Plan", subscription_plan.plan, "payment_gateway")
|
payment_gateway = frappe.db.get_value("Subscription Plan", subscription_plan.plan, "payment_gateway")
|
||||||
if payment_gateway != self.payment_gateway_account:
|
if payment_gateway != self.payment_gateway_account:
|
||||||
frappe.throw(_('The payment gateway account in plan {0} is different from the payment gateway account in this payment request'.format(subscription_plan.name)))
|
frappe.throw(_('The payment gateway account in plan {0} is different from the payment gateway account in this payment request').format(subscription_plan.name))
|
||||||
|
|
||||||
rate = get_plan_rate(subscription_plan.plan, quantity=subscription_plan.qty)
|
rate = get_plan_rate(subscription_plan.plan, quantity=subscription_plan.qty)
|
||||||
|
|
||||||
amount += rate
|
amount += rate
|
||||||
|
|
||||||
if amount != self.grand_total:
|
if amount != self.grand_total:
|
||||||
frappe.msgprint(_("The amount of {0} set in this payment request is different from the calculated amount of all payment plans: {1}. Make sure this is correct before submitting the document.".format(self.grand_total, amount)))
|
frappe.msgprint(_("The amount of {0} set in this payment request is different from the calculated amount of all payment plans: {1}. Make sure this is correct before submitting the document.").format(self.grand_total, amount))
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
if self.payment_request_type == 'Outward':
|
if self.payment_request_type == 'Outward':
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
"autoname": "Prompt",
|
"autoname": "Prompt",
|
||||||
"creation": "2013-05-24 12:15:51",
|
"creation": "2013-05-24 12:15:51",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"disabled",
|
"disabled",
|
||||||
"section_break_2",
|
"section_break_2",
|
||||||
@ -50,6 +51,7 @@
|
|||||||
"income_account",
|
"income_account",
|
||||||
"expense_account",
|
"expense_account",
|
||||||
"taxes_and_charges",
|
"taxes_and_charges",
|
||||||
|
"tax_category",
|
||||||
"apply_discount_on",
|
"apply_discount_on",
|
||||||
"accounting_dimensions_section",
|
"accounting_dimensions_section",
|
||||||
"cost_center",
|
"cost_center",
|
||||||
@ -381,11 +383,17 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "dimension_col_break",
|
"fieldname": "dimension_col_break",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "tax_category",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Tax Category",
|
||||||
|
"options": "Tax Category"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "icon-cog",
|
"icon": "icon-cog",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"modified": "2019-05-25 22:56:30.352693",
|
"modified": "2020-01-24 15:52:03.797701",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "POS Profile",
|
"name": "POS Profile",
|
||||||
|
@ -29,27 +29,29 @@ class TestPOSProfile(unittest.TestCase):
|
|||||||
|
|
||||||
frappe.db.sql("delete from `tabPOS Profile`")
|
frappe.db.sql("delete from `tabPOS Profile`")
|
||||||
|
|
||||||
def make_pos_profile():
|
def make_pos_profile(**args):
|
||||||
frappe.db.sql("delete from `tabPOS Profile`")
|
frappe.db.sql("delete from `tabPOS Profile`")
|
||||||
|
|
||||||
|
args = frappe._dict(args)
|
||||||
|
|
||||||
pos_profile = frappe.get_doc({
|
pos_profile = frappe.get_doc({
|
||||||
"company": "_Test Company",
|
"company": args.company or "_Test Company",
|
||||||
"cost_center": "_Test Cost Center - _TC",
|
"cost_center": args.cost_center or "_Test Cost Center - _TC",
|
||||||
"currency": "INR",
|
"currency": args.currency or "INR",
|
||||||
"doctype": "POS Profile",
|
"doctype": "POS Profile",
|
||||||
"expense_account": "_Test Account Cost for Goods Sold - _TC",
|
"expense_account": args.expense_account or "_Test Account Cost for Goods Sold - _TC",
|
||||||
"income_account": "Sales - _TC",
|
"income_account": args.income_account or "Sales - _TC",
|
||||||
"name": "_Test POS Profile",
|
"name": args.name or "_Test POS Profile",
|
||||||
"naming_series": "_T-POS Profile-",
|
"naming_series": "_T-POS Profile-",
|
||||||
"selling_price_list": "_Test Price List",
|
"selling_price_list": args.selling_price_list or "_Test Price List",
|
||||||
"territory": "_Test Territory",
|
"territory": args.territory or "_Test Territory",
|
||||||
"customer_group": frappe.db.get_value('Customer Group', {'is_group': 0}, 'name'),
|
"customer_group": frappe.db.get_value('Customer Group', {'is_group': 0}, 'name'),
|
||||||
"warehouse": "_Test Warehouse - _TC",
|
"warehouse": args.warehouse or "_Test Warehouse - _TC",
|
||||||
"write_off_account": "_Test Write Off - _TC",
|
"write_off_account": args.write_off_account or "_Test Write Off - _TC",
|
||||||
"write_off_cost_center": "_Test Write Off Cost Center - _TC"
|
"write_off_cost_center": args.write_off_cost_center or "_Test Write Off Cost Center - _TC"
|
||||||
})
|
})
|
||||||
|
|
||||||
if not frappe.db.exists("POS Profile", "_Test POS Profile"):
|
if not frappe.db.exists("POS Profile", args.name or "_Test POS Profile"):
|
||||||
pos_profile.insert()
|
pos_profile.insert()
|
||||||
|
|
||||||
return pos_profile
|
return pos_profile
|
||||||
|
@ -56,12 +56,12 @@ class PricingRule(Document):
|
|||||||
|
|
||||||
if not self.selling and self.applicable_for in ["Customer", "Customer Group",
|
if not self.selling and self.applicable_for in ["Customer", "Customer Group",
|
||||||
"Territory", "Sales Partner", "Campaign"]:
|
"Territory", "Sales Partner", "Campaign"]:
|
||||||
throw(_("Selling must be checked, if Applicable For is selected as {0}"
|
throw(_("Selling must be checked, if Applicable For is selected as {0}")
|
||||||
.format(self.applicable_for)))
|
.format(self.applicable_for))
|
||||||
|
|
||||||
if not self.buying and self.applicable_for in ["Supplier", "Supplier Group"]:
|
if not self.buying and self.applicable_for in ["Supplier", "Supplier Group"]:
|
||||||
throw(_("Buying must be checked, if Applicable For is selected as {0}"
|
throw(_("Buying must be checked, if Applicable For is selected as {0}")
|
||||||
.format(self.applicable_for)))
|
.format(self.applicable_for))
|
||||||
|
|
||||||
def validate_min_max_qty(self):
|
def validate_min_max_qty(self):
|
||||||
if self.min_qty and self.max_qty and flt(self.min_qty) > flt(self.max_qty):
|
if self.min_qty and self.max_qty and flt(self.min_qty) > flt(self.max_qty):
|
||||||
@ -248,7 +248,7 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=Fa
|
|||||||
if pricing_rule.price_or_product_discount == "Price":
|
if pricing_rule.price_or_product_discount == "Price":
|
||||||
apply_price_discount_rule(pricing_rule, item_details, args)
|
apply_price_discount_rule(pricing_rule, item_details, args)
|
||||||
else:
|
else:
|
||||||
get_product_discount_rule(pricing_rule, item_details, doc)
|
get_product_discount_rule(pricing_rule, item_details, args, doc)
|
||||||
|
|
||||||
item_details.has_pricing_rule = 1
|
item_details.has_pricing_rule = 1
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@ from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_orde
|
|||||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||||
from erpnext.stock.get_item_details import get_item_details
|
from erpnext.stock.get_item_details import get_item_details
|
||||||
from frappe import MandatoryError
|
from frappe import MandatoryError
|
||||||
|
from erpnext.stock.doctype.item.test_item import make_item
|
||||||
|
from erpnext.healthcare.doctype.lab_test_template.lab_test_template import make_item_price
|
||||||
|
|
||||||
class TestPricingRule(unittest.TestCase):
|
class TestPricingRule(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -145,6 +147,52 @@ class TestPricingRule(unittest.TestCase):
|
|||||||
self.assertEquals(details.get("margin_type"), "Percentage")
|
self.assertEquals(details.get("margin_type"), "Percentage")
|
||||||
self.assertEquals(details.get("margin_rate_or_amount"), 10)
|
self.assertEquals(details.get("margin_rate_or_amount"), 10)
|
||||||
|
|
||||||
|
def test_mixed_conditions_for_item_group(self):
|
||||||
|
for item in ["Mixed Cond Item 1", "Mixed Cond Item 2"]:
|
||||||
|
make_item(item, {"item_group": "Products"})
|
||||||
|
make_item_price(item, "_Test Price List", 100)
|
||||||
|
|
||||||
|
test_record = {
|
||||||
|
"doctype": "Pricing Rule",
|
||||||
|
"title": "_Test Pricing Rule for Item Group",
|
||||||
|
"apply_on": "Item Group",
|
||||||
|
"item_groups": [
|
||||||
|
{
|
||||||
|
"item_group": "Products",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item_group": "Seed",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"selling": 1,
|
||||||
|
"mixed_conditions": 1,
|
||||||
|
"currency": "USD",
|
||||||
|
"rate_or_discount": "Discount Percentage",
|
||||||
|
"discount_percentage": 10,
|
||||||
|
"applicable_for": "Customer Group",
|
||||||
|
"customer_group": "All Customer Groups",
|
||||||
|
"company": "_Test Company"
|
||||||
|
}
|
||||||
|
frappe.get_doc(test_record.copy()).insert()
|
||||||
|
|
||||||
|
args = frappe._dict({
|
||||||
|
"item_code": "Mixed Cond Item 1",
|
||||||
|
"item_group": "Products",
|
||||||
|
"company": "_Test Company",
|
||||||
|
"price_list": "_Test Price List",
|
||||||
|
"currency": "_Test Currency",
|
||||||
|
"doctype": "Sales Order",
|
||||||
|
"conversion_rate": 1,
|
||||||
|
"price_list_currency": "_Test Currency",
|
||||||
|
"plc_conversion_rate": 1,
|
||||||
|
"order_type": "Sales",
|
||||||
|
"customer": "_Test Customer",
|
||||||
|
"customer_group": "_Test Customer Group",
|
||||||
|
"name": None
|
||||||
|
})
|
||||||
|
details = get_item_details(args)
|
||||||
|
self.assertEquals(details.get("discount_percentage"), 10)
|
||||||
|
|
||||||
def test_pricing_rule_for_variants(self):
|
def test_pricing_rule_for_variants(self):
|
||||||
from erpnext.stock.get_item_details import get_item_details
|
from erpnext.stock.get_item_details import get_item_details
|
||||||
from frappe import MandatoryError
|
from frappe import MandatoryError
|
||||||
@ -278,6 +326,66 @@ class TestPricingRule(unittest.TestCase):
|
|||||||
self.assertEquals(item.discount_amount, 110)
|
self.assertEquals(item.discount_amount, 110)
|
||||||
self.assertEquals(item.rate, 990)
|
self.assertEquals(item.rate, 990)
|
||||||
|
|
||||||
|
def test_pricing_rule_for_product_discount_on_same_item(self):
|
||||||
|
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
|
||||||
|
test_record = {
|
||||||
|
"doctype": "Pricing Rule",
|
||||||
|
"title": "_Test Pricing Rule",
|
||||||
|
"apply_on": "Item Code",
|
||||||
|
"currency": "USD",
|
||||||
|
"items": [{
|
||||||
|
"item_code": "_Test Item",
|
||||||
|
}],
|
||||||
|
"selling": 1,
|
||||||
|
"rate_or_discount": "Discount Percentage",
|
||||||
|
"rate": 0,
|
||||||
|
"min_qty": 0,
|
||||||
|
"max_qty": 7,
|
||||||
|
"discount_percentage": 17.5,
|
||||||
|
"price_or_product_discount": "Product",
|
||||||
|
"same_item": 1,
|
||||||
|
"free_qty": 1,
|
||||||
|
"company": "_Test Company"
|
||||||
|
}
|
||||||
|
frappe.get_doc(test_record.copy()).insert()
|
||||||
|
|
||||||
|
# With pricing rule
|
||||||
|
so = make_sales_order(item_code="_Test Item", qty=1)
|
||||||
|
so.load_from_db()
|
||||||
|
self.assertEqual(so.items[1].is_free_item, 1)
|
||||||
|
self.assertEqual(so.items[1].item_code, "_Test Item")
|
||||||
|
|
||||||
|
|
||||||
|
def test_pricing_rule_for_product_discount_on_different_item(self):
|
||||||
|
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
|
||||||
|
test_record = {
|
||||||
|
"doctype": "Pricing Rule",
|
||||||
|
"title": "_Test Pricing Rule",
|
||||||
|
"apply_on": "Item Code",
|
||||||
|
"currency": "USD",
|
||||||
|
"items": [{
|
||||||
|
"item_code": "_Test Item",
|
||||||
|
}],
|
||||||
|
"selling": 1,
|
||||||
|
"rate_or_discount": "Discount Percentage",
|
||||||
|
"rate": 0,
|
||||||
|
"min_qty": 0,
|
||||||
|
"max_qty": 7,
|
||||||
|
"discount_percentage": 17.5,
|
||||||
|
"price_or_product_discount": "Product",
|
||||||
|
"same_item": 0,
|
||||||
|
"free_item": "_Test Item 2",
|
||||||
|
"free_qty": 1,
|
||||||
|
"company": "_Test Company"
|
||||||
|
}
|
||||||
|
frappe.get_doc(test_record.copy()).insert()
|
||||||
|
|
||||||
|
# With pricing rule
|
||||||
|
so = make_sales_order(item_code="_Test Item", qty=1)
|
||||||
|
so.load_from_db()
|
||||||
|
self.assertEqual(so.items[1].is_free_item, 1)
|
||||||
|
self.assertEqual(so.items[1].item_code, "_Test Item 2")
|
||||||
|
|
||||||
def make_pricing_rule(**args):
|
def make_pricing_rule(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
|
||||||
|
@ -435,7 +435,7 @@ def apply_pricing_rule_on_transaction(doc):
|
|||||||
doc.calculate_taxes_and_totals()
|
doc.calculate_taxes_and_totals()
|
||||||
elif d.price_or_product_discount == 'Product':
|
elif d.price_or_product_discount == 'Product':
|
||||||
item_details = frappe._dict({'parenttype': doc.doctype})
|
item_details = frappe._dict({'parenttype': doc.doctype})
|
||||||
get_product_discount_rule(d, item_details, doc)
|
get_product_discount_rule(d, item_details, doc=doc)
|
||||||
apply_pricing_rule_for_free_items(doc, item_details.free_item_data)
|
apply_pricing_rule_for_free_items(doc, item_details.free_item_data)
|
||||||
doc.set_missing_values()
|
doc.set_missing_values()
|
||||||
|
|
||||||
@ -443,9 +443,10 @@ def get_applied_pricing_rules(item_row):
|
|||||||
return (item_row.get("pricing_rules").split(',')
|
return (item_row.get("pricing_rules").split(',')
|
||||||
if item_row.get("pricing_rules") else [])
|
if item_row.get("pricing_rules") else [])
|
||||||
|
|
||||||
def get_product_discount_rule(pricing_rule, item_details, doc=None):
|
def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None):
|
||||||
free_item = (pricing_rule.free_item
|
free_item = pricing_rule.free_item
|
||||||
if not pricing_rule.same_item or pricing_rule.apply_on == 'Transaction' else item_details.item_code)
|
if pricing_rule.same_item:
|
||||||
|
free_item = item_details.item_code or args.item_code
|
||||||
|
|
||||||
if not free_item:
|
if not free_item:
|
||||||
frappe.throw(_("Free item not set in the pricing rule {0}")
|
frappe.throw(_("Free item not set in the pricing rule {0}")
|
||||||
@ -489,7 +490,7 @@ def get_pricing_rule_items(pr_doc):
|
|||||||
|
|
||||||
for d in pr_doc.get(pricing_rule_apply_on):
|
for d in pr_doc.get(pricing_rule_apply_on):
|
||||||
if apply_on == 'item_group':
|
if apply_on == 'item_group':
|
||||||
get_child_item_groups(d.get(apply_on))
|
apply_on_data.extend(get_child_item_groups(d.get(apply_on)))
|
||||||
else:
|
else:
|
||||||
apply_on_data.append(d.get(apply_on))
|
apply_on_data.append(d.get(apply_on))
|
||||||
|
|
||||||
|
@ -149,6 +149,7 @@
|
|||||||
"column_break_63",
|
"column_break_63",
|
||||||
"status",
|
"status",
|
||||||
"inter_company_invoice_reference",
|
"inter_company_invoice_reference",
|
||||||
|
"is_internal_supplier",
|
||||||
"remarks",
|
"remarks",
|
||||||
"subscription_section",
|
"subscription_section",
|
||||||
"from_date",
|
"from_date",
|
||||||
@ -418,7 +419,6 @@
|
|||||||
"fieldname": "contact_email",
|
"fieldname": "contact_email",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"label": "Contact Email",
|
"label": "Contact Email",
|
||||||
"options": "Email",
|
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
@ -1284,6 +1284,14 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "dimension_col_break",
|
"fieldname": "dimension_col_break",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fetch_from": "supplier.is_internal_supplier",
|
||||||
|
"fieldname": "is_internal_supplier",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Is Internal Supplier",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-file-text",
|
"icon": "fa fa-file-text",
|
||||||
|
@ -224,7 +224,7 @@ class PurchaseInvoice(BuyingController):
|
|||||||
for item in self.get("items"):
|
for item in self.get("items"):
|
||||||
# in case of auto inventory accounting,
|
# in case of auto inventory accounting,
|
||||||
# expense account is always "Stock Received But Not Billed" for a stock item
|
# expense account is always "Stock Received But Not Billed" for a stock item
|
||||||
# except epening entry, drop-ship entry and fixed asset items
|
# except opening entry, drop-ship entry and fixed asset items
|
||||||
if item.item_code:
|
if item.item_code:
|
||||||
asset_category = frappe.get_cached_value("Item", item.item_code, "asset_category")
|
asset_category = frappe.get_cached_value("Item", item.item_code, "asset_category")
|
||||||
|
|
||||||
@ -233,10 +233,22 @@ class PurchaseInvoice(BuyingController):
|
|||||||
and (not item.po_detail or
|
and (not item.po_detail or
|
||||||
not frappe.db.get_value("Purchase Order Item", item.po_detail, "delivered_by_supplier")):
|
not frappe.db.get_value("Purchase Order Item", item.po_detail, "delivered_by_supplier")):
|
||||||
|
|
||||||
if self.update_stock:
|
if self.update_stock and (not item.from_warehouse):
|
||||||
item.expense_account = warehouse_account[item.warehouse]["account"]
|
item.expense_account = warehouse_account[item.warehouse]["account"]
|
||||||
else:
|
else:
|
||||||
|
# check if 'Stock Received But Not Billed' account is credited in Purchase receipt or not
|
||||||
|
if item.purchase_receipt:
|
||||||
|
negative_expense_booked_in_pr = frappe.db.sql("""select name from `tabGL Entry`
|
||||||
|
where voucher_type='Purchase Receipt' and voucher_no=%s and account = %s""",
|
||||||
|
(item.purchase_receipt, stock_not_billed_account))
|
||||||
|
|
||||||
|
if negative_expense_booked_in_pr:
|
||||||
item.expense_account = stock_not_billed_account
|
item.expense_account = stock_not_billed_account
|
||||||
|
else:
|
||||||
|
# If no purchase receipt present then book expense in 'Stock Received But Not Billed'
|
||||||
|
# This is done in cases when Purchase Invoice is created before Purchase Receipt
|
||||||
|
item.expense_account = stock_not_billed_account
|
||||||
|
|
||||||
elif item.is_fixed_asset and not is_cwip_accounting_enabled(asset_category):
|
elif item.is_fixed_asset and not is_cwip_accounting_enabled(asset_category):
|
||||||
item.expense_account = get_asset_category_account('fixed_asset_account', item=item.item_code,
|
item.expense_account = get_asset_category_account('fixed_asset_account', item=item.item_code,
|
||||||
company = self.company)
|
company = self.company)
|
||||||
@ -467,6 +479,37 @@ class PurchaseInvoice(BuyingController):
|
|||||||
warehouse_debit_amount = self.make_stock_adjustment_entry(gl_entries,
|
warehouse_debit_amount = self.make_stock_adjustment_entry(gl_entries,
|
||||||
item, voucher_wise_stock_value, account_currency)
|
item, voucher_wise_stock_value, account_currency)
|
||||||
|
|
||||||
|
if item.from_warehouse:
|
||||||
|
|
||||||
|
gl_entries.append(self.get_gl_dict({
|
||||||
|
"account": warehouse_account[item.warehouse]['account'],
|
||||||
|
"against": warehouse_account[item.from_warehouse]["account"],
|
||||||
|
"cost_center": item.cost_center,
|
||||||
|
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||||
|
"debit": warehouse_debit_amount,
|
||||||
|
}, warehouse_account[item.warehouse]["account_currency"], item=item))
|
||||||
|
|
||||||
|
# Intentionally passed negative debit amount to avoid incorrect GL Entry validation
|
||||||
|
gl_entries.append(self.get_gl_dict({
|
||||||
|
"account": warehouse_account[item.from_warehouse]['account'],
|
||||||
|
"against": warehouse_account[item.warehouse]["account"],
|
||||||
|
"cost_center": item.cost_center,
|
||||||
|
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||||
|
"debit": -1 * flt(item.base_net_amount, item.precision("base_net_amount")),
|
||||||
|
}, warehouse_account[item.from_warehouse]["account_currency"], item=item))
|
||||||
|
|
||||||
|
gl_entries.append(
|
||||||
|
self.get_gl_dict({
|
||||||
|
"account": item.expense_account,
|
||||||
|
"against": self.supplier,
|
||||||
|
"debit": flt(item.base_net_amount, item.precision("base_net_amount")),
|
||||||
|
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||||
|
"cost_center": item.cost_center,
|
||||||
|
"project": item.project
|
||||||
|
}, account_currency, item=item)
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
gl_entries.append(
|
gl_entries.append(
|
||||||
self.get_gl_dict({
|
self.get_gl_dict({
|
||||||
"account": item.expense_account,
|
"account": item.expense_account,
|
||||||
@ -908,7 +951,7 @@ class PurchaseInvoice(BuyingController):
|
|||||||
|
|
||||||
if pi:
|
if pi:
|
||||||
pi = pi[0][0]
|
pi = pi[0][0]
|
||||||
frappe.throw(_("Supplier Invoice No exists in Purchase Invoice {0}".format(pi)))
|
frappe.throw(_("Supplier Invoice No exists in Purchase Invoice {0}").format(pi))
|
||||||
|
|
||||||
def update_billing_status_in_pr(self, update_modified=True):
|
def update_billing_status_in_pr(self, update_modified=True):
|
||||||
updated_pr = []
|
updated_pr = []
|
||||||
@ -1015,7 +1058,7 @@ def unblock_invoice(name):
|
|||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def block_invoice(name, hold_comment, release_date):
|
def block_invoice(name, release_date, hold_comment=None):
|
||||||
if frappe.db.exists('Purchase Invoice', name):
|
if frappe.db.exists('Purchase Invoice', name):
|
||||||
pi = frappe.get_doc('Purchase Invoice', name)
|
pi = frappe.get_doc('Purchase Invoice', name)
|
||||||
pi.block_invoice(hold_comment, release_date)
|
pi.block_invoice(hold_comment, release_date)
|
||||||
|
@ -63,6 +63,7 @@
|
|||||||
"warehouse_section",
|
"warehouse_section",
|
||||||
"warehouse",
|
"warehouse",
|
||||||
"rejected_warehouse",
|
"rejected_warehouse",
|
||||||
|
"from_warehouse",
|
||||||
"quality_inspection",
|
"quality_inspection",
|
||||||
"batch_no",
|
"batch_no",
|
||||||
"col_br_wh",
|
"col_br_wh",
|
||||||
@ -762,16 +763,22 @@
|
|||||||
"fetch_from": "item_code.asset_category",
|
"fetch_from": "item_code.asset_category",
|
||||||
"fieldname": "asset_category",
|
"fieldname": "asset_category",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"in_preview": 1,
|
|
||||||
"label": "Asset Category",
|
"label": "Asset Category",
|
||||||
"options": "Asset Category",
|
"options": "Asset Category",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "from_warehouse",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"ignore_user_permissions": 1,
|
||||||
|
"label": "Supplier Warehouse",
|
||||||
|
"options": "Warehouse"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2019-12-04 12:23:17.046413",
|
"modified": "2020-01-13 16:04:14.200462",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Purchase Invoice Item",
|
"name": "Purchase Invoice Item",
|
||||||
|
@ -152,8 +152,11 @@ def update_multi_mode_option(doc, pos_profile):
|
|||||||
|
|
||||||
|
|
||||||
def get_mode_of_payment(doc):
|
def get_mode_of_payment(doc):
|
||||||
return frappe.db.sql(""" select mpa.default_account, mpa.parent, mp.type as type from `tabMode of Payment Account` mpa, \
|
return frappe.db.sql("""
|
||||||
`tabMode of Payment` mp where mpa.parent = mp.name and mpa.company = %(company)s""", {'company': doc.company}, as_dict=1)
|
select mpa.default_account, mpa.parent, mp.type as type
|
||||||
|
from `tabMode of Payment Account` mpa,`tabMode of Payment` mp
|
||||||
|
where mpa.parent = mp.name and mpa.company = %(company)s and mp.enabled = 1""",
|
||||||
|
{'company': doc.company}, as_dict=1)
|
||||||
|
|
||||||
|
|
||||||
def update_tax_table(doc):
|
def update_tax_table(doc):
|
||||||
|
@ -25,7 +25,7 @@ frappe.ui.form.on("Sales Invoice", {
|
|||||||
if(frm.doc.docstatus == 1 && !frm.is_dirty()
|
if(frm.doc.docstatus == 1 && !frm.is_dirty()
|
||||||
&& !frm.doc.is_return && !frm.doc.ewaybill) {
|
&& !frm.doc.is_return && !frm.doc.ewaybill) {
|
||||||
|
|
||||||
frm.add_custom_button('e-Way Bill JSON', () => {
|
frm.add_custom_button('E-Way Bill JSON', () => {
|
||||||
var w = window.open(
|
var w = window.open(
|
||||||
frappe.urllib.get_full_url(
|
frappe.urllib.get_full_url(
|
||||||
"/api/method/erpnext.regional.india.utils.generate_ewb_json?"
|
"/api/method/erpnext.regional.india.utils.generate_ewb_json?"
|
||||||
@ -36,7 +36,7 @@ frappe.ui.form.on("Sales Invoice", {
|
|||||||
if (!w) {
|
if (!w) {
|
||||||
frappe.msgprint(__("Please enable pop-ups")); return;
|
frappe.msgprint(__("Please enable pop-ups")); return;
|
||||||
}
|
}
|
||||||
}, __("Make"));
|
}, __("Create"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ frappe.listview_settings['Sales Invoice'].onload = function (doclist) {
|
|||||||
|
|
||||||
for (let doc of selected_docs) {
|
for (let doc of selected_docs) {
|
||||||
if (doc.docstatus !== 1) {
|
if (doc.docstatus !== 1) {
|
||||||
frappe.throw(__("e-Way Bill JSON can only be generated from a submitted document"));
|
frappe.throw(__("E-Way Bill JSON can only be generated from a submitted document"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,5 +29,5 @@ frappe.listview_settings['Sales Invoice'].onload = function (doclist) {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
doclist.page.add_actions_menu_item(__('Generate e-Way Bill JSON'), action, false);
|
doclist.page.add_actions_menu_item(__('Generate E-Way Bill JSON'), action, false);
|
||||||
};
|
};
|
@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"actions": [],
|
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"creation": "2013-05-24 19:29:05",
|
"creation": "2013-05-24 19:29:05",
|
||||||
@ -154,6 +153,7 @@
|
|||||||
"select_print_heading",
|
"select_print_heading",
|
||||||
"more_information",
|
"more_information",
|
||||||
"inter_company_invoice_reference",
|
"inter_company_invoice_reference",
|
||||||
|
"is_internal_customer",
|
||||||
"customer_group",
|
"customer_group",
|
||||||
"campaign",
|
"campaign",
|
||||||
"is_discounted",
|
"is_discounted",
|
||||||
@ -373,7 +373,8 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Sales Invoice",
|
"options": "Sales Invoice",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1,
|
||||||
|
"search_index": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_21",
|
"fieldname": "column_break_21",
|
||||||
@ -1563,13 +1564,20 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "dimension_col_break",
|
"fieldname": "dimension_col_break",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fetch_from": "customer.is_internal_customer",
|
||||||
|
"fieldname": "is_internal_customer",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Is Internal Customer",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-file-text",
|
"icon": "fa fa-file-text",
|
||||||
"idx": 181,
|
"idx": 181,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"modified": "2020-02-10 04:57:11.221180",
|
||||||
"modified": "2019-12-30 19:15:59.580414",
|
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Invoice",
|
"name": "Sales Invoice",
|
||||||
|
@ -225,7 +225,7 @@ class SalesInvoice(SellingController):
|
|||||||
total_amount_in_payments += payment.amount
|
total_amount_in_payments += payment.amount
|
||||||
invoice_total = self.rounded_total or self.grand_total
|
invoice_total = self.rounded_total or self.grand_total
|
||||||
if total_amount_in_payments < invoice_total:
|
if total_amount_in_payments < invoice_total:
|
||||||
frappe.throw(_("Total payments amount can't be greater than {}".format(-invoice_total)))
|
frappe.throw(_("Total payments amount can't be greater than {}").format(-invoice_total))
|
||||||
|
|
||||||
def validate_pos_paid_amount(self):
|
def validate_pos_paid_amount(self):
|
||||||
if len(self.payments) == 0 and self.is_pos:
|
if len(self.payments) == 0 and self.is_pos:
|
||||||
@ -421,6 +421,9 @@ class SalesInvoice(SellingController):
|
|||||||
if pos:
|
if pos:
|
||||||
self.allow_print_before_pay = pos.allow_print_before_pay
|
self.allow_print_before_pay = pos.allow_print_before_pay
|
||||||
|
|
||||||
|
if not for_validate:
|
||||||
|
self.tax_category = pos.get("tax_category")
|
||||||
|
|
||||||
if not for_validate and not self.customer:
|
if not for_validate and not self.customer:
|
||||||
self.customer = pos.customer
|
self.customer = pos.customer
|
||||||
|
|
||||||
@ -1041,11 +1044,11 @@ class SalesInvoice(SellingController):
|
|||||||
si_serial_nos = set(get_serial_nos(serial_nos))
|
si_serial_nos = set(get_serial_nos(serial_nos))
|
||||||
|
|
||||||
if si_serial_nos - dn_serial_nos:
|
if si_serial_nos - dn_serial_nos:
|
||||||
frappe.throw(_("Serial Numbers in row {0} does not match with Delivery Note".format(item.idx)))
|
frappe.throw(_("Serial Numbers in row {0} does not match with Delivery Note").format(item.idx))
|
||||||
|
|
||||||
if item.serial_no and cint(item.qty) != len(si_serial_nos):
|
if item.serial_no and cint(item.qty) != len(si_serial_nos):
|
||||||
frappe.throw(_("Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.".format(
|
frappe.throw(_("Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.").format(
|
||||||
item.idx, item.qty, item.item_code, len(si_serial_nos))))
|
item.idx, item.qty, item.item_code, len(si_serial_nos)))
|
||||||
|
|
||||||
def validate_serial_against_sales_invoice(self):
|
def validate_serial_against_sales_invoice(self):
|
||||||
""" check if serial number is already used in other sales invoice """
|
""" check if serial number is already used in other sales invoice """
|
||||||
@ -1064,8 +1067,8 @@ class SalesInvoice(SellingController):
|
|||||||
and self.name != serial_no_details.sales_invoice:
|
and self.name != serial_no_details.sales_invoice:
|
||||||
sales_invoice_company = frappe.db.get_value("Sales Invoice", serial_no_details.sales_invoice, "company")
|
sales_invoice_company = frappe.db.get_value("Sales Invoice", serial_no_details.sales_invoice, "company")
|
||||||
if sales_invoice_company == self.company:
|
if sales_invoice_company == self.company:
|
||||||
frappe.throw(_("Serial Number: {0} is already referenced in Sales Invoice: {1}"
|
frappe.throw(_("Serial Number: {0} is already referenced in Sales Invoice: {1}")
|
||||||
.format(serial_no, serial_no_details.sales_invoice)))
|
.format(serial_no, serial_no_details.sales_invoice))
|
||||||
|
|
||||||
def update_project(self):
|
def update_project(self):
|
||||||
if self.project:
|
if self.project:
|
||||||
@ -1240,18 +1243,21 @@ class SalesInvoice(SellingController):
|
|||||||
|
|
||||||
precision = self.precision("outstanding_amount")
|
precision = self.precision("outstanding_amount")
|
||||||
outstanding_amount = flt(self.outstanding_amount, precision)
|
outstanding_amount = flt(self.outstanding_amount, precision)
|
||||||
|
due_date = getdate(self.due_date)
|
||||||
|
nowdate = getdate()
|
||||||
|
discountng_status = self.get_discounting_status()
|
||||||
|
|
||||||
if not status:
|
if not status:
|
||||||
if self.docstatus == 2:
|
if self.docstatus == 2:
|
||||||
status = "Cancelled"
|
status = "Cancelled"
|
||||||
elif self.docstatus == 1:
|
elif self.docstatus == 1:
|
||||||
if outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.is_discounted and self.get_discounting_status()=='Disbursed':
|
if outstanding_amount > 0 and due_date < nowdate and self.is_discounted and discountng_status=='Disbursed':
|
||||||
self.status = "Overdue and Discounted"
|
self.status = "Overdue and Discounted"
|
||||||
elif outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()):
|
elif outstanding_amount > 0 and due_date < nowdate:
|
||||||
self.status = "Overdue"
|
self.status = "Overdue"
|
||||||
elif outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.is_discounted and self.get_discounting_status()=='Disbursed':
|
elif outstanding_amount > 0 and due_date >= nowdate and self.is_discounted and discountng_status=='Disbursed':
|
||||||
self.status = "Unpaid and Discounted"
|
self.status = "Unpaid and Discounted"
|
||||||
elif outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()):
|
elif outstanding_amount > 0 and due_date >= nowdate:
|
||||||
self.status = "Unpaid"
|
self.status = "Unpaid"
|
||||||
#Check if outstanding amount is 0 due to credit note issued against invoice
|
#Check if outstanding amount is 0 due to credit note issued against invoice
|
||||||
elif outstanding_amount <= 0 and self.is_return == 0 and frappe.db.get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}):
|
elif outstanding_amount <= 0 and self.is_return == 0 and frappe.db.get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}):
|
||||||
@ -1423,23 +1429,42 @@ def set_account_for_mode_of_payment(self):
|
|||||||
data.account = get_bank_cash_account(data.mode_of_payment, self.company).get("account")
|
data.account = get_bank_cash_account(data.mode_of_payment, self.company).get("account")
|
||||||
|
|
||||||
def get_inter_company_details(doc, doctype):
|
def get_inter_company_details(doc, doctype):
|
||||||
if doctype in ["Sales Invoice", "Sales Order"]:
|
if doctype in ["Sales Invoice", "Sales Order", "Delivery Note"]:
|
||||||
party = frappe.db.get_value("Supplier", {"disabled": 0, "is_internal_supplier": 1, "represents_company": doc.company}, "name")
|
parties = frappe.db.get_all("Supplier", fields=["name"], filters={"disabled": 0, "is_internal_supplier": 1, "represents_company": doc.company})
|
||||||
company = frappe.get_cached_value("Customer", doc.customer, "represents_company")
|
company = frappe.get_cached_value("Customer", doc.customer, "represents_company")
|
||||||
|
|
||||||
|
party = get_internal_party(parties, "Supplier", doc)
|
||||||
else:
|
else:
|
||||||
party = frappe.db.get_value("Customer", {"disabled": 0, "is_internal_customer": 1, "represents_company": doc.company}, "name")
|
parties = frappe.db.get_all("Customer", fields=["name"], filters={"disabled": 0, "is_internal_customer": 1, "represents_company": doc.company})
|
||||||
company = frappe.get_cached_value("Supplier", doc.supplier, "represents_company")
|
company = frappe.get_cached_value("Supplier", doc.supplier, "represents_company")
|
||||||
|
|
||||||
|
party = get_internal_party(parties, "Customer", doc)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"party": party,
|
"party": party,
|
||||||
"company": company
|
"company": company
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def get_internal_party(parties, link_doctype, doc):
|
||||||
|
if len(parties) == 1:
|
||||||
|
party = parties[0].name
|
||||||
|
else:
|
||||||
|
# If more than one Internal Supplier/Customer, get supplier/customer on basis of address
|
||||||
|
if doc.get('company_address') or doc.get('shipping_address'):
|
||||||
|
party = frappe.db.get_value("Dynamic Link", {"parent": doc.get('company_address') or doc.get('shipping_address'),
|
||||||
|
"parenttype": "Address", "link_doctype": link_doctype}, "link_name")
|
||||||
|
|
||||||
|
if not party:
|
||||||
|
party = parties[0].name
|
||||||
|
else:
|
||||||
|
party = parties[0].name
|
||||||
|
|
||||||
|
return party
|
||||||
|
|
||||||
def validate_inter_company_transaction(doc, doctype):
|
def validate_inter_company_transaction(doc, doctype):
|
||||||
|
|
||||||
details = get_inter_company_details(doc, doctype)
|
details = get_inter_company_details(doc, doctype)
|
||||||
price_list = doc.selling_price_list if doctype in ["Sales Invoice", "Sales Order"] else doc.buying_price_list
|
price_list = doc.selling_price_list if doctype in ["Sales Invoice", "Sales Order", "Delivery Note"] else doc.buying_price_list
|
||||||
valid_price_list = frappe.db.get_value("Price List", {"name": price_list, "buying": 1, "selling": 1})
|
valid_price_list = frappe.db.get_value("Price List", {"name": price_list, "buying": 1, "selling": 1})
|
||||||
if not valid_price_list:
|
if not valid_price_list:
|
||||||
frappe.throw(_("Selected Price List should have buying and selling fields checked."))
|
frappe.throw(_("Selected Price List should have buying and selling fields checked."))
|
||||||
@ -1523,6 +1548,9 @@ def get_loyalty_programs(customer):
|
|||||||
else:
|
else:
|
||||||
return lp_details
|
return lp_details
|
||||||
|
|
||||||
|
def on_doctype_update():
|
||||||
|
frappe.db.add_index("Sales Invoice", ["customer", "is_return", "return_against"])
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def create_invoice_discounting(source_name, target_doc=None):
|
def create_invoice_discounting(source_name, target_doc=None):
|
||||||
invoice = frappe.get_doc("Sales Invoice", source_name)
|
invoice = frappe.get_doc("Sales Invoice", source_name)
|
||||||
|
@ -705,6 +705,64 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
|
|
||||||
self.pos_gl_entry(si, pos, 50)
|
self.pos_gl_entry(si, pos, 50)
|
||||||
|
|
||||||
|
def test_pos_returns_without_repayment(self):
|
||||||
|
pos_profile = make_pos_profile()
|
||||||
|
|
||||||
|
pos = create_sales_invoice(qty = 10, do_not_save=True)
|
||||||
|
pos.is_pos = 1
|
||||||
|
pos.pos_profile = pos_profile.name
|
||||||
|
|
||||||
|
pos.append("payments", {'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - _TC', 'amount': 500})
|
||||||
|
pos.append("payments", {'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 500})
|
||||||
|
pos.insert()
|
||||||
|
pos.submit()
|
||||||
|
|
||||||
|
pos_return = create_sales_invoice(is_return=1,
|
||||||
|
return_against=pos.name, qty=-5, do_not_save=True)
|
||||||
|
|
||||||
|
pos_return.is_pos = 1
|
||||||
|
pos_return.pos_profile = pos_profile.name
|
||||||
|
|
||||||
|
pos_return.insert()
|
||||||
|
pos_return.submit()
|
||||||
|
|
||||||
|
self.assertFalse(pos_return.is_pos)
|
||||||
|
self.assertFalse(pos_return.get('payments'))
|
||||||
|
|
||||||
|
def test_pos_returns_with_repayment(self):
|
||||||
|
pos_profile = make_pos_profile()
|
||||||
|
|
||||||
|
pos_profile.append('payments', {
|
||||||
|
'default': 1,
|
||||||
|
'mode_of_payment': 'Cash',
|
||||||
|
'amount': 0.0
|
||||||
|
})
|
||||||
|
|
||||||
|
pos_profile.save()
|
||||||
|
|
||||||
|
pos = create_sales_invoice(qty = 10, do_not_save=True)
|
||||||
|
|
||||||
|
pos.is_pos = 1
|
||||||
|
pos.pos_profile = pos_profile.name
|
||||||
|
|
||||||
|
pos.append("payments", {'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - _TC', 'amount': 500})
|
||||||
|
pos.append("payments", {'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 500})
|
||||||
|
pos.insert()
|
||||||
|
pos.submit()
|
||||||
|
|
||||||
|
pos_return = create_sales_invoice(is_return=1,
|
||||||
|
return_against=pos.name, qty=-5, do_not_save=True)
|
||||||
|
|
||||||
|
pos_return.is_pos = 1
|
||||||
|
pos_return.pos_profile = pos_profile.name
|
||||||
|
pos_return.insert()
|
||||||
|
pos_return.submit()
|
||||||
|
|
||||||
|
self.assertEqual(pos_return.get('payments')[0].amount, -500)
|
||||||
|
pos_profile.payments = []
|
||||||
|
pos_profile.save()
|
||||||
|
|
||||||
|
|
||||||
def test_pos_change_amount(self):
|
def test_pos_change_amount(self):
|
||||||
make_pos_profile()
|
make_pos_profile()
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ class ShippingRule(Document):
|
|||||||
if not shipping_country:
|
if not shipping_country:
|
||||||
frappe.throw(_('Shipping Address does not have country, which is required for this Shipping Rule'))
|
frappe.throw(_('Shipping Address does not have country, which is required for this Shipping Rule'))
|
||||||
if shipping_country not in [d.country for d in self.countries]:
|
if shipping_country not in [d.country for d in self.countries]:
|
||||||
frappe.throw(_('Shipping rule not applicable for country {0}'.format(shipping_country)))
|
frappe.throw(_('Shipping rule not applicable for country {0}').format(shipping_country))
|
||||||
|
|
||||||
def add_shipping_rule_to_tax_table(self, doc, shipping_amount):
|
def add_shipping_rule_to_tax_table(self, doc, shipping_amount):
|
||||||
shipping_charge = {
|
shipping_charge = {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"autoname": "ACC-SUB-.YYYY.-.#####",
|
"autoname": "ACC-SUB-.YYYY.-.#####",
|
||||||
"creation": "2017-07-18 17:50:43.967266",
|
"creation": "2017-07-18 17:50:43.967266",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
@ -155,7 +156,7 @@
|
|||||||
"fieldname": "apply_additional_discount",
|
"fieldname": "apply_additional_discount",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"label": "Apply Additional Discount On",
|
"label": "Apply Additional Discount On",
|
||||||
"options": "\nGrand Total\nNet total"
|
"options": "\nGrand Total\nNet Total"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "cb_2",
|
"fieldname": "cb_2",
|
||||||
@ -196,7 +197,8 @@
|
|||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2019-07-25 18:45:38.579579",
|
"links": [],
|
||||||
|
"modified": "2020-01-27 14:37:32.845173",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Subscription",
|
"name": "Subscription",
|
||||||
|
@ -195,7 +195,7 @@ class Subscription(Document):
|
|||||||
doc = frappe.get_doc('Sales Invoice', current.invoice)
|
doc = frappe.get_doc('Sales Invoice', current.invoice)
|
||||||
return doc
|
return doc
|
||||||
else:
|
else:
|
||||||
frappe.throw(_('Invoice {0} no longer exists'.format(current.invoice)))
|
frappe.throw(_('Invoice {0} no longer exists').format(current.invoice))
|
||||||
|
|
||||||
def is_new_subscription(self):
|
def is_new_subscription(self):
|
||||||
"""
|
"""
|
||||||
@ -280,7 +280,7 @@ class Subscription(Document):
|
|||||||
|
|
||||||
if self.additional_discount_percentage or self.additional_discount_amount:
|
if self.additional_discount_percentage or self.additional_discount_amount:
|
||||||
discount_on = self.apply_additional_discount
|
discount_on = self.apply_additional_discount
|
||||||
invoice.apply_additional_discount = discount_on if discount_on else 'Grand Total'
|
invoice.apply_discount_on = discount_on if discount_on else 'Grand Total'
|
||||||
|
|
||||||
# Subscription period
|
# Subscription period
|
||||||
invoice.from_date = self.current_invoice_start
|
invoice.from_date = self.current_invoice_start
|
||||||
@ -388,7 +388,7 @@ class Subscription(Document):
|
|||||||
"""
|
"""
|
||||||
current_invoice = self.get_current_invoice()
|
current_invoice = self.get_current_invoice()
|
||||||
if not current_invoice:
|
if not current_invoice:
|
||||||
frappe.throw(_('Current invoice {0} is missing'.format(current_invoice.invoice)))
|
frappe.throw(_('Current invoice {0} is missing').format(current_invoice.invoice))
|
||||||
else:
|
else:
|
||||||
if self.is_not_outstanding(current_invoice):
|
if self.is_not_outstanding(current_invoice):
|
||||||
self.status = 'Active'
|
self.status = 'Active'
|
||||||
|
@ -95,7 +95,7 @@ class TaxRule(Document):
|
|||||||
|
|
||||||
if tax_rule:
|
if tax_rule:
|
||||||
if tax_rule[0].priority == self.priority:
|
if tax_rule[0].priority == self.priority:
|
||||||
frappe.throw(_("Tax Rule Conflicts with {0}".format(tax_rule[0].name)), ConflictingTaxRule)
|
frappe.throw(_("Tax Rule Conflicts with {0}").format(tax_rule[0].name), ConflictingTaxRule)
|
||||||
|
|
||||||
def validate_use_for_shopping_cart(self):
|
def validate_use_for_shopping_cart(self):
|
||||||
'''If shopping cart is enabled and no tax rule exists for shopping cart, enable this one'''
|
'''If shopping cart is enabled and no tax rule exists for shopping cart, enable this one'''
|
||||||
|
@ -36,7 +36,6 @@ def get_party_details(party=None, account=None, party_type="Customer", company=N
|
|||||||
def _get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None,
|
def _get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None,
|
||||||
bill_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False,
|
bill_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False,
|
||||||
fetch_payment_terms_template=True, party_address=None, company_address=None, shipping_address=None, pos_profile=None):
|
fetch_payment_terms_template=True, party_address=None, company_address=None, shipping_address=None, pos_profile=None):
|
||||||
|
|
||||||
party_details = frappe._dict(set_account_and_due_date(party, account, party_type, company, posting_date, bill_date, doctype))
|
party_details = frappe._dict(set_account_and_due_date(party, account, party_type, company, posting_date, bill_date, doctype))
|
||||||
party = party_details[party_type.lower()]
|
party = party_details[party_type.lower()]
|
||||||
|
|
||||||
|
@ -100,6 +100,11 @@ frappe.query_reports["Accounts Payable"] = {
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"options": "Supplier Group"
|
"options": "Supplier Group"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "group_by_party",
|
||||||
|
"label": __("Group By Supplier"),
|
||||||
|
"fieldtype": "Check"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname":"based_on_payment_terms",
|
"fieldname":"based_on_payment_terms",
|
||||||
"label": __("Based On Payment Terms"),
|
"label": __("Based On Payment Terms"),
|
||||||
@ -112,6 +117,16 @@ frappe.query_reports["Accounts Payable"] = {
|
|||||||
"hidden": 1
|
"hidden": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"formatter": function(value, row, column, data, default_formatter) {
|
||||||
|
value = default_formatter(value, row, column, data);
|
||||||
|
if (data && data.bold) {
|
||||||
|
value = value.bold();
|
||||||
|
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
|
||||||
onload: function(report) {
|
onload: function(report) {
|
||||||
report.page.add_inner_button(__("Accounts Payable Summary"), function() {
|
report.page.add_inner_button(__("Accounts Payable Summary"), function() {
|
||||||
var filters = report.get_values();
|
var filters = report.get_values();
|
||||||
|
@ -131,6 +131,11 @@ frappe.query_reports["Accounts Receivable"] = {
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"options": "Sales Person"
|
"options": "Sales Person"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "group_by_party",
|
||||||
|
"label": __("Group By Customer"),
|
||||||
|
"fieldtype": "Check"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname":"based_on_payment_terms",
|
"fieldname":"based_on_payment_terms",
|
||||||
"label": __("Based On Payment Terms"),
|
"label": __("Based On Payment Terms"),
|
||||||
@ -177,6 +182,15 @@ frappe.query_reports["Accounts Receivable"] = {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"formatter": function(value, row, column, data, default_formatter) {
|
||||||
|
value = default_formatter(value, row, column, data);
|
||||||
|
if (data && data.bold) {
|
||||||
|
value = value.bold();
|
||||||
|
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
|
||||||
onload: function(report) {
|
onload: function(report) {
|
||||||
report.page.add_inner_button(__("Accounts Receivable Summary"), function() {
|
report.page.add_inner_button(__("Accounts Receivable Summary"), function() {
|
||||||
var filters = report.get_values();
|
var filters = report.get_values();
|
||||||
|
@ -46,7 +46,7 @@ class ReceivablePayableReport(object):
|
|||||||
self.get_columns()
|
self.get_columns()
|
||||||
self.get_data()
|
self.get_data()
|
||||||
self.get_chart_data()
|
self.get_chart_data()
|
||||||
return self.columns, self.data, None, self.chart
|
return self.columns, self.data, None, self.chart, None, self.skip_total_row
|
||||||
|
|
||||||
def set_defaults(self):
|
def set_defaults(self):
|
||||||
if not self.filters.get("company"):
|
if not self.filters.get("company"):
|
||||||
@ -57,6 +57,12 @@ class ReceivablePayableReport(object):
|
|||||||
self.party_type = self.filters.party_type
|
self.party_type = self.filters.party_type
|
||||||
self.party_details = {}
|
self.party_details = {}
|
||||||
self.invoices = set()
|
self.invoices = set()
|
||||||
|
self.skip_total_row = 0
|
||||||
|
|
||||||
|
if self.filters.get('group_by_party'):
|
||||||
|
self.previous_party=''
|
||||||
|
self.total_row_map = {}
|
||||||
|
self.skip_total_row = 1
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
self.get_gl_entries()
|
self.get_gl_entries()
|
||||||
@ -102,6 +108,12 @@ class ReceivablePayableReport(object):
|
|||||||
)
|
)
|
||||||
self.get_invoices(gle)
|
self.get_invoices(gle)
|
||||||
|
|
||||||
|
if self.filters.get('group_by_party'):
|
||||||
|
self.init_subtotal_row(gle.party)
|
||||||
|
|
||||||
|
if self.filters.get('group_by_party'):
|
||||||
|
self.init_subtotal_row('Total')
|
||||||
|
|
||||||
def get_invoices(self, gle):
|
def get_invoices(self, gle):
|
||||||
if gle.voucher_type in ('Sales Invoice', 'Purchase Invoice'):
|
if gle.voucher_type in ('Sales Invoice', 'Purchase Invoice'):
|
||||||
if self.filters.get("sales_person"):
|
if self.filters.get("sales_person"):
|
||||||
@ -111,6 +123,20 @@ class ReceivablePayableReport(object):
|
|||||||
else:
|
else:
|
||||||
self.invoices.add(gle.voucher_no)
|
self.invoices.add(gle.voucher_no)
|
||||||
|
|
||||||
|
def init_subtotal_row(self, party):
|
||||||
|
if not self.total_row_map.get(party):
|
||||||
|
self.total_row_map.setdefault(party, {
|
||||||
|
'party': party,
|
||||||
|
'bold': 1
|
||||||
|
})
|
||||||
|
|
||||||
|
for field in self.get_currency_fields():
|
||||||
|
self.total_row_map[party][field] = 0.0
|
||||||
|
|
||||||
|
def get_currency_fields(self):
|
||||||
|
return ['invoiced', 'paid', 'credit_note', 'outstanding', 'range1',
|
||||||
|
'range2', 'range3', 'range4', 'range5']
|
||||||
|
|
||||||
def update_voucher_balance(self, gle):
|
def update_voucher_balance(self, gle):
|
||||||
# get the row where this balance needs to be updated
|
# get the row where this balance needs to be updated
|
||||||
# if its a payment, it will return the linked invoice or will be considered as advance
|
# if its a payment, it will return the linked invoice or will be considered as advance
|
||||||
@ -135,6 +161,18 @@ class ReceivablePayableReport(object):
|
|||||||
# advance / unlinked payment or other adjustment
|
# advance / unlinked payment or other adjustment
|
||||||
row.paid -= gle_balance
|
row.paid -= gle_balance
|
||||||
|
|
||||||
|
def update_sub_total_row(self, row, party):
|
||||||
|
total_row = self.total_row_map.get(party)
|
||||||
|
|
||||||
|
for field in self.get_currency_fields():
|
||||||
|
total_row[field] += row.get(field, 0.0)
|
||||||
|
|
||||||
|
def append_subtotal_row(self, party):
|
||||||
|
sub_total_row = self.total_row_map.get(party)
|
||||||
|
self.data.append(sub_total_row)
|
||||||
|
self.data.append({})
|
||||||
|
self.update_sub_total_row(sub_total_row, 'Total')
|
||||||
|
|
||||||
def get_voucher_balance(self, gle):
|
def get_voucher_balance(self, gle):
|
||||||
if self.filters.get("sales_person"):
|
if self.filters.get("sales_person"):
|
||||||
against_voucher = gle.against_voucher or gle.voucher_no
|
against_voucher = gle.against_voucher or gle.voucher_no
|
||||||
@ -192,11 +230,22 @@ class ReceivablePayableReport(object):
|
|||||||
else:
|
else:
|
||||||
self.append_row(row)
|
self.append_row(row)
|
||||||
|
|
||||||
|
if self.filters.get('group_by_party'):
|
||||||
|
self.append_subtotal_row(self.previous_party)
|
||||||
|
self.data.append(self.total_row_map.get('Total'))
|
||||||
|
|
||||||
def append_row(self, row):
|
def append_row(self, row):
|
||||||
self.allocate_future_payments(row)
|
self.allocate_future_payments(row)
|
||||||
self.set_invoice_details(row)
|
self.set_invoice_details(row)
|
||||||
self.set_party_details(row)
|
self.set_party_details(row)
|
||||||
self.set_ageing(row)
|
self.set_ageing(row)
|
||||||
|
|
||||||
|
if self.filters.get('group_by_party'):
|
||||||
|
self.update_sub_total_row(row, row.party)
|
||||||
|
if self.previous_party and (self.previous_party != row.party):
|
||||||
|
self.append_subtotal_row(self.previous_party)
|
||||||
|
self.previous_party = row.party
|
||||||
|
|
||||||
self.data.append(row)
|
self.data.append(row)
|
||||||
|
|
||||||
def set_invoice_details(self, row):
|
def set_invoice_details(self, row):
|
||||||
@ -503,6 +552,7 @@ class ReceivablePayableReport(object):
|
|||||||
# get all the GL entries filtered by the given filters
|
# get all the GL entries filtered by the given filters
|
||||||
|
|
||||||
conditions, values = self.prepare_conditions()
|
conditions, values = self.prepare_conditions()
|
||||||
|
order_by = self.get_order_by_condition()
|
||||||
|
|
||||||
if self.filters.get(scrub(self.party_type)):
|
if self.filters.get(scrub(self.party_type)):
|
||||||
select_fields = "debit_in_account_currency as debit, credit_in_account_currency as credit"
|
select_fields = "debit_in_account_currency as debit, credit_in_account_currency as credit"
|
||||||
@ -520,9 +570,8 @@ class ReceivablePayableReport(object):
|
|||||||
and party_type=%s
|
and party_type=%s
|
||||||
and (party is not null and party != '')
|
and (party is not null and party != '')
|
||||||
and posting_date <= %s
|
and posting_date <= %s
|
||||||
{1}
|
{1} {2}"""
|
||||||
order by posting_date, party"""
|
.format(select_fields, conditions, order_by), values, as_dict=True)
|
||||||
.format(select_fields, conditions), values, as_dict=True)
|
|
||||||
|
|
||||||
def get_sales_invoices_or_customers_based_on_sales_person(self):
|
def get_sales_invoices_or_customers_based_on_sales_person(self):
|
||||||
if self.filters.get("sales_person"):
|
if self.filters.get("sales_person"):
|
||||||
@ -557,6 +606,12 @@ class ReceivablePayableReport(object):
|
|||||||
|
|
||||||
return " and ".join(conditions), values
|
return " and ".join(conditions), values
|
||||||
|
|
||||||
|
def get_order_by_condition(self):
|
||||||
|
if self.filters.get('group_by_party'):
|
||||||
|
return "order by party, posting_date"
|
||||||
|
else:
|
||||||
|
return "order by posting_date, party"
|
||||||
|
|
||||||
def add_common_filters(self, conditions, values, party_type_field):
|
def add_common_filters(self, conditions, values, party_type_field):
|
||||||
if self.filters.company:
|
if self.filters.company:
|
||||||
conditions.append("company=%s")
|
conditions.append("company=%s")
|
||||||
@ -736,6 +791,8 @@ class ReceivablePayableReport(object):
|
|||||||
def get_chart_data(self):
|
def get_chart_data(self):
|
||||||
rows = []
|
rows = []
|
||||||
for row in self.data:
|
for row in self.data:
|
||||||
|
row = frappe._dict(row)
|
||||||
|
if not cint(row.bold):
|
||||||
values = [row.range1, row.range2, row.range3, row.range4, row.range5]
|
values = [row.range1, row.range2, row.range3, row.range4, row.range5]
|
||||||
precision = cint(frappe.db.get_default("float_precision")) or 2
|
precision = cint(frappe.db.get_default("float_precision")) or 2
|
||||||
rows.append({
|
rows.append({
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import cint
|
from frappe.utils import cint, cstr
|
||||||
from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
|
from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
|
||||||
from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import get_net_profit_loss
|
from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import get_net_profit_loss
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
@ -129,13 +129,13 @@ def get_account_type_based_gl_data(company, start_date, end_date, account_type,
|
|||||||
cond = ""
|
cond = ""
|
||||||
filters = frappe._dict(filters)
|
filters = frappe._dict(filters)
|
||||||
|
|
||||||
if filters.finance_book:
|
|
||||||
cond = " AND (finance_book in (%s, '') OR finance_book IS NULL)" %(frappe.db.escape(filters.finance_book))
|
|
||||||
if filters.include_default_book_entries:
|
if filters.include_default_book_entries:
|
||||||
company_fb = frappe.db.get_value("Company", company, 'default_finance_book')
|
company_fb = frappe.db.get_value("Company", company, 'default_finance_book')
|
||||||
|
|
||||||
cond = """ AND (finance_book in (%s, %s, '') OR finance_book IS NULL)
|
cond = """ AND (finance_book in (%s, %s, '') OR finance_book IS NULL)
|
||||||
""" %(frappe.db.escape(filters.finance_book), frappe.db.escape(company_fb))
|
""" %(frappe.db.escape(filters.finance_book), frappe.db.escape(company_fb))
|
||||||
|
else:
|
||||||
|
cond = " AND (finance_book in (%s, '') OR finance_book IS NULL)" %(frappe.db.escape(cstr(filters.finance_book)))
|
||||||
|
|
||||||
|
|
||||||
gl_sum = frappe.db.sql_list("""
|
gl_sum = frappe.db.sql_list("""
|
||||||
select sum(credit) - sum(debit)
|
select sum(credit) - sum(debit)
|
||||||
|
@ -387,7 +387,6 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
|
|||||||
if from_date:
|
if from_date:
|
||||||
additional_conditions.append("gl.posting_date >= %(from_date)s")
|
additional_conditions.append("gl.posting_date >= %(from_date)s")
|
||||||
|
|
||||||
if filters.get("finance_book"):
|
|
||||||
if filters.get("include_default_book_entries"):
|
if filters.get("include_default_book_entries"):
|
||||||
additional_conditions.append("(finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)")
|
additional_conditions.append("(finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)")
|
||||||
else:
|
else:
|
||||||
|
@ -13,7 +13,7 @@ import frappe, erpnext
|
|||||||
from erpnext.accounts.report.utils import get_currency, convert_to_presentation_currency
|
from erpnext.accounts.report.utils import get_currency, convert_to_presentation_currency
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import (flt, getdate, get_first_day, add_months, add_days, formatdate)
|
from frappe.utils import (flt, getdate, get_first_day, add_months, add_days, formatdate, cstr)
|
||||||
|
|
||||||
from six import itervalues
|
from six import itervalues
|
||||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
||||||
@ -175,7 +175,7 @@ def calculate_values(
|
|||||||
d = accounts_by_name.get(entry.account)
|
d = accounts_by_name.get(entry.account)
|
||||||
if not d:
|
if not d:
|
||||||
frappe.msgprint(
|
frappe.msgprint(
|
||||||
_("Could not retrieve information for {0}.".format(entry.account)), title="Error",
|
_("Could not retrieve information for {0}.").format(entry.account), title="Error",
|
||||||
raise_exception=1
|
raise_exception=1
|
||||||
)
|
)
|
||||||
for period in period_list:
|
for period in period_list:
|
||||||
@ -348,7 +348,9 @@ def set_gl_entries_by_account(
|
|||||||
additional_conditions = get_additional_conditions(from_date, ignore_closing_entries, filters)
|
additional_conditions = get_additional_conditions(from_date, ignore_closing_entries, filters)
|
||||||
|
|
||||||
accounts = frappe.db.sql_list("""select name from `tabAccount`
|
accounts = frappe.db.sql_list("""select name from `tabAccount`
|
||||||
where lft >= %s and rgt <= %s""", (root_lft, root_rgt))
|
where lft >= %s and rgt <= %s and company = %s""", (root_lft, root_rgt, company))
|
||||||
|
|
||||||
|
if accounts:
|
||||||
additional_conditions += " and account in ({})"\
|
additional_conditions += " and account in ({})"\
|
||||||
.format(", ".join([frappe.db.escape(d) for d in accounts]))
|
.format(", ".join([frappe.db.escape(d) for d in accounts]))
|
||||||
|
|
||||||
@ -356,7 +358,7 @@ def set_gl_entries_by_account(
|
|||||||
"company": company,
|
"company": company,
|
||||||
"from_date": from_date,
|
"from_date": from_date,
|
||||||
"to_date": to_date,
|
"to_date": to_date,
|
||||||
"finance_book": filters.get("finance_book")
|
"finance_book": cstr(filters.get("finance_book"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if filters.get("include_default_book_entries"):
|
if filters.get("include_default_book_entries"):
|
||||||
@ -406,7 +408,6 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
|
|||||||
filters.cost_center = get_cost_centers_with_children(filters.cost_center)
|
filters.cost_center = get_cost_centers_with_children(filters.cost_center)
|
||||||
additional_conditions.append("cost_center in %(cost_center)s")
|
additional_conditions.append("cost_center in %(cost_center)s")
|
||||||
|
|
||||||
if filters.get("finance_book"):
|
|
||||||
if filters.get("include_default_book_entries"):
|
if filters.get("include_default_book_entries"):
|
||||||
additional_conditions.append("(finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)")
|
additional_conditions.append("(finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)")
|
||||||
else:
|
else:
|
||||||
@ -430,7 +431,7 @@ def get_cost_centers_with_children(cost_centers):
|
|||||||
children = frappe.get_all("Cost Center", filters={"lft": [">=", lft], "rgt": ["<=", rgt]})
|
children = frappe.get_all("Cost Center", filters={"lft": [">=", lft], "rgt": ["<=", rgt]})
|
||||||
all_cost_centers += [c.name for c in children]
|
all_cost_centers += [c.name for c in children]
|
||||||
else:
|
else:
|
||||||
frappe.throw(_("Cost Center: {0} does not exist".format(d)))
|
frappe.throw(_("Cost Center: {0} does not exist").format(d))
|
||||||
|
|
||||||
return list(set(all_cost_centers))
|
return list(set(all_cost_centers))
|
||||||
|
|
||||||
|
@ -373,19 +373,19 @@ def get_columns(filters):
|
|||||||
"width": 180
|
"width": 180
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": _("Debit ({0})".format(currency)),
|
"label": _("Debit ({0})").format(currency),
|
||||||
"fieldname": "debit",
|
"fieldname": "debit",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"width": 100
|
"width": 100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": _("Credit ({0})".format(currency)),
|
"label": _("Credit ({0})").format(currency),
|
||||||
"fieldname": "credit",
|
"fieldname": "credit",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"width": 100
|
"width": 100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": _("Balance ({0})".format(currency)),
|
"label": _("Balance ({0})").format(currency),
|
||||||
"fieldname": "balance",
|
"fieldname": "balance",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"width": 130
|
"width": 130
|
||||||
|
@ -34,6 +34,20 @@ frappe.query_reports["Item-wise Purchase Register"] = {
|
|||||||
"label": __("Mode of Payment"),
|
"label": __("Mode of Payment"),
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"options": "Mode of Payment"
|
"options": "Mode of Payment"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": __("Group By"),
|
||||||
|
"fieldname": "group_by",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"options": ["Supplier", "Item Group", "Item", "Invoice"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"formatter": function(value, row, column, data, default_formatter) {
|
||||||
|
value = default_formatter(value, row, column, data);
|
||||||
|
if (data && data.bold) {
|
||||||
|
value = value.bold();
|
||||||
|
|
||||||
|
}
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,9 @@ from __future__ import unicode_literals
|
|||||||
import frappe, erpnext
|
import frappe, erpnext
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import flt
|
from frappe.utils import flt
|
||||||
from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import get_tax_accounts
|
from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import (get_tax_accounts,
|
||||||
|
get_grand_total, add_total_row, get_display_value, get_group_by_and_display_fields, add_sub_total_row,
|
||||||
|
get_group_by_conditions)
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
return _execute(filters)
|
return _execute(filters)
|
||||||
@ -13,7 +15,7 @@ def execute(filters=None):
|
|||||||
def _execute(filters=None, additional_table_columns=None, additional_query_columns=None):
|
def _execute(filters=None, additional_table_columns=None, additional_query_columns=None):
|
||||||
if not filters: filters = {}
|
if not filters: filters = {}
|
||||||
filters.update({"from_date": filters.get("date_range")[0], "to_date": filters.get("date_range")[1]})
|
filters.update({"from_date": filters.get("date_range")[0], "to_date": filters.get("date_range")[1]})
|
||||||
columns = get_columns(additional_table_columns)
|
columns = get_columns(additional_table_columns, filters)
|
||||||
|
|
||||||
company_currency = erpnext.get_company_currency(filters.company)
|
company_currency = erpnext.get_company_currency(filters.company)
|
||||||
|
|
||||||
@ -23,16 +25,16 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
|||||||
itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency,
|
itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency,
|
||||||
doctype="Purchase Invoice", tax_doctype="Purchase Taxes and Charges")
|
doctype="Purchase Invoice", tax_doctype="Purchase Taxes and Charges")
|
||||||
|
|
||||||
columns.append({
|
|
||||||
"fieldname": "currency",
|
|
||||||
"label": _("Currency"),
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"width": 80
|
|
||||||
})
|
|
||||||
|
|
||||||
po_pr_map = get_purchase_receipts_against_purchase_order(item_list)
|
po_pr_map = get_purchase_receipts_against_purchase_order(item_list)
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
|
total_row_map = {}
|
||||||
|
skip_total_row = 0
|
||||||
|
prev_group_by_value = ''
|
||||||
|
|
||||||
|
if filters.get('group_by'):
|
||||||
|
grand_total = get_grand_total(filters, 'Purchase Invoice')
|
||||||
|
|
||||||
for d in item_list:
|
for d in item_list:
|
||||||
if not d.stock_qty:
|
if not d.stock_qty:
|
||||||
continue
|
continue
|
||||||
@ -44,51 +46,243 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
|||||||
purchase_receipt = ", ".join(po_pr_map.get(d.po_detail, []))
|
purchase_receipt = ", ".join(po_pr_map.get(d.po_detail, []))
|
||||||
|
|
||||||
expense_account = d.expense_account or aii_account_map.get(d.company)
|
expense_account = d.expense_account or aii_account_map.get(d.company)
|
||||||
row = [d.item_code, d.item_name, d.item_group, d.description, d.parent, d.posting_date, d.supplier,
|
|
||||||
d.supplier_name]
|
row = {
|
||||||
|
'item_code': d.item_code,
|
||||||
|
'item_name': d.item_name,
|
||||||
|
'item_group': d.item_group,
|
||||||
|
'description': d.description,
|
||||||
|
'invoice': d.parent,
|
||||||
|
'posting_date': d.posting_date,
|
||||||
|
'customer': d.supplier,
|
||||||
|
'customer_name': d.supplier_name
|
||||||
|
}
|
||||||
|
|
||||||
if additional_query_columns:
|
if additional_query_columns:
|
||||||
for col in additional_query_columns:
|
for col in additional_query_columns:
|
||||||
row.append(d.get(col))
|
row.update({
|
||||||
|
col: d.get(col)
|
||||||
|
})
|
||||||
|
|
||||||
row += [
|
row.update({
|
||||||
d.credit_to, d.mode_of_payment, d.project, d.company, d.purchase_order,
|
'credit_to': d.credit_to,
|
||||||
purchase_receipt, expense_account, d.stock_qty, d.stock_uom, d.base_net_amount / d.stock_qty, d.base_net_amount
|
'mode_of_payment': d.mode_of_payment,
|
||||||
]
|
'project': d.project,
|
||||||
|
'company': d.company,
|
||||||
|
'purchase_order': d.purchase_order,
|
||||||
|
'purchase_receipt': d.purchase_receipt,
|
||||||
|
'expense_account': expense_account,
|
||||||
|
'stock_qty': d.stock_qty,
|
||||||
|
'stock_uom': d.stock_uom,
|
||||||
|
'rate': d.base_net_amount / d.stock_qty,
|
||||||
|
'amount': d.base_net_amount
|
||||||
|
})
|
||||||
|
|
||||||
total_tax = 0
|
total_tax = 0
|
||||||
for tax in tax_columns:
|
for tax in tax_columns:
|
||||||
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
|
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
|
||||||
row += [item_tax.get("tax_rate", 0), item_tax.get("tax_amount", 0)]
|
row.update({
|
||||||
|
frappe.scrub(tax + ' Rate'): item_tax.get("tax_rate", 0),
|
||||||
|
frappe.scrub(tax + ' Amount'): item_tax.get("tax_amount", 0),
|
||||||
|
})
|
||||||
total_tax += flt(item_tax.get("tax_amount"))
|
total_tax += flt(item_tax.get("tax_amount"))
|
||||||
|
|
||||||
row += [total_tax, d.base_net_amount + total_tax, company_currency]
|
row.update({
|
||||||
|
'total_tax': total_tax,
|
||||||
|
'total': d.base_net_amount + total_tax,
|
||||||
|
'currency': company_currency
|
||||||
|
})
|
||||||
|
|
||||||
|
if filters.get('group_by'):
|
||||||
|
row.update({'percent_gt': flt(row['total']/grand_total) * 100})
|
||||||
|
group_by_field, subtotal_display_field = get_group_by_and_display_fields(filters)
|
||||||
|
data, prev_group_by_value = add_total_row(data, filters, prev_group_by_value, d, total_row_map,
|
||||||
|
group_by_field, subtotal_display_field, grand_total, tax_columns)
|
||||||
|
add_sub_total_row(row, total_row_map, d.get(group_by_field, ''), tax_columns)
|
||||||
|
|
||||||
data.append(row)
|
data.append(row)
|
||||||
|
|
||||||
return columns, data
|
if filters.get('group_by'):
|
||||||
|
total_row = total_row_map.get(prev_group_by_value or d.get('item_name'))
|
||||||
|
total_row['percent_gt'] = flt(total_row['total']/grand_total * 100)
|
||||||
|
data.append(total_row)
|
||||||
|
data.append({})
|
||||||
|
add_sub_total_row(total_row, total_row_map, 'total_row', tax_columns)
|
||||||
|
data.append(total_row_map.get('total_row'))
|
||||||
|
skip_total_row = 1
|
||||||
|
|
||||||
|
return columns, data, None, None, None, skip_total_row
|
||||||
|
|
||||||
|
|
||||||
def get_columns(additional_table_columns):
|
def get_columns(additional_table_columns, filters):
|
||||||
columns = [
|
|
||||||
_("Item Code") + ":Link/Item:120", _("Item Name") + "::120",
|
columns = []
|
||||||
_("Item Group") + ":Link/Item Group:100", "Description::150", _("Invoice") + ":Link/Purchase Invoice:120",
|
|
||||||
_("Posting Date") + ":Date:80", _("Supplier") + ":Link/Supplier:120",
|
if filters.get('group_by') != ('Item'):
|
||||||
"Supplier Name::120"
|
columns.extend(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
'label': _('Item Code'),
|
||||||
|
'fieldname': 'item_code',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Item',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Item Name'),
|
||||||
|
'fieldname': 'item_name',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 120
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
if filters.get('group_by') not in ('Item', 'Item Group'):
|
||||||
|
columns.extend([
|
||||||
|
{
|
||||||
|
'label': _('Item Group'),
|
||||||
|
'fieldname': 'item_group',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Item Group',
|
||||||
|
'width': 120
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
columns.extend([
|
||||||
|
{
|
||||||
|
'label': _('Description'),
|
||||||
|
'fieldname': 'description',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Invoice'),
|
||||||
|
'fieldname': 'invoice',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Purchase Invoice',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Posting Date'),
|
||||||
|
'fieldname': 'posting_date',
|
||||||
|
'fieldtype': 'Date',
|
||||||
|
'width': 120
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
if filters.get('group_by') != 'Supplier':
|
||||||
|
columns.extend([
|
||||||
|
{
|
||||||
|
'label': _('Supplier'),
|
||||||
|
'fieldname': 'supplier',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Supplier',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Supplier Name'),
|
||||||
|
'fieldname': 'supplier_name',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 120
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
if additional_table_columns:
|
if additional_table_columns:
|
||||||
columns += additional_table_columns
|
columns += additional_table_columns
|
||||||
|
|
||||||
columns += [
|
columns += [
|
||||||
"Payable Account:Link/Account:120",
|
{
|
||||||
_("Mode of Payment") + ":Link/Mode of Payment:80", _("Project") + ":Link/Project:80",
|
'label': _('Payable Account'),
|
||||||
_("Company") + ":Link/Company:100", _("Purchase Order") + ":Link/Purchase Order:100",
|
'fieldname': 'credit_to',
|
||||||
_("Purchase Receipt") + ":Link/Purchase Receipt:100", _("Expense Account") + ":Link/Account:140",
|
'fieldtype': 'Link',
|
||||||
_("Stock Qty") + ":Float:120", _("Stock UOM") + "::100",
|
'options': 'Account',
|
||||||
_("Rate") + ":Currency/currency:120", _("Amount") + ":Currency/currency:120"
|
'width': 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Mode Of Payment'),
|
||||||
|
'fieldname': 'mode_of_payment',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Project'),
|
||||||
|
'fieldname': 'project',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Project',
|
||||||
|
'width': 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Company'),
|
||||||
|
'fieldname': 'company',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Company',
|
||||||
|
'width': 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Purchase Order'),
|
||||||
|
'fieldname': 'purchase_order',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Purchase Order',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Purchase Receipt"),
|
||||||
|
'fieldname': 'Purchase Receipt',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Purchase Receipt',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Expense Account'),
|
||||||
|
'fieldname': 'expense_account',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Account',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Stock Qty'),
|
||||||
|
'fieldname': 'stock_qty',
|
||||||
|
'fieldtype': 'Float',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Stock UOM'),
|
||||||
|
'fieldname': 'stock_uom',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'UOM',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Rate'),
|
||||||
|
'fieldname': 'rate',
|
||||||
|
'fieldtype': 'Float',
|
||||||
|
'options': 'currency',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Amount'),
|
||||||
|
'fieldname': 'amount',
|
||||||
|
'fieldtype': 'Currency',
|
||||||
|
'options': 'currency',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'currency',
|
||||||
|
'label': _('Currency'),
|
||||||
|
'fieldtype': 'Currency',
|
||||||
|
'width': 80,
|
||||||
|
'hidden': 1
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if filters.get('group_by'):
|
||||||
|
columns.append({
|
||||||
|
'label': _('% Of Grand Total'),
|
||||||
|
'fieldname': 'percent_gt',
|
||||||
|
'fieldtype': 'Float',
|
||||||
|
'width': 80
|
||||||
|
})
|
||||||
|
|
||||||
return columns
|
return columns
|
||||||
|
|
||||||
def get_conditions(filters):
|
def get_conditions(filters):
|
||||||
@ -103,6 +297,11 @@ def get_conditions(filters):
|
|||||||
if filters.get(opts[0]):
|
if filters.get(opts[0]):
|
||||||
conditions += opts[1]
|
conditions += opts[1]
|
||||||
|
|
||||||
|
if not filters.get("group_by"):
|
||||||
|
conditions += "ORDER BY `tabPurchase Invoice`.posting_date desc, `tabPurchase Invoice Item`.item_code desc"
|
||||||
|
else:
|
||||||
|
conditions += get_group_by_conditions(filters, 'Purchase Invoice')
|
||||||
|
|
||||||
return conditions
|
return conditions
|
||||||
|
|
||||||
def get_items(filters, additional_query_columns):
|
def get_items(filters, additional_query_columns):
|
||||||
@ -129,7 +328,6 @@ def get_items(filters, additional_query_columns):
|
|||||||
from `tabPurchase Invoice`, `tabPurchase Invoice Item`
|
from `tabPurchase Invoice`, `tabPurchase Invoice Item`
|
||||||
where `tabPurchase Invoice`.name = `tabPurchase Invoice Item`.`parent` and
|
where `tabPurchase Invoice`.name = `tabPurchase Invoice Item`.`parent` and
|
||||||
`tabPurchase Invoice`.docstatus = 1 %s %s
|
`tabPurchase Invoice`.docstatus = 1 %s %s
|
||||||
order by `tabPurchase Invoice`.posting_date desc, `tabPurchase Invoice Item`.item_code desc
|
|
||||||
""".format(additional_query_columns) % (conditions, match_conditions), filters, as_dict=1)
|
""".format(additional_query_columns) % (conditions, match_conditions), filters, as_dict=1)
|
||||||
|
|
||||||
def get_aii_accounts():
|
def get_aii_accounts():
|
||||||
|
@ -46,6 +46,20 @@ frappe.query_reports["Item-wise Sales Register"] = {
|
|||||||
"label": __("Item Group"),
|
"label": __("Item Group"),
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"options": "Item Group"
|
"options": "Item Group"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": __("Group By"),
|
||||||
|
"fieldname": "group_by",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"options": ["Customer Group", "Customer", "Item Group", "Item", "Territory", "Invoice"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"formatter": function(value, row, column, data, default_formatter) {
|
||||||
|
value = default_formatter(value, row, column, data);
|
||||||
|
if (data && data.bold) {
|
||||||
|
value = value.bold();
|
||||||
|
|
||||||
|
}
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe, erpnext
|
import frappe, erpnext
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import flt
|
from frappe.utils import flt, cstr
|
||||||
from frappe.model.meta import get_field_precision
|
from frappe.model.meta import get_field_precision
|
||||||
from frappe.utils.xlsxutils import handle_html
|
from frappe.utils.xlsxutils import handle_html
|
||||||
from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments
|
from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments
|
||||||
@ -15,23 +15,25 @@ def execute(filters=None):
|
|||||||
def _execute(filters=None, additional_table_columns=None, additional_query_columns=None):
|
def _execute(filters=None, additional_table_columns=None, additional_query_columns=None):
|
||||||
if not filters: filters = {}
|
if not filters: filters = {}
|
||||||
filters.update({"from_date": filters.get("date_range") and filters.get("date_range")[0], "to_date": filters.get("date_range") and filters.get("date_range")[1]})
|
filters.update({"from_date": filters.get("date_range") and filters.get("date_range")[0], "to_date": filters.get("date_range") and filters.get("date_range")[1]})
|
||||||
columns = get_columns(additional_table_columns)
|
columns = get_columns(additional_table_columns, filters)
|
||||||
|
|
||||||
company_currency = frappe.get_cached_value('Company', filters.get("company"), "default_currency")
|
company_currency = frappe.get_cached_value('Company', filters.get("company"), "default_currency")
|
||||||
|
|
||||||
item_list = get_items(filters, additional_query_columns)
|
item_list = get_items(filters, additional_query_columns)
|
||||||
if item_list:
|
if item_list:
|
||||||
itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency)
|
itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency)
|
||||||
columns.append({
|
|
||||||
"fieldname": "currency",
|
|
||||||
"label": _("Currency"),
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"width": 80
|
|
||||||
})
|
|
||||||
mode_of_payments = get_mode_of_payments(set([d.parent for d in item_list]))
|
mode_of_payments = get_mode_of_payments(set([d.parent for d in item_list]))
|
||||||
so_dn_map = get_delivery_notes_against_sales_order(item_list)
|
so_dn_map = get_delivery_notes_against_sales_order(item_list)
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
|
total_row_map = {}
|
||||||
|
skip_total_row = 0
|
||||||
|
prev_group_by_value = ''
|
||||||
|
|
||||||
|
if filters.get('group_by'):
|
||||||
|
grand_total = get_grand_total(filters, 'Sales Invoice')
|
||||||
|
|
||||||
for d in item_list:
|
for d in item_list:
|
||||||
delivery_note = None
|
delivery_note = None
|
||||||
if d.delivery_note:
|
if d.delivery_note:
|
||||||
@ -42,57 +44,285 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
|||||||
if not delivery_note and d.update_stock:
|
if not delivery_note and d.update_stock:
|
||||||
delivery_note = d.parent
|
delivery_note = d.parent
|
||||||
|
|
||||||
row = [d.item_code, d.item_name, d.item_group, d.description, d.parent, d.posting_date, d.customer, d.customer_name]
|
row = {
|
||||||
|
'item_code': d.item_code,
|
||||||
|
'item_name': d.item_name,
|
||||||
|
'item_group': d.item_group,
|
||||||
|
'description': d.description,
|
||||||
|
'invoice': d.parent,
|
||||||
|
'posting_date': d.posting_date,
|
||||||
|
'customer': d.customer,
|
||||||
|
'customer_name': d.customer_name,
|
||||||
|
'customer_group': d.customer_group,
|
||||||
|
}
|
||||||
|
|
||||||
if additional_query_columns:
|
if additional_query_columns:
|
||||||
for col in additional_query_columns:
|
for col in additional_query_columns:
|
||||||
row.append(d.get(col))
|
row.update({
|
||||||
|
col: d.get(col)
|
||||||
|
})
|
||||||
|
|
||||||
row += [
|
row.update({
|
||||||
d.customer_group, d.debit_to, ", ".join(mode_of_payments.get(d.parent, [])),
|
'debit_to': d.debit_to,
|
||||||
d.territory, d.project, d.company, d.sales_order,
|
'mode_of_payment': ", ".join(mode_of_payments.get(d.parent, [])),
|
||||||
delivery_note, d.income_account, d.cost_center, d.stock_qty, d.stock_uom
|
'territory': d.territory,
|
||||||
]
|
'project': d.project,
|
||||||
|
'company': d.company,
|
||||||
|
'sales_order': d.sales_order,
|
||||||
|
'delivery_note': d.delivery_note,
|
||||||
|
'income_account': d.income_account,
|
||||||
|
'cost_center': d.cost_center,
|
||||||
|
'stock_qty': d.stock_qty,
|
||||||
|
'stock_uom': d.stock_uom
|
||||||
|
})
|
||||||
|
|
||||||
if d.stock_uom != d.uom and d.stock_qty:
|
if d.stock_uom != d.uom and d.stock_qty:
|
||||||
row += [(d.base_net_rate * d.qty)/d.stock_qty, d.base_net_amount]
|
row.update({
|
||||||
|
'rate': (d.base_net_rate * d.qty)/d.stock_qty,
|
||||||
|
'amount': d.base_net_amount
|
||||||
|
})
|
||||||
else:
|
else:
|
||||||
row += [d.base_net_rate, d.base_net_amount]
|
row.update({
|
||||||
|
'rate': d.base_net_rate,
|
||||||
|
'amount': d.base_net_amount
|
||||||
|
})
|
||||||
|
|
||||||
total_tax = 0
|
total_tax = 0
|
||||||
for tax in tax_columns:
|
for tax in tax_columns:
|
||||||
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
|
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
|
||||||
row += [item_tax.get("tax_rate", 0), item_tax.get("tax_amount", 0)]
|
row.update({
|
||||||
|
frappe.scrub(tax + ' Rate'): item_tax.get("tax_rate", 0),
|
||||||
|
frappe.scrub(tax + ' Amount'): item_tax.get("tax_amount", 0),
|
||||||
|
})
|
||||||
total_tax += flt(item_tax.get("tax_amount"))
|
total_tax += flt(item_tax.get("tax_amount"))
|
||||||
|
|
||||||
row += [total_tax, d.base_net_amount + total_tax, company_currency]
|
row.update({
|
||||||
|
'total_tax': total_tax,
|
||||||
|
'total': d.base_net_amount + total_tax,
|
||||||
|
'currency': company_currency
|
||||||
|
})
|
||||||
|
|
||||||
|
if filters.get('group_by'):
|
||||||
|
row.update({'percent_gt': flt(row['total']/grand_total) * 100})
|
||||||
|
group_by_field, subtotal_display_field = get_group_by_and_display_fields(filters)
|
||||||
|
data, prev_group_by_value = add_total_row(data, filters, prev_group_by_value, d, total_row_map,
|
||||||
|
group_by_field, subtotal_display_field, grand_total, tax_columns)
|
||||||
|
add_sub_total_row(row, total_row_map, d.get(group_by_field, ''), tax_columns)
|
||||||
|
|
||||||
data.append(row)
|
data.append(row)
|
||||||
|
|
||||||
return columns, data
|
if filters.get('group_by'):
|
||||||
|
total_row = total_row_map.get(prev_group_by_value or d.get('item_name'))
|
||||||
|
total_row['percent_gt'] = flt(total_row['total']/grand_total * 100)
|
||||||
|
data.append(total_row)
|
||||||
|
data.append({})
|
||||||
|
add_sub_total_row(total_row, total_row_map, 'total_row', tax_columns)
|
||||||
|
data.append(total_row_map.get('total_row'))
|
||||||
|
skip_total_row = 1
|
||||||
|
|
||||||
def get_columns(additional_table_columns):
|
return columns, data, None, None, None, skip_total_row
|
||||||
columns = [
|
|
||||||
_("Item Code") + ":Link/Item:120", _("Item Name") + "::120",
|
def get_columns(additional_table_columns, filters):
|
||||||
_("Item Group") + ":Link/Item Group:100", "Description::150", _("Invoice") + ":Link/Sales Invoice:120",
|
columns = []
|
||||||
_("Posting Date") + ":Date:80", _("Customer") + ":Link/Customer:120",
|
|
||||||
_("Customer Name") + "::120"]
|
if filters.get('group_by') != ('Item'):
|
||||||
|
columns.extend(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
'label': _('Item Code'),
|
||||||
|
'fieldname': 'item_code',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Item',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Item Name'),
|
||||||
|
'fieldname': 'item_name',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 120
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
if filters.get('group_by') not in ('Item', 'Item Group'):
|
||||||
|
columns.extend([
|
||||||
|
{
|
||||||
|
'label': _('Item Group'),
|
||||||
|
'fieldname': 'item_group',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Item Group',
|
||||||
|
'width': 120
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
columns.extend([
|
||||||
|
{
|
||||||
|
'label': _('Description'),
|
||||||
|
'fieldname': 'description',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Invoice'),
|
||||||
|
'fieldname': 'invoice',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Sales Invoice',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Posting Date'),
|
||||||
|
'fieldname': 'posting_date',
|
||||||
|
'fieldtype': 'Date',
|
||||||
|
'width': 120
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
if filters.get('group_by') != 'Customer':
|
||||||
|
columns.extend([
|
||||||
|
{
|
||||||
|
'label': _('Customer Group'),
|
||||||
|
'fieldname': 'customer_group',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Customer Group',
|
||||||
|
'width': 120
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
if filters.get('group_by') not in ('Customer', 'Customer Group'):
|
||||||
|
columns.extend([
|
||||||
|
{
|
||||||
|
'label': _('Customer'),
|
||||||
|
'fieldname': 'customer',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Customer',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Customer Name'),
|
||||||
|
'fieldname': 'customer_name',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 120
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
if additional_table_columns:
|
if additional_table_columns:
|
||||||
columns += additional_table_columns
|
columns += additional_table_columns
|
||||||
|
|
||||||
columns += [
|
columns += [
|
||||||
_("Customer Group") + ":Link/Customer Group:120",
|
{
|
||||||
_("Receivable Account") + ":Link/Account:120",
|
'label': _('Receivable Account'),
|
||||||
_("Mode of Payment") + "::120", _("Territory") + ":Link/Territory:80",
|
'fieldname': 'debit_to',
|
||||||
_("Project") + ":Link/Project:80", _("Company") + ":Link/Company:100",
|
'fieldtype': 'Link',
|
||||||
_("Sales Order") + ":Link/Sales Order:100", _("Delivery Note") + ":Link/Delivery Note:100",
|
'options': 'Account',
|
||||||
_("Income Account") + ":Link/Account:140", _("Cost Center") + ":Link/Cost Center:140",
|
'width': 80
|
||||||
_("Stock Qty") + ":Float:120", _("Stock UOM") + "::100",
|
},
|
||||||
_("Rate") + ":Currency/currency:120",
|
{
|
||||||
_("Amount") + ":Currency/currency:120"
|
'label': _('Mode Of Payment'),
|
||||||
|
'fieldname': 'mode_of_payment',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 120
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if filters.get('group_by') != 'Terriotory':
|
||||||
|
columns.extend([
|
||||||
|
{
|
||||||
|
'label': _("Territory"),
|
||||||
|
'fieldname': 'territory',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Territory',
|
||||||
|
'width': 80
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
columns += [
|
||||||
|
{
|
||||||
|
'label': _('Project'),
|
||||||
|
'fieldname': 'project',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Project',
|
||||||
|
'width': 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Company'),
|
||||||
|
'fieldname': 'company',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Company',
|
||||||
|
'width': 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Sales Order'),
|
||||||
|
'fieldname': 'sales_order',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Sales Order',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Delivery Note"),
|
||||||
|
'fieldname': 'delivery_note',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Delivery Note',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Income Account'),
|
||||||
|
'fieldname': 'income_account',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Account',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Cost Center"),
|
||||||
|
'fieldname': 'cost_center',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Cost Center',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Stock Qty'),
|
||||||
|
'fieldname': 'stock_qty',
|
||||||
|
'fieldtype': 'Float',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Stock UOM'),
|
||||||
|
'fieldname': 'stock_uom',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'UOM',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Rate'),
|
||||||
|
'fieldname': 'rate',
|
||||||
|
'fieldtype': 'Float',
|
||||||
|
'options': 'currency',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Amount'),
|
||||||
|
'fieldname': 'amount',
|
||||||
|
'fieldtype': 'Currency',
|
||||||
|
'options': 'currency',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'currency',
|
||||||
|
'label': _('Currency'),
|
||||||
|
'fieldtype': 'Currency',
|
||||||
|
'width': 80,
|
||||||
|
'hidden': 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
if filters.get('group_by'):
|
||||||
|
columns.append({
|
||||||
|
'label': _('% Of Grand Total'),
|
||||||
|
'fieldname': 'percent_gt',
|
||||||
|
'fieldtype': 'Float',
|
||||||
|
'width': 80
|
||||||
|
})
|
||||||
|
|
||||||
return columns
|
return columns
|
||||||
|
|
||||||
def get_conditions(filters):
|
def get_conditions(filters):
|
||||||
@ -112,24 +342,32 @@ def get_conditions(filters):
|
|||||||
and ifnull(`tabSales Invoice Payment`.mode_of_payment, '') = %(mode_of_payment)s)"""
|
and ifnull(`tabSales Invoice Payment`.mode_of_payment, '') = %(mode_of_payment)s)"""
|
||||||
|
|
||||||
if filters.get("warehouse"):
|
if filters.get("warehouse"):
|
||||||
conditions += """ and exists(select name from `tabSales Invoice Item`
|
conditions += """and ifnull(`tabSales Invoice Item`.warehouse, '') = %(warehouse)s"""
|
||||||
where parent=`tabSales Invoice`.name
|
|
||||||
and ifnull(`tabSales Invoice Item`.warehouse, '') = %(warehouse)s)"""
|
|
||||||
|
|
||||||
|
|
||||||
if filters.get("brand"):
|
if filters.get("brand"):
|
||||||
conditions += """ and exists(select name from `tabSales Invoice Item`
|
conditions += """and ifnull(`tabSales Invoice Item`.brand, '') = %(brand)s"""
|
||||||
where parent=`tabSales Invoice`.name
|
|
||||||
and ifnull(`tabSales Invoice Item`.brand, '') = %(brand)s)"""
|
|
||||||
|
|
||||||
if filters.get("item_group"):
|
if filters.get("item_group"):
|
||||||
conditions += """ and exists(select name from `tabSales Invoice Item`
|
conditions += """and ifnull(`tabSales Invoice Item`.item_group, '') = %(item_group)s"""
|
||||||
where parent=`tabSales Invoice`.name
|
|
||||||
and ifnull(`tabSales Invoice Item`.item_group, '') = %(item_group)s)"""
|
|
||||||
|
|
||||||
|
if not filters.get("group_by"):
|
||||||
|
conditions += "ORDER BY `tabSales Invoice`.posting_date desc, `tabSales Invoice Item`.item_group desc"
|
||||||
|
else:
|
||||||
|
conditions += get_group_by_conditions(filters, 'Sales Invoice')
|
||||||
|
|
||||||
return conditions
|
return conditions
|
||||||
|
|
||||||
|
def get_group_by_conditions(filters, doctype):
|
||||||
|
if filters.get("group_by") == 'Invoice':
|
||||||
|
return "ORDER BY `tab{0} Item`.parent desc".format(doctype)
|
||||||
|
elif filters.get("group_by") == 'Item':
|
||||||
|
return "ORDER BY `tab{0} Item`.`item_code`".format(doctype)
|
||||||
|
elif filters.get("group_by") == 'Item Group':
|
||||||
|
return "ORDER BY `tab{0} Item`.{1}".format(doctype, frappe.scrub(filters.get('group_by')))
|
||||||
|
elif filters.get("group_by") in ('Customer', 'Customer Group', 'Territory', 'Supplier'):
|
||||||
|
return "ORDER BY `tab{0}`.{1}".format(doctype, frappe.scrub(filters.get('group_by')))
|
||||||
|
|
||||||
def get_items(filters, additional_query_columns):
|
def get_items(filters, additional_query_columns):
|
||||||
conditions = get_conditions(filters)
|
conditions = get_conditions(filters)
|
||||||
match_conditions = frappe.build_match_conditions("Sales Invoice")
|
match_conditions = frappe.build_match_conditions("Sales Invoice")
|
||||||
@ -156,9 +394,8 @@ def get_items(filters, additional_query_columns):
|
|||||||
`tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty {0}
|
`tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty {0}
|
||||||
from `tabSales Invoice`, `tabSales Invoice Item`
|
from `tabSales Invoice`, `tabSales Invoice Item`
|
||||||
where `tabSales Invoice`.name = `tabSales Invoice Item`.parent
|
where `tabSales Invoice`.name = `tabSales Invoice Item`.parent
|
||||||
and `tabSales Invoice`.docstatus = 1 %s %s
|
and `tabSales Invoice`.docstatus = 1 {1} {2}
|
||||||
order by `tabSales Invoice`.posting_date desc, `tabSales Invoice Item`.item_code desc
|
""".format(additional_query_columns or '', conditions, match_conditions), filters, as_dict=1) #nosec
|
||||||
""".format(additional_query_columns or '') % (conditions, match_conditions), filters, as_dict=1)
|
|
||||||
|
|
||||||
def get_delivery_notes_against_sales_order(item_list):
|
def get_delivery_notes_against_sales_order(item_list):
|
||||||
so_dn_map = frappe._dict()
|
so_dn_map = frappe._dict()
|
||||||
@ -177,6 +414,15 @@ def get_delivery_notes_against_sales_order(item_list):
|
|||||||
|
|
||||||
return so_dn_map
|
return so_dn_map
|
||||||
|
|
||||||
|
def get_grand_total(filters, doctype):
|
||||||
|
|
||||||
|
return frappe.db.sql(""" SELECT
|
||||||
|
SUM(`tab{0}`.base_grand_total)
|
||||||
|
FROM `tab{0}`
|
||||||
|
WHERE `tab{0}`.docstatus = 1
|
||||||
|
and posting_date between %s and %s
|
||||||
|
""".format(doctype), (filters.get('from_date'), filters.get('to_date')))[0][0] #nosec
|
||||||
|
|
||||||
def get_deducted_taxes():
|
def get_deducted_taxes():
|
||||||
return frappe.db.sql_list("select name from `tabPurchase Taxes and Charges` where add_deduct_tax = 'Deduct'")
|
return frappe.db.sql_list("select name from `tabPurchase Taxes and Charges` where add_deduct_tax = 'Deduct'")
|
||||||
|
|
||||||
@ -264,9 +510,117 @@ def get_tax_accounts(item_list, columns, company_currency,
|
|||||||
|
|
||||||
tax_columns.sort()
|
tax_columns.sort()
|
||||||
for desc in tax_columns:
|
for desc in tax_columns:
|
||||||
columns.append(desc + " Rate:Data:80")
|
columns.append({
|
||||||
columns.append(desc + " Amount:Currency/currency:100")
|
'label': _(desc + ' Rate'),
|
||||||
|
'fieldname': frappe.scrub(desc + ' Rate'),
|
||||||
|
'fieldtype': 'Float',
|
||||||
|
'width': 100
|
||||||
|
})
|
||||||
|
|
||||||
columns += ["Total Tax:Currency/currency:80", "Total:Currency/currency:100"]
|
columns.append({
|
||||||
|
'label': _(desc + ' Amount'),
|
||||||
|
'fieldname': frappe.scrub(desc + ' Amount'),
|
||||||
|
'fieldtype': 'Currency',
|
||||||
|
'options': 'currency',
|
||||||
|
'width': 100
|
||||||
|
})
|
||||||
|
|
||||||
|
columns += [
|
||||||
|
{
|
||||||
|
'label': _('Total Tax'),
|
||||||
|
'fieldname': 'total_tax',
|
||||||
|
'fieldtype': 'Currency',
|
||||||
|
'options': 'currency',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _('Total'),
|
||||||
|
'fieldname': 'total',
|
||||||
|
'fieldtype': 'Currency',
|
||||||
|
'options': 'currency',
|
||||||
|
'width': 100
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
return itemised_tax, tax_columns
|
return itemised_tax, tax_columns
|
||||||
|
|
||||||
|
def add_total_row(data, filters, prev_group_by_value, item, total_row_map,
|
||||||
|
group_by_field, subtotal_display_field, grand_total, tax_columns):
|
||||||
|
if prev_group_by_value != item.get(group_by_field, ''):
|
||||||
|
if prev_group_by_value:
|
||||||
|
total_row = total_row_map.get(prev_group_by_value)
|
||||||
|
data.append(total_row)
|
||||||
|
data.append({})
|
||||||
|
add_sub_total_row(total_row, total_row_map, 'total_row', tax_columns)
|
||||||
|
|
||||||
|
prev_group_by_value = item.get(group_by_field, '')
|
||||||
|
|
||||||
|
total_row_map.setdefault(item.get(group_by_field, ''), {
|
||||||
|
subtotal_display_field: get_display_value(filters, group_by_field, item),
|
||||||
|
'stock_qty': 0.0,
|
||||||
|
'amount': 0.0,
|
||||||
|
'bold': 1,
|
||||||
|
'total_tax': 0.0,
|
||||||
|
'total': 0.0,
|
||||||
|
'percent_gt': 0.0
|
||||||
|
})
|
||||||
|
|
||||||
|
total_row_map.setdefault('total_row', {
|
||||||
|
subtotal_display_field: "Total",
|
||||||
|
'stock_qty': 0.0,
|
||||||
|
'amount': 0.0,
|
||||||
|
'bold': 1,
|
||||||
|
'total_tax': 0.0,
|
||||||
|
'total': 0.0,
|
||||||
|
'percent_gt': 0.0
|
||||||
|
})
|
||||||
|
|
||||||
|
return data, prev_group_by_value
|
||||||
|
|
||||||
|
def get_display_value(filters, group_by_field, item):
|
||||||
|
if filters.get('group_by') == 'Item':
|
||||||
|
if item.get('item_code') != item.get('item_name'):
|
||||||
|
value = cstr(item.get('item_code')) + "<br><br>" + \
|
||||||
|
"<span style='font-weight: normal'>" + cstr(item.get('item_name')) + "</span>"
|
||||||
|
else:
|
||||||
|
value = item.get('item_code', '')
|
||||||
|
elif filters.get('group_by') in ('Customer', 'Supplier'):
|
||||||
|
party = frappe.scrub(filters.get('group_by'))
|
||||||
|
if item.get(party) != item.get(party+'_name'):
|
||||||
|
value = item.get(party) + "<br><br>" + \
|
||||||
|
"<span style='font-weight: normal'>" + item.get(party+'_name') + "</span>"
|
||||||
|
else:
|
||||||
|
value = item.get(party)
|
||||||
|
else:
|
||||||
|
value = item.get(group_by_field)
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
def get_group_by_and_display_fields(filters):
|
||||||
|
if filters.get('group_by') == 'Item':
|
||||||
|
group_by_field = 'item_code'
|
||||||
|
subtotal_display_field = 'invoice'
|
||||||
|
elif filters.get('group_by') == 'Invoice':
|
||||||
|
group_by_field = 'parent'
|
||||||
|
subtotal_display_field = 'item_code'
|
||||||
|
else:
|
||||||
|
group_by_field = frappe.scrub(filters.get('group_by'))
|
||||||
|
subtotal_display_field = 'item_code'
|
||||||
|
|
||||||
|
return group_by_field, subtotal_display_field
|
||||||
|
|
||||||
|
def add_sub_total_row(item, total_row_map, group_by_value, tax_columns):
|
||||||
|
total_row = total_row_map.get(group_by_value)
|
||||||
|
total_row['stock_qty'] += item['stock_qty']
|
||||||
|
total_row['amount'] += item['amount']
|
||||||
|
total_row['total_tax'] += item['total_tax']
|
||||||
|
total_row['total'] += item['total']
|
||||||
|
total_row['percent_gt'] += item['percent_gt']
|
||||||
|
|
||||||
|
for tax in tax_columns:
|
||||||
|
total_row.setdefault(frappe.scrub(tax + ' Amount'), 0.0)
|
||||||
|
total_row[frappe.scrub(tax + ' Amount')] += flt(item[frappe.scrub(tax + ' Amount')])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ def get_columns(invoice_list, additional_table_columns):
|
|||||||
|
|
||||||
columns +=[
|
columns +=[
|
||||||
{
|
{
|
||||||
'label': _("Custmer Group"),
|
'label': _("Customer Group"),
|
||||||
'fieldname': 'customer_group',
|
'fieldname': 'customer_group',
|
||||||
'fieldtype': 'Link',
|
'fieldtype': 'Link',
|
||||||
'options': 'Customer Group',
|
'options': 'Customer Group',
|
||||||
@ -175,7 +175,7 @@ def get_columns(invoice_list, additional_table_columns):
|
|||||||
'label': _("Project"),
|
'label': _("Project"),
|
||||||
'fieldname': 'project',
|
'fieldname': 'project',
|
||||||
'fieldtype': 'Link',
|
'fieldtype': 'Link',
|
||||||
'options': 'project',
|
'options': 'Project',
|
||||||
'width': 80
|
'width': 80
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -513,7 +513,7 @@ def remove_ref_doc_link_from_jv(ref_type, ref_no):
|
|||||||
where reference_type=%s and reference_name=%s
|
where reference_type=%s and reference_name=%s
|
||||||
and docstatus < 2""", (now(), frappe.session.user, ref_type, ref_no))
|
and docstatus < 2""", (now(), frappe.session.user, ref_type, ref_no))
|
||||||
|
|
||||||
frappe.msgprint(_("Journal Entries {0} are un-linked".format("\n".join(linked_jv))))
|
frappe.msgprint(_("Journal Entries {0} are un-linked").format("\n".join(linked_jv)))
|
||||||
|
|
||||||
def remove_ref_doc_link_from_pe(ref_type, ref_no):
|
def remove_ref_doc_link_from_pe(ref_type, ref_no):
|
||||||
linked_pe = frappe.db.sql_list("""select parent from `tabPayment Entry Reference`
|
linked_pe = frappe.db.sql_list("""select parent from `tabPayment Entry Reference`
|
||||||
@ -536,7 +536,7 @@ def remove_ref_doc_link_from_pe(ref_type, ref_no):
|
|||||||
where name=%s""", (pe_doc.total_allocated_amount, pe_doc.base_total_allocated_amount,
|
where name=%s""", (pe_doc.total_allocated_amount, pe_doc.base_total_allocated_amount,
|
||||||
pe_doc.unallocated_amount, now(), frappe.session.user, pe))
|
pe_doc.unallocated_amount, now(), frappe.session.user, pe))
|
||||||
|
|
||||||
frappe.msgprint(_("Payment Entries {0} are un-linked".format("\n".join(linked_pe))))
|
frappe.msgprint(_("Payment Entries {0} are un-linked").format("\n".join(linked_pe)))
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_company_default(company, fieldname):
|
def get_company_default(company, fieldname):
|
||||||
|
@ -44,7 +44,7 @@ class CropCycle(Document):
|
|||||||
self.import_disease_tasks(disease.disease, disease.start_date)
|
self.import_disease_tasks(disease.disease, disease.start_date)
|
||||||
disease.tasks_created = True
|
disease.tasks_created = True
|
||||||
|
|
||||||
frappe.msgprint(_("Tasks have been created for managing the {0} disease (on row {1})".format(disease.disease, disease.idx)))
|
frappe.msgprint(_("Tasks have been created for managing the {0} disease (on row {1})").format(disease.disease, disease.idx))
|
||||||
|
|
||||||
def import_disease_tasks(self, disease, start_date):
|
def import_disease_tasks(self, disease, start_date):
|
||||||
disease_doc = frappe.get_doc('Disease', disease)
|
disease_doc = frappe.get_doc('Disease', disease)
|
||||||
|
@ -589,7 +589,7 @@ def transfer_asset(args):
|
|||||||
|
|
||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
|
|
||||||
frappe.msgprint(_("Asset Movement record {0} created").format("<a href='#Form/Asset Movement/{0}'>{0}</a>".format(movement_entry.name)))
|
frappe.msgprint(_("Asset Movement record {0} created").format("<a href='#Form/Asset Movement/{0}'>{0}</a>").format(movement_entry.name))
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_item_details(item_code, asset_category):
|
def get_item_details(item_code, asset_category):
|
||||||
|
@ -10,7 +10,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import g
|
|||||||
|
|
||||||
def post_depreciation_entries(date=None):
|
def post_depreciation_entries(date=None):
|
||||||
# Return if automatic booking of asset depreciation is disabled
|
# Return if automatic booking of asset depreciation is disabled
|
||||||
if not cint(frappe.db.get_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically")):
|
if not cint(frappe.db.get_single_value("Accounts Settings", "book_asset_depreciation_entry_automatically")):
|
||||||
return
|
return
|
||||||
|
|
||||||
if not date:
|
if not date:
|
||||||
|
@ -1,580 +1,146 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 1,
|
"allow_rename": 1,
|
||||||
"autoname": "field:location_name",
|
"autoname": "field:location_name",
|
||||||
"beta": 0,
|
|
||||||
"creation": "2018-05-07 12:49:22.595974",
|
"creation": "2018-05-07 12:49:22.595974",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"location_name",
|
||||||
|
"parent_location",
|
||||||
|
"cb_details",
|
||||||
|
"is_container",
|
||||||
|
"is_group",
|
||||||
|
"sb_location_details",
|
||||||
|
"latitude",
|
||||||
|
"longitude",
|
||||||
|
"cb_latlong",
|
||||||
|
"area",
|
||||||
|
"area_uom",
|
||||||
|
"sb_geolocation",
|
||||||
|
"location",
|
||||||
|
"tree_details",
|
||||||
|
"lft",
|
||||||
|
"rgt",
|
||||||
|
"old_parent"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "location_name",
|
"fieldname": "location_name",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Location Name",
|
"label": "Location Name",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"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,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 1
|
"unique": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "parent_location",
|
"fieldname": "parent_location",
|
||||||
"fieldtype": "Link",
|
"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": "Parent Location",
|
"label": "Parent Location",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Location",
|
"options": "Location",
|
||||||
"permlevel": 0,
|
"search_index": 1
|
||||||
"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": 1,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "cb_details",
|
"fieldname": "cb_details",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"default": "0",
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"description": "Check if it is a hydroponic unit",
|
"description": "Check if it is a hydroponic unit",
|
||||||
"fieldname": "is_container",
|
"fieldname": "is_container",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"label": "Is Container"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Is Container",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 1,
|
"bold": 1,
|
||||||
"collapsible": 0,
|
"default": "0",
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "is_group",
|
"fieldname": "is_group",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
"label": "Is Group"
|
||||||
"label": "Is Group",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "sb_location_details",
|
"fieldname": "sb_location_details",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"label": "Location Details"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Location Details",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "parent_location.latitude",
|
"fetch_from": "parent_location.latitude",
|
||||||
"fieldname": "latitude",
|
"fieldname": "latitude",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"hidden": 0,
|
"label": "Latitude"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Latitude",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "parent_location.longitude",
|
"fetch_from": "parent_location.longitude",
|
||||||
"fieldname": "longitude",
|
"fieldname": "longitude",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"hidden": 0,
|
"label": "Longitude"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Longitude",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "cb_latlong",
|
"fieldname": "cb_latlong",
|
||||||
"fieldtype": "Column Break",
|
"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,
|
|
||||||
"label": "",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "area",
|
"fieldname": "area",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Area",
|
"label": "Area",
|
||||||
"length": 0,
|
"read_only": 1
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"depends_on": "eval:doc.area",
|
"depends_on": "eval:doc.area",
|
||||||
"fieldname": "area_uom",
|
"fieldname": "area_uom",
|
||||||
"fieldtype": "Link",
|
"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": "Area UOM",
|
"label": "Area UOM",
|
||||||
"length": 0,
|
"options": "UOM"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "UOM",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "sb_geolocation",
|
"fieldname": "sb_geolocation",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "location",
|
"fieldname": "location",
|
||||||
"fieldtype": "Geolocation",
|
"fieldtype": "Geolocation",
|
||||||
"hidden": 0,
|
"label": "Location"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Location",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "tree_details",
|
"fieldname": "tree_details",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"ignore_user_permissions": 0,
|
"label": "Tree Details"
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Tree Details",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "lft",
|
"fieldname": "lft",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "lft",
|
"label": "lft",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_hide_if_no_value": 0,
|
"read_only": 1
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "rgt",
|
"fieldname": "rgt",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "rgt",
|
"label": "rgt",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_hide_if_no_value": 0,
|
"read_only": 1
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "old_parent",
|
"fieldname": "old_parent",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Old Parent",
|
"label": "Old Parent",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_hide_if_no_value": 0,
|
"read_only": 1
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"links": [],
|
||||||
"hide_heading": 0,
|
"modified": "2020-01-28 13:52:22.513425",
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 0,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2018-07-11 13:36:30.999405",
|
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Assets",
|
"module": "Assets",
|
||||||
"name": "Location",
|
"name": "Location",
|
||||||
@ -582,127 +148,78 @@
|
|||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "System Manager",
|
"role": "System Manager",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Stock User",
|
"role": "Stock User",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Accounts User",
|
"role": "Accounts User",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Stock Manager",
|
"role": "Stock Manager",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Agriculture Manager",
|
"role": "Agriculture Manager",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 0,
|
|
||||||
"delete": 0,
|
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Agriculture User",
|
"role": "Agriculture User",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 1,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 1,
|
"show_name_in_global_search": 1,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"track_changes": 1,
|
"track_changes": 1
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
@ -180,10 +180,20 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
|||||||
get_items_from_open_material_requests: function() {
|
get_items_from_open_material_requests: function() {
|
||||||
erpnext.utils.map_current_doc({
|
erpnext.utils.map_current_doc({
|
||||||
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order_based_on_supplier",
|
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order_based_on_supplier",
|
||||||
|
args: {
|
||||||
|
supplier: this.frm.doc.supplier
|
||||||
|
},
|
||||||
|
source_doctype: "Material Request",
|
||||||
source_name: this.frm.doc.supplier,
|
source_name: this.frm.doc.supplier,
|
||||||
|
target: this.frm,
|
||||||
|
setters: {
|
||||||
|
company: me.frm.doc.company
|
||||||
|
},
|
||||||
get_query_filters: {
|
get_query_filters: {
|
||||||
docstatus: ["!=", 2],
|
docstatus: ["!=", 2],
|
||||||
}
|
supplier: this.frm.doc.supplier
|
||||||
|
},
|
||||||
|
get_query_method: "erpnext.stock.doctype.material_request.material_request.get_material_requests_based_on_supplier"
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
"supplier",
|
"supplier",
|
||||||
"get_items_from_open_material_requests",
|
"get_items_from_open_material_requests",
|
||||||
"supplier_name",
|
"supplier_name",
|
||||||
"company",
|
|
||||||
"column_break1",
|
"column_break1",
|
||||||
|
"company",
|
||||||
"transaction_date",
|
"transaction_date",
|
||||||
"schedule_date",
|
"schedule_date",
|
||||||
"order_confirmation_no",
|
"order_confirmation_no",
|
||||||
@ -170,6 +170,7 @@
|
|||||||
"search_index": 1
|
"search_index": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"description": "Fetch items based on Default Supplier.",
|
||||||
"depends_on": "eval:doc.supplier && doc.docstatus===0 && (!(doc.items && doc.items.length) || (doc.items.length==1 && !doc.items[0].item_code))",
|
"depends_on": "eval:doc.supplier && doc.docstatus===0 && (!(doc.items && doc.items.length) || (doc.items.length==1 && !doc.items[0].item_code))",
|
||||||
"fieldname": "get_items_from_open_material_requests",
|
"fieldname": "get_items_from_open_material_requests",
|
||||||
"fieldtype": "Button",
|
"fieldtype": "Button",
|
||||||
|
@ -9,7 +9,7 @@ cur_frm.add_fetch('contact', 'email_id', 'email_id')
|
|||||||
frappe.ui.form.on("Request for Quotation",{
|
frappe.ui.form.on("Request for Quotation",{
|
||||||
setup: function(frm) {
|
setup: function(frm) {
|
||||||
frm.custom_make_buttons = {
|
frm.custom_make_buttons = {
|
||||||
'Supplier Quotation': 'Supplier Quotation'
|
'Supplier Quotation': 'Create'
|
||||||
}
|
}
|
||||||
|
|
||||||
frm.fields_dict["suppliers"].grid.get_field("contact").get_query = function(doc, cdt, cdn) {
|
frm.fields_dict["suppliers"].grid.get_field("contact").get_query = function(doc, cdt, cdn) {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -58,7 +58,9 @@ class Supplier(TransactionBase):
|
|||||||
frappe.db.set(self, "supplier_name", newdn)
|
frappe.db.set(self, "supplier_name", newdn)
|
||||||
|
|
||||||
def create_onboarding_docs(self, args):
|
def create_onboarding_docs(self, args):
|
||||||
defaults = frappe.defaults.get_defaults()
|
company = frappe.defaults.get_defaults().get('company') or \
|
||||||
|
frappe.db.get_single_value('Global Defaults', 'default_company')
|
||||||
|
|
||||||
for i in range(1, args.get('max_count')):
|
for i in range(1, args.get('max_count')):
|
||||||
supplier = args.get('supplier_name_' + str(i))
|
supplier = args.get('supplier_name_' + str(i))
|
||||||
if supplier:
|
if supplier:
|
||||||
@ -67,7 +69,7 @@ class Supplier(TransactionBase):
|
|||||||
'doctype': self.doctype,
|
'doctype': self.doctype,
|
||||||
'supplier_name': supplier,
|
'supplier_name': supplier,
|
||||||
'supplier_group': _('Local'),
|
'supplier_group': _('Local'),
|
||||||
'company': defaults.get('company')
|
'company': company
|
||||||
}).insert()
|
}).insert()
|
||||||
|
|
||||||
if args.get('supplier_email_' + str(i)):
|
if args.get('supplier_email_' + str(i)):
|
||||||
|
@ -9,7 +9,8 @@ def get_data():
|
|||||||
'heatmap_message': _('This is based on transactions against this Supplier. See timeline below for details'),
|
'heatmap_message': _('This is based on transactions against this Supplier. See timeline below for details'),
|
||||||
'fieldname': 'supplier',
|
'fieldname': 'supplier',
|
||||||
'non_standard_fieldnames': {
|
'non_standard_fieldnames': {
|
||||||
'Payment Entry': 'party_name'
|
'Payment Entry': 'party_name',
|
||||||
|
'Bank Account': 'party'
|
||||||
},
|
},
|
||||||
'transactions': [
|
'transactions': [
|
||||||
{
|
{
|
||||||
@ -24,6 +25,10 @@ def get_data():
|
|||||||
'label': _('Payments'),
|
'label': _('Payments'),
|
||||||
'items': ['Payment Entry']
|
'items': ['Payment Entry']
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'label': _('Bank'),
|
||||||
|
'items': ['Bank Account']
|
||||||
|
},
|
||||||
{
|
{
|
||||||
'label': _('Pricing'),
|
'label': _('Pricing'),
|
||||||
'items': ['Pricing Rule']
|
'items': ['Pricing Rule']
|
||||||
|
@ -43,7 +43,7 @@ class SupplierScorecardPeriod(Document):
|
|||||||
try:
|
try:
|
||||||
crit.score = min(crit.max_score, max( 0 ,frappe.safe_eval(self.get_eval_statement(crit.formula), None, {'max':max, 'min': min})))
|
crit.score = min(crit.max_score, max( 0 ,frappe.safe_eval(self.get_eval_statement(crit.formula), None, {'max':max, 'min': min})))
|
||||||
except Exception:
|
except Exception:
|
||||||
frappe.throw(_("Could not solve criteria score function for {0}. Make sure the formula is valid.".format(crit.criteria_name)),frappe.ValidationError)
|
frappe.throw(_("Could not solve criteria score function for {0}. Make sure the formula is valid.").format(crit.criteria_name),frappe.ValidationError)
|
||||||
crit.score = 0
|
crit.score = 0
|
||||||
|
|
||||||
def calculate_score(self):
|
def calculate_score(self):
|
||||||
|
@ -141,13 +141,13 @@ def get_conditions(filters):
|
|||||||
conditions = ""
|
conditions = ""
|
||||||
|
|
||||||
if filters.get("company"):
|
if filters.get("company"):
|
||||||
conditions += " AND company='%s'"% filters.get('company')
|
conditions += " AND company=%s"% frappe.db.escape(filters.get('company'))
|
||||||
|
|
||||||
if filters.get("cost_center") or filters.get("project"):
|
if filters.get("cost_center") or filters.get("project"):
|
||||||
conditions += """
|
conditions += """
|
||||||
AND (cost_center='%s'
|
AND (cost_center=%s
|
||||||
OR project='%s')
|
OR project=%s)
|
||||||
"""% (filters.get('cost_center'), filters.get('project'))
|
"""% (frappe.db.escape(filters.get('cost_center')), frappe.db.escape(filters.get('project')))
|
||||||
|
|
||||||
if filters.get("from_date"):
|
if filters.get("from_date"):
|
||||||
conditions += " AND transaction_date>=%s"% filters.get('from_date')
|
conditions += " AND transaction_date>=%s"% filters.get('from_date')
|
||||||
|
@ -117,6 +117,13 @@ def get_data():
|
|||||||
"name": "Lead Owner Efficiency",
|
"name": "Lead Owner Efficiency",
|
||||||
"doctype": "Lead",
|
"doctype": "Lead",
|
||||||
"dependencies": ["Lead"]
|
"dependencies": ["Lead"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "report",
|
||||||
|
"is_query_report": True,
|
||||||
|
"name": "Territory-wise Sales",
|
||||||
|
"doctype": "Opportunity",
|
||||||
|
"dependencies": ["Opportunity"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -80,6 +80,15 @@ def get_data():
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Sales pipeline, leads, opportunities and customers."
|
"description": "Sales pipeline, leads, opportunities and customers."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"module_name": "Loan Management",
|
||||||
|
"category": "Modules",
|
||||||
|
"label": _("Loan Management"),
|
||||||
|
"color": "#EF4DB6",
|
||||||
|
"icon": "octicon octicon-repo",
|
||||||
|
"type": "module",
|
||||||
|
"description": "Loan Management for Customer and Employees"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"module_name": "Support",
|
"module_name": "Support",
|
||||||
"category": "Modules",
|
"category": "Modules",
|
||||||
|
@ -289,6 +289,10 @@ def get_data():
|
|||||||
"name": "Job Offer",
|
"name": "Job Offer",
|
||||||
"onboard": 1,
|
"onboard": 1,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Appointment Letter",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "doctype",
|
"type": "doctype",
|
||||||
"name": "Staffing Plan",
|
"name": "Staffing Plan",
|
||||||
|
107
erpnext/config/loan_management.py
Normal file
107
erpnext/config/loan_management.py
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
from frappe import _
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
|
||||||
|
def get_data():
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"label": _("Loan"),
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Loan Type",
|
||||||
|
"description": _("Loan Type for interest and penalty rates"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Loan Application",
|
||||||
|
"description": _("Loan Applications from customers and employees."),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Loan",
|
||||||
|
"description": _("Loans provided to customers and employees."),
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Loan Security"),
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Loan Security Type",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Loan Security Price",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Loan Security",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Loan Security Pledge",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Loan Security Unpledge",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Loan Security Shortfall",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Disbursement and Repayment"),
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Loan Disbursement",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Loan Repayment",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Loan Interest Accrual"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Loan Processes"),
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Process Loan Security Shortfall",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Process Loan Interest Accrual",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Reports"),
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "report",
|
||||||
|
"is_query_report": True,
|
||||||
|
"name": "Loan Repayment and Closure",
|
||||||
|
"route": "#query-report/Loan Repayment and Closure",
|
||||||
|
"doctype": "Loan Repayment",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "report",
|
||||||
|
"is_query_report": True,
|
||||||
|
"name": "Loan Security Status",
|
||||||
|
"route": "#query-report/Loan Security Status",
|
||||||
|
"doctype": "Loan Security Pledge",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
@ -58,7 +58,7 @@ class AccountsController(TransactionBase):
|
|||||||
(is_supplier_payment and supplier.hold_type in ['All', 'Payments']):
|
(is_supplier_payment and supplier.hold_type in ['All', 'Payments']):
|
||||||
if not supplier.release_date or getdate(nowdate()) <= supplier.release_date:
|
if not supplier.release_date or getdate(nowdate()) <= supplier.release_date:
|
||||||
frappe.msgprint(
|
frappe.msgprint(
|
||||||
_('{0} is blocked so this transaction cannot proceed'.format(supplier_name)), raise_exception=1)
|
_('{0} is blocked so this transaction cannot proceed').format(supplier_name), raise_exception=1)
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
if not self.get('is_return'):
|
if not self.get('is_return'):
|
||||||
@ -926,7 +926,7 @@ def validate_taxes_and_charges(tax):
|
|||||||
frappe.throw(
|
frappe.throw(
|
||||||
_("Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row"))
|
_("Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row"))
|
||||||
elif not tax.row_id:
|
elif not tax.row_id:
|
||||||
frappe.throw(_("Please specify a valid Row ID for row {0} in table {1}".format(tax.idx, _(tax.doctype))))
|
frappe.throw(_("Please specify a valid Row ID for row {0} in table {1}").format(tax.idx, _(tax.doctype)))
|
||||||
elif tax.row_id and cint(tax.row_id) >= cint(tax.idx):
|
elif tax.row_id and cint(tax.row_id) >= cint(tax.idx):
|
||||||
frappe.throw(_("Cannot refer row number greater than or equal to current row number for this Charge type"))
|
frappe.throw(_("Cannot refer row number greater than or equal to current row number for this Charge type"))
|
||||||
|
|
||||||
@ -1135,6 +1135,7 @@ def set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname,
|
|||||||
child_item.reqd_by_date = p_doctype.delivery_date
|
child_item.reqd_by_date = p_doctype.delivery_date
|
||||||
child_item.uom = item.stock_uom
|
child_item.uom = item.stock_uom
|
||||||
child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0
|
child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0
|
||||||
|
child_item.warehouse = p_doctype.set_warehouse or p_doctype.items[0].warehouse
|
||||||
return child_item
|
return child_item
|
||||||
|
|
||||||
|
|
||||||
@ -1199,6 +1200,8 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
|
|||||||
child_item = set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, d.get("item_code"))
|
child_item = set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, d.get("item_code"))
|
||||||
else:
|
else:
|
||||||
child_item = frappe.get_doc(parent_doctype + ' Item', d.get("docname"))
|
child_item = frappe.get_doc(parent_doctype + ' Item', d.get("docname"))
|
||||||
|
if flt(child_item.get("rate")) == flt(d.get("rate")) and flt(child_item.get("qty")) == flt(d.get("qty")):
|
||||||
|
continue
|
||||||
|
|
||||||
if parent_doctype == "Sales Order" and flt(d.get("qty")) < flt(child_item.delivered_qty):
|
if parent_doctype == "Sales Order" and flt(d.get("qty")) < flt(child_item.delivered_qty):
|
||||||
frappe.throw(_("Cannot set quantity less than delivered quantity"))
|
frappe.throw(_("Cannot set quantity less than delivered quantity"))
|
||||||
|
@ -43,6 +43,7 @@ class BuyingController(StockController):
|
|||||||
self.set_qty_as_per_stock_uom()
|
self.set_qty_as_per_stock_uom()
|
||||||
self.validate_stock_or_nonstock_items()
|
self.validate_stock_or_nonstock_items()
|
||||||
self.validate_warehouse()
|
self.validate_warehouse()
|
||||||
|
self.validate_from_warehouse()
|
||||||
self.set_supplier_address()
|
self.set_supplier_address()
|
||||||
|
|
||||||
if self.doctype=="Purchase Invoice":
|
if self.doctype=="Purchase Invoice":
|
||||||
@ -115,6 +116,14 @@ class BuyingController(StockController):
|
|||||||
if not d.cost_center and lc_voucher_data and lc_voucher_data[0][1]:
|
if not d.cost_center and lc_voucher_data and lc_voucher_data[0][1]:
|
||||||
d.db_set('cost_center', lc_voucher_data[0][1])
|
d.db_set('cost_center', lc_voucher_data[0][1])
|
||||||
|
|
||||||
|
def validate_from_warehouse(self):
|
||||||
|
for item in self.get('items'):
|
||||||
|
if item.get('from_warehouse') and (item.get('from_warehouse') == item.get('warehouse')):
|
||||||
|
frappe.throw(_("Row #{0}: Accepted Warehouse and Supplier Warehouse cannot be same").format(item.idx))
|
||||||
|
|
||||||
|
if item.get('from_warehouse') and self.get('is_subcontracted') == 'Yes':
|
||||||
|
frappe.throw(_("Row #{0}: Cannot select Supplier Warehouse while suppling raw materials to subcontractor").format(item.idx))
|
||||||
|
|
||||||
def set_supplier_address(self):
|
def set_supplier_address(self):
|
||||||
address_dict = {
|
address_dict = {
|
||||||
'supplier_address': 'address_display',
|
'supplier_address': 'address_display',
|
||||||
@ -500,8 +509,8 @@ class BuyingController(StockController):
|
|||||||
item_row = item_row.as_dict()
|
item_row = item_row.as_dict()
|
||||||
for fieldname in field_list:
|
for fieldname in field_list:
|
||||||
if flt(item_row[fieldname]) < 0:
|
if flt(item_row[fieldname]) < 0:
|
||||||
frappe.throw(_("Row #{0}: {1} can not be negative for item {2}".format(item_row['idx'],
|
frappe.throw(_("Row #{0}: {1} can not be negative for item {2}").format(item_row['idx'],
|
||||||
frappe.get_meta(item_row.doctype).get_label(fieldname), item_row['item_code'])))
|
frappe.get_meta(item_row.doctype).get_label(fieldname), item_row['item_code']))
|
||||||
|
|
||||||
def check_for_on_hold_or_closed_status(self, ref_doctype, ref_fieldname):
|
def check_for_on_hold_or_closed_status(self, ref_doctype, ref_fieldname):
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
@ -521,6 +530,16 @@ class BuyingController(StockController):
|
|||||||
pr_qty = flt(d.qty) * flt(d.conversion_factor)
|
pr_qty = flt(d.qty) * flt(d.conversion_factor)
|
||||||
|
|
||||||
if pr_qty:
|
if pr_qty:
|
||||||
|
|
||||||
|
if d.from_warehouse and ((not cint(self.is_return) and self.docstatus==1)
|
||||||
|
or (cint(self.is_return) and self.docstatus==2)):
|
||||||
|
from_warehouse_sle = self.get_sl_entries(d, {
|
||||||
|
"actual_qty": -1 * pr_qty,
|
||||||
|
"warehouse": d.from_warehouse
|
||||||
|
})
|
||||||
|
|
||||||
|
sl_entries.append(from_warehouse_sle)
|
||||||
|
|
||||||
sle = self.get_sl_entries(d, {
|
sle = self.get_sl_entries(d, {
|
||||||
"actual_qty": flt(pr_qty),
|
"actual_qty": flt(pr_qty),
|
||||||
"serial_no": cstr(d.serial_no).strip()
|
"serial_no": cstr(d.serial_no).strip()
|
||||||
@ -541,6 +560,15 @@ class BuyingController(StockController):
|
|||||||
})
|
})
|
||||||
sl_entries.append(sle)
|
sl_entries.append(sle)
|
||||||
|
|
||||||
|
if d.from_warehouse and ((not cint(self.is_return) and self.docstatus==2)
|
||||||
|
or (cint(self.is_return) and self.docstatus==1)):
|
||||||
|
from_warehouse_sle = self.get_sl_entries(d, {
|
||||||
|
"actual_qty": -1 * pr_qty,
|
||||||
|
"warehouse": d.from_warehouse
|
||||||
|
})
|
||||||
|
|
||||||
|
sl_entries.append(from_warehouse_sle)
|
||||||
|
|
||||||
if flt(d.rejected_qty) != 0:
|
if flt(d.rejected_qty) != 0:
|
||||||
sl_entries.append(self.get_sl_entries(d, {
|
sl_entries.append(self.get_sl_entries(d, {
|
||||||
"warehouse": d.rejected_warehouse,
|
"warehouse": d.rejected_warehouse,
|
||||||
@ -872,9 +900,9 @@ def validate_item_type(doc, fieldname, message):
|
|||||||
items = ", ".join([d for d in invalid_items])
|
items = ", ".join([d for d in invalid_items])
|
||||||
|
|
||||||
if len(invalid_items) > 1:
|
if len(invalid_items) > 1:
|
||||||
error_message = _("Following items {0} are not marked as {1} item. You can enable them as {1} item from its Item master".format(items, message))
|
error_message = _("Following items {0} are not marked as {1} item. You can enable them as {1} item from its Item master").format(items, message)
|
||||||
else:
|
else:
|
||||||
error_message = _("Following item {0} is not marked as {1} item. You can enable them as {1} item from its Item master".format(items, message))
|
error_message = _("Following item {0} is not marked as {1} item. You can enable them as {1} item from its Item master").format(items, message)
|
||||||
|
|
||||||
frappe.throw(error_message)
|
frappe.throw(error_message)
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ class SellingController(StockController):
|
|||||||
|
|
||||||
last_purchase_rate, is_stock_item = frappe.get_cached_value("Item", it.item_code, ["last_purchase_rate", "is_stock_item"])
|
last_purchase_rate, is_stock_item = frappe.get_cached_value("Item", it.item_code, ["last_purchase_rate", "is_stock_item"])
|
||||||
last_purchase_rate_in_sales_uom = last_purchase_rate / (it.conversion_factor or 1)
|
last_purchase_rate_in_sales_uom = last_purchase_rate / (it.conversion_factor or 1)
|
||||||
if flt(it.base_rate) < flt(last_purchase_rate_in_sales_uom):
|
if flt(it.base_rate) < flt(last_purchase_rate_in_sales_uom) and not self.get('is_internal_customer'):
|
||||||
throw_message(it.item_name, last_purchase_rate_in_sales_uom, "last purchase rate")
|
throw_message(it.item_name, last_purchase_rate_in_sales_uom, "last purchase rate")
|
||||||
|
|
||||||
last_valuation_rate = frappe.db.sql("""
|
last_valuation_rate = frappe.db.sql("""
|
||||||
@ -190,7 +190,8 @@ class SellingController(StockController):
|
|||||||
""", (it.item_code, it.warehouse))
|
""", (it.item_code, it.warehouse))
|
||||||
if last_valuation_rate:
|
if last_valuation_rate:
|
||||||
last_valuation_rate_in_sales_uom = last_valuation_rate[0][0] / (it.conversion_factor or 1)
|
last_valuation_rate_in_sales_uom = last_valuation_rate[0][0] / (it.conversion_factor or 1)
|
||||||
if is_stock_item and flt(it.base_rate) < flt(last_valuation_rate_in_sales_uom):
|
if is_stock_item and flt(it.base_rate) < flt(last_valuation_rate_in_sales_uom) \
|
||||||
|
and not self.get('is_internal_customer'):
|
||||||
throw_message(it.name, last_valuation_rate_in_sales_uom, "valuation rate")
|
throw_message(it.name, last_valuation_rate_in_sales_uom, "valuation rate")
|
||||||
|
|
||||||
|
|
||||||
@ -300,7 +301,7 @@ class SellingController(StockController):
|
|||||||
d.conversion_factor = get_conversion_factor(d.item_code, d.uom).get("conversion_factor") or 1.0
|
d.conversion_factor = get_conversion_factor(d.item_code, d.uom).get("conversion_factor") or 1.0
|
||||||
return_rate = 0
|
return_rate = 0
|
||||||
if cint(self.is_return) and self.return_against and self.docstatus==1:
|
if cint(self.is_return) and self.return_against and self.docstatus==1:
|
||||||
return_rate = self.get_incoming_rate_for_sales_return(d.item_code, self.return_against)
|
return_rate = self.get_incoming_rate_for_return(d.item_code, self.return_against)
|
||||||
|
|
||||||
# On cancellation or if return entry submission, make stock ledger entry for
|
# On cancellation or if return entry submission, make stock ledger entry for
|
||||||
# target warehouse first, to update serial no values properly
|
# target warehouse first, to update serial no values properly
|
||||||
|
@ -72,7 +72,7 @@ class StockController(AccountsController):
|
|||||||
if sle_list:
|
if sle_list:
|
||||||
for sle in sle_list:
|
for sle in sle_list:
|
||||||
if warehouse_account.get(sle.warehouse):
|
if warehouse_account.get(sle.warehouse):
|
||||||
# from warehouse account
|
# from warehouse account/ target warehouse account
|
||||||
|
|
||||||
self.check_expense_account(item_row)
|
self.check_expense_account(item_row)
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ class StockController(AccountsController):
|
|||||||
"is_opening": item_row.get("is_opening") or self.get("is_opening") or "No",
|
"is_opening": item_row.get("is_opening") or self.get("is_opening") or "No",
|
||||||
}, warehouse_account[sle.warehouse]["account_currency"], item=item_row))
|
}, warehouse_account[sle.warehouse]["account_currency"], item=item_row))
|
||||||
|
|
||||||
# to target warehouse / expense account
|
# expense account
|
||||||
gl_list.append(self.get_gl_dict({
|
gl_list.append(self.get_gl_dict({
|
||||||
"account": item_row.expense_account,
|
"account": item_row.expense_account,
|
||||||
"against": warehouse_account[sle.warehouse]["account"],
|
"against": warehouse_account[sle.warehouse]["account"],
|
||||||
@ -288,7 +288,7 @@ class StockController(AccountsController):
|
|||||||
|
|
||||||
return serialized_items
|
return serialized_items
|
||||||
|
|
||||||
def get_incoming_rate_for_sales_return(self, item_code, against_document):
|
def get_incoming_rate_for_return(self, item_code, against_document):
|
||||||
incoming_rate = 0.0
|
incoming_rate = 0.0
|
||||||
if against_document and item_code:
|
if against_document and item_code:
|
||||||
incoming_rate = frappe.db.sql("""select abs(stock_value_difference / actual_qty)
|
incoming_rate = frappe.db.sql("""select abs(stock_value_difference / actual_qty)
|
||||||
@ -306,6 +306,16 @@ class StockController(AccountsController):
|
|||||||
warehouses = list(set([d.warehouse for d in
|
warehouses = list(set([d.warehouse for d in
|
||||||
self.get("items") if getattr(d, "warehouse", None)]))
|
self.get("items") if getattr(d, "warehouse", None)]))
|
||||||
|
|
||||||
|
target_warehouses = list(set([d.target_warehouse for d in
|
||||||
|
self.get("items") if getattr(d, "target_warehouse", None)]))
|
||||||
|
|
||||||
|
warehouses.extend(target_warehouses)
|
||||||
|
|
||||||
|
from_warehouse = list(set([d.from_warehouse for d in
|
||||||
|
self.get("items") if getattr(d, "from_warehouse", None)]))
|
||||||
|
|
||||||
|
warehouses.extend(from_warehouse)
|
||||||
|
|
||||||
for w in warehouses:
|
for w in warehouses:
|
||||||
validate_warehouse_company(w, self.company)
|
validate_warehouse_company(w, self.company)
|
||||||
|
|
||||||
@ -419,7 +429,7 @@ def get_future_stock_vouchers(posting_date, posting_time, for_warehouses=None, f
|
|||||||
for d in frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no
|
for d in frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no
|
||||||
from `tabStock Ledger Entry` sle
|
from `tabStock Ledger Entry` sle
|
||||||
where timestamp(sle.posting_date, sle.posting_time) >= timestamp(%s, %s) {condition}
|
where timestamp(sle.posting_date, sle.posting_time) >= timestamp(%s, %s) {condition}
|
||||||
order by timestamp(sle.posting_date, sle.posting_time) asc, creation asc""".format(condition=condition),
|
order by timestamp(sle.posting_date, sle.posting_time) asc, creation asc for update""".format(condition=condition),
|
||||||
tuple([posting_date, posting_time] + values), as_dict=True):
|
tuple([posting_date, posting_time] + values), as_dict=True):
|
||||||
future_stock_vouchers.append([d.voucher_type, d.voucher_no])
|
future_stock_vouchers.append([d.voucher_type, d.voucher_no])
|
||||||
|
|
||||||
|
@ -514,7 +514,7 @@ class calculate_taxes_and_totals(object):
|
|||||||
if self.doc.doctype == "Sales Invoice":
|
if self.doc.doctype == "Sales Invoice":
|
||||||
self.calculate_paid_amount()
|
self.calculate_paid_amount()
|
||||||
|
|
||||||
if self.doc.is_return and self.doc.return_against: return
|
if self.doc.is_return and self.doc.return_against and not self.doc.get('is_pos'): return
|
||||||
|
|
||||||
self.doc.round_floats_in(self.doc, ["grand_total", "total_advance", "write_off_amount"])
|
self.doc.round_floats_in(self.doc, ["grand_total", "total_advance", "write_off_amount"])
|
||||||
self._set_in_company_currency(self.doc, ['write_off_amount'])
|
self._set_in_company_currency(self.doc, ['write_off_amount'])
|
||||||
@ -532,7 +532,7 @@ class calculate_taxes_and_totals(object):
|
|||||||
self.doc.round_floats_in(self.doc, ["paid_amount"])
|
self.doc.round_floats_in(self.doc, ["paid_amount"])
|
||||||
change_amount = 0
|
change_amount = 0
|
||||||
|
|
||||||
if self.doc.doctype == "Sales Invoice":
|
if self.doc.doctype == "Sales Invoice" and not self.doc.get('is_return'):
|
||||||
self.calculate_write_off_amount()
|
self.calculate_write_off_amount()
|
||||||
self.calculate_change_amount()
|
self.calculate_change_amount()
|
||||||
change_amount = self.doc.change_amount \
|
change_amount = self.doc.change_amount \
|
||||||
@ -544,6 +544,9 @@ class calculate_taxes_and_totals(object):
|
|||||||
self.doc.outstanding_amount = flt(total_amount_to_pay - flt(paid_amount) + flt(change_amount),
|
self.doc.outstanding_amount = flt(total_amount_to_pay - flt(paid_amount) + flt(change_amount),
|
||||||
self.doc.precision("outstanding_amount"))
|
self.doc.precision("outstanding_amount"))
|
||||||
|
|
||||||
|
if self.doc.doctype == 'Sales Invoice' and self.doc.get('is_pos') and self.doc.get('is_return'):
|
||||||
|
self.update_paid_amount_for_return(total_amount_to_pay)
|
||||||
|
|
||||||
def calculate_paid_amount(self):
|
def calculate_paid_amount(self):
|
||||||
|
|
||||||
paid_amount = base_paid_amount = 0.0
|
paid_amount = base_paid_amount = 0.0
|
||||||
@ -614,6 +617,27 @@ class calculate_taxes_and_totals(object):
|
|||||||
def set_item_wise_tax_breakup(self):
|
def set_item_wise_tax_breakup(self):
|
||||||
self.doc.other_charges_calculation = get_itemised_tax_breakup_html(self.doc)
|
self.doc.other_charges_calculation = get_itemised_tax_breakup_html(self.doc)
|
||||||
|
|
||||||
|
def update_paid_amount_for_return(self, total_amount_to_pay):
|
||||||
|
default_mode_of_payment = frappe.db.get_value('Sales Invoice Payment',
|
||||||
|
{'parent': self.doc.pos_profile, 'default': 1},
|
||||||
|
['mode_of_payment', 'type', 'account'], as_dict=1)
|
||||||
|
|
||||||
|
self.doc.payments = []
|
||||||
|
|
||||||
|
if default_mode_of_payment:
|
||||||
|
self.doc.append('payments', {
|
||||||
|
'mode_of_payment': default_mode_of_payment.mode_of_payment,
|
||||||
|
'type': default_mode_of_payment.type,
|
||||||
|
'account': default_mode_of_payment.account,
|
||||||
|
'amount': total_amount_to_pay
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
self.doc.is_pos = 0
|
||||||
|
self.doc.pos_profile = ''
|
||||||
|
|
||||||
|
self.calculate_paid_amount()
|
||||||
|
|
||||||
|
|
||||||
def get_itemised_tax_breakup_html(doc):
|
def get_itemised_tax_breakup_html(doc):
|
||||||
if not doc.taxes:
|
if not doc.taxes:
|
||||||
return
|
return
|
||||||
|
@ -13,5 +13,14 @@ frappe.ui.form.on('Appointment', {
|
|||||||
frappe.set_route("Form", "Event", frm.doc.calendar_event);
|
frappe.set_route("Form", "Event", frm.doc.calendar_event);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
onload: function(frm){
|
||||||
|
frm.set_query("appointment_with", function(){
|
||||||
|
return {
|
||||||
|
filters : {
|
||||||
|
"name": ["in", ["Customer", "Lead"]]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"autoname": "format:APMT-{customer_name}-{####}",
|
"autoname": "format:APMT-{customer_name}-{####}",
|
||||||
"creation": "2019-08-27 10:48:27.926283",
|
"creation": "2019-08-27 10:48:27.926283",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
@ -15,7 +16,8 @@
|
|||||||
"col_br_2",
|
"col_br_2",
|
||||||
"customer_details",
|
"customer_details",
|
||||||
"linked_docs_section",
|
"linked_docs_section",
|
||||||
"lead",
|
"appointment_with",
|
||||||
|
"party",
|
||||||
"col_br_3",
|
"col_br_3",
|
||||||
"calendar_event"
|
"calendar_event"
|
||||||
],
|
],
|
||||||
@ -61,12 +63,6 @@
|
|||||||
"options": "Open\nUnverified\nClosed",
|
"options": "Open\nUnverified\nClosed",
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "lead",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"label": "Lead",
|
|
||||||
"options": "Lead"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "calendar_event",
|
"fieldname": "calendar_event",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
@ -91,9 +87,22 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "col_br_3",
|
"fieldname": "col_br_3",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "appointment_with",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Appointment With",
|
||||||
|
"options": "DocType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "party",
|
||||||
|
"fieldtype": "Dynamic Link",
|
||||||
|
"label": "Party",
|
||||||
|
"options": "appointment_with"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2019-10-14 15:23:54.630731",
|
"links": [],
|
||||||
|
"modified": "2020-01-28 16:16:45.447213",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "CRM",
|
"module": "CRM",
|
||||||
"name": "Appointment",
|
"name": "Appointment",
|
||||||
|
@ -24,6 +24,14 @@ class Appointment(Document):
|
|||||||
return lead_list[0].name
|
return lead_list[0].name
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def find_customer_by_email(self):
|
||||||
|
customer_list = frappe.get_list(
|
||||||
|
'Customer', filters={'email_id': self.customer_email}, ignore_permissions=True
|
||||||
|
)
|
||||||
|
if customer_list:
|
||||||
|
return customer_list[0].name
|
||||||
|
return None
|
||||||
|
|
||||||
def before_insert(self):
|
def before_insert(self):
|
||||||
number_of_appointments_in_same_slot = frappe.db.count(
|
number_of_appointments_in_same_slot = frappe.db.count(
|
||||||
'Appointment', filters={'scheduled_time': self.scheduled_time})
|
'Appointment', filters={'scheduled_time': self.scheduled_time})
|
||||||
@ -32,11 +40,18 @@ class Appointment(Document):
|
|||||||
if (number_of_appointments_in_same_slot >= number_of_agents):
|
if (number_of_appointments_in_same_slot >= number_of_agents):
|
||||||
frappe.throw('Time slot is not available')
|
frappe.throw('Time slot is not available')
|
||||||
# Link lead
|
# Link lead
|
||||||
if not self.lead:
|
if not self.party:
|
||||||
self.lead = self.find_lead_by_email()
|
lead = self.find_lead_by_email()
|
||||||
|
customer = self.find_customer_by_email()
|
||||||
|
if customer:
|
||||||
|
self.appointment_with = "Customer"
|
||||||
|
self.party = customer
|
||||||
|
else:
|
||||||
|
self.appointment_with = "Lead"
|
||||||
|
self.party = lead
|
||||||
|
|
||||||
def after_insert(self):
|
def after_insert(self):
|
||||||
if self.lead:
|
if self.party:
|
||||||
# Create Calendar event
|
# Create Calendar event
|
||||||
self.auto_assign()
|
self.auto_assign()
|
||||||
self.create_calendar_event()
|
self.create_calendar_event()
|
||||||
@ -89,7 +104,7 @@ class Appointment(Document):
|
|||||||
|
|
||||||
def create_lead_and_link(self):
|
def create_lead_and_link(self):
|
||||||
# Return if already linked
|
# Return if already linked
|
||||||
if self.lead:
|
if self.party:
|
||||||
return
|
return
|
||||||
lead = frappe.get_doc({
|
lead = frappe.get_doc({
|
||||||
'doctype': 'Lead',
|
'doctype': 'Lead',
|
||||||
@ -100,7 +115,7 @@ class Appointment(Document):
|
|||||||
})
|
})
|
||||||
lead.insert(ignore_permissions=True)
|
lead.insert(ignore_permissions=True)
|
||||||
# Link lead
|
# Link lead
|
||||||
self.lead = lead.name
|
self.party = lead.name
|
||||||
|
|
||||||
def auto_assign(self):
|
def auto_assign(self):
|
||||||
from frappe.desk.form.assign_to import add as add_assignemnt
|
from frappe.desk.form.assign_to import add as add_assignemnt
|
||||||
@ -129,14 +144,14 @@ class Appointment(Document):
|
|||||||
break
|
break
|
||||||
|
|
||||||
def get_assignee_from_latest_opportunity(self):
|
def get_assignee_from_latest_opportunity(self):
|
||||||
if not self.lead:
|
if not self.party:
|
||||||
return None
|
return None
|
||||||
if not frappe.db.exists('Lead', self.lead):
|
if not frappe.db.exists('Lead', self.party):
|
||||||
return None
|
return None
|
||||||
opporutnities = frappe.get_list(
|
opporutnities = frappe.get_list(
|
||||||
'Opportunity',
|
'Opportunity',
|
||||||
filters={
|
filters={
|
||||||
'party_name': self.lead,
|
'party_name': self.party,
|
||||||
},
|
},
|
||||||
ignore_permissions=True,
|
ignore_permissions=True,
|
||||||
order_by='creation desc')
|
order_by='creation desc')
|
||||||
@ -159,7 +174,7 @@ class Appointment(Document):
|
|||||||
'status': 'Open',
|
'status': 'Open',
|
||||||
'type': 'Public',
|
'type': 'Public',
|
||||||
'send_reminder': frappe.db.get_single_value('Appointment Booking Settings', 'email_reminders'),
|
'send_reminder': frappe.db.get_single_value('Appointment Booking Settings', 'email_reminders'),
|
||||||
'event_participants': [dict(reference_doctype='Lead', reference_docname=self.lead)]
|
'event_participants': [dict(reference_doctype=self.appointment_with, reference_docname=self.party)]
|
||||||
})
|
})
|
||||||
employee = _get_employee_from_user(self._assign)
|
employee = _get_employee_from_user(self._assign)
|
||||||
if employee:
|
if employee:
|
||||||
|
@ -59,6 +59,7 @@ frappe.ui.form.on("Opportunity", {
|
|||||||
contact_person: erpnext.utils.get_contact_details,
|
contact_person: erpnext.utils.get_contact_details,
|
||||||
|
|
||||||
opportunity_from: function(frm) {
|
opportunity_from: function(frm) {
|
||||||
|
frm.trigger('setup_queries');
|
||||||
frm.toggle_reqd("party_name", frm.doc.opportunity_from);
|
frm.toggle_reqd("party_name", frm.doc.opportunity_from);
|
||||||
frm.trigger("set_dynamic_field_label");
|
frm.trigger("set_dynamic_field_label");
|
||||||
},
|
},
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
"sales_stage",
|
"sales_stage",
|
||||||
"order_lost_reason",
|
"order_lost_reason",
|
||||||
"mins_to_first_response",
|
"mins_to_first_response",
|
||||||
|
"expected_closing",
|
||||||
"next_contact",
|
"next_contact",
|
||||||
"contact_by",
|
"contact_by",
|
||||||
"contact_date",
|
"contact_date",
|
||||||
@ -156,6 +157,11 @@
|
|||||||
"label": "Mins to first response",
|
"label": "Mins to first response",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "expected_closing",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"label": "Expected Closing Date"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"collapsible_depends_on": "contact_by",
|
"collapsible_depends_on": "contact_by",
|
||||||
|
@ -37,7 +37,7 @@ class AssessmentPlan(Document):
|
|||||||
for d in self.assessment_criteria:
|
for d in self.assessment_criteria:
|
||||||
max_score += d.maximum_score
|
max_score += d.maximum_score
|
||||||
if self.maximum_assessment_score != max_score:
|
if self.maximum_assessment_score != max_score:
|
||||||
frappe.throw(_("Sum of Scores of Assessment Criteria needs to be {0}.".format(self.maximum_assessment_score)))
|
frappe.throw(_("Sum of Scores of Assessment Criteria needs to be {0}.").format(self.maximum_assessment_score))
|
||||||
|
|
||||||
def validate_assessment_criteria(self):
|
def validate_assessment_criteria(self):
|
||||||
assessment_criteria_list = frappe.db.sql_list(''' select apc.assessment_criteria
|
assessment_criteria_list = frappe.db.sql_list(''' select apc.assessment_criteria
|
||||||
|
@ -41,7 +41,7 @@ class AssessmentResult(Document):
|
|||||||
assessment_result = frappe.get_list("Assessment Result", filters={"name": ("not in", [self.name]),
|
assessment_result = frappe.get_list("Assessment Result", filters={"name": ("not in", [self.name]),
|
||||||
"student":self.student, "assessment_plan":self.assessment_plan, "docstatus":("!=", 2)})
|
"student":self.student, "assessment_plan":self.assessment_plan, "docstatus":("!=", 2)})
|
||||||
if assessment_result:
|
if assessment_result:
|
||||||
frappe.throw(_("Assessment Result record {0} already exists.".format(getlink("Assessment Result",assessment_result[0].name))))
|
frappe.throw(_("Assessment Result record {0} already exists.").format(getlink("Assessment Result",assessment_result[0].name)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,3 +37,16 @@ frappe.ui.form.on("Course", "refresh", function(frm) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
frappe.ui.form.on('Course Topic', {
|
||||||
|
topics_add: function(frm){
|
||||||
|
frm.fields_dict['topics'].grid.get_field('topic').get_query = function(doc){
|
||||||
|
var topics_list = [];
|
||||||
|
if(!doc.__islocal) topics_list.push(doc.name);
|
||||||
|
$.each(doc.topics, function(idx, val){
|
||||||
|
if (val.topic) topics_list.push(val.topic);
|
||||||
|
});
|
||||||
|
return { filters: [['Topic', 'name', 'not in', topics_list]] };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
@ -16,4 +16,4 @@ class CourseActivity(Document):
|
|||||||
if frappe.db.exists("Course Enrollment", self.enrollment):
|
if frappe.db.exists("Course Enrollment", self.enrollment):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
frappe.throw(_("Course Enrollment {0} does not exists".format(self.enrollment)))
|
frappe.throw(_("Course Enrollment {0} does not exists").format(self.enrollment))
|
@ -13,7 +13,7 @@ class GradingScale(Document):
|
|||||||
thresholds = []
|
thresholds = []
|
||||||
for d in self.intervals:
|
for d in self.intervals:
|
||||||
if d.threshold in thresholds:
|
if d.threshold in thresholds:
|
||||||
frappe.throw(_("Treshold {0}% appears more than once".format(d.threshold)))
|
frappe.throw(_("Treshold {0}% appears more than once").format(d.threshold))
|
||||||
else:
|
else:
|
||||||
thresholds.append(cint(d.threshold))
|
thresholds.append(cint(d.threshold))
|
||||||
if 0 not in thresholds:
|
if 0 not in thresholds:
|
||||||
|
@ -12,7 +12,6 @@ frappe.ui.form.on("Instructor", {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
frm.set_query("department", "instructor_log", function() {
|
frm.set_query("department", "instructor_log", function() {
|
||||||
return {
|
return {
|
||||||
"filters": {
|
"filters": {
|
||||||
@ -49,5 +48,12 @@ frappe.ui.form.on("Instructor", {
|
|||||||
frappe.set_route("List", "Assessment Plan");
|
frappe.set_route("List", "Assessment Plan");
|
||||||
}, __("Assessment Plan"));
|
}, __("Assessment Plan"));
|
||||||
}
|
}
|
||||||
|
frm.set_query("employee", function(doc) {
|
||||||
|
return {
|
||||||
|
"filters": {
|
||||||
|
"department": doc.department,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
@ -81,3 +81,16 @@ frappe.ui.form.on("Program Enrollment", {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
frappe.ui.form.on('Program Enrollment Course', {
|
||||||
|
courses_add: function(frm){
|
||||||
|
frm.fields_dict['courses'].grid.get_field('course').get_query = function(doc){
|
||||||
|
var course_list = [];
|
||||||
|
if(!doc.__islocal) course_list.push(doc.name);
|
||||||
|
$.each(doc.courses, function(idx, val){
|
||||||
|
if (val.course) course_list.push(val.course);
|
||||||
|
});
|
||||||
|
return { filters: [['Course', 'name', 'not in', course_list]] };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
@ -38,7 +38,7 @@ class Question(Document):
|
|||||||
options = self.options
|
options = self.options
|
||||||
answers = [item.name for item in options if item.is_correct == True]
|
answers = [item.name for item in options if item.is_correct == True]
|
||||||
if len(answers) == 0:
|
if len(answers) == 0:
|
||||||
frappe.throw(_("No correct answer is set for {0}".format(self.name)))
|
frappe.throw(_("No correct answer is set for {0}").format(self.name))
|
||||||
return None
|
return None
|
||||||
elif len(answers) == 1:
|
elif len(answers) == 1:
|
||||||
return answers[0]
|
return answers[0]
|
||||||
|
@ -4,5 +4,18 @@
|
|||||||
frappe.ui.form.on('Quiz', {
|
frappe.ui.form.on('Quiz', {
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
|
|
||||||
|
},
|
||||||
|
validate: function(frm){
|
||||||
|
frm.events.check_duplicate_question(frm.doc.question);
|
||||||
|
},
|
||||||
|
check_duplicate_question: function(questions_data){
|
||||||
|
var questions = [];
|
||||||
|
questions_data.forEach(function(q){
|
||||||
|
questions.push(q.question_link);
|
||||||
|
});
|
||||||
|
var questions_set = new Set(questions);
|
||||||
|
if (questions.length != questions_set.size) {
|
||||||
|
frappe.throw(__("The question cannot be duplicate"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
@ -22,9 +22,16 @@ class Student(Document):
|
|||||||
self.update_student_name_in_linked_doctype()
|
self.update_student_name_in_linked_doctype()
|
||||||
|
|
||||||
def validate_dates(self):
|
def validate_dates(self):
|
||||||
|
for sibling in self.siblings:
|
||||||
|
if sibling.date_of_birth and getdate(sibling.date_of_birth) > getdate():
|
||||||
|
frappe.throw(_("Row {0}:Sibling Date of Birth cannot be greater than today.").format(sibling.idx))
|
||||||
|
|
||||||
if self.date_of_birth and getdate(self.date_of_birth) >= getdate(today()):
|
if self.date_of_birth and getdate(self.date_of_birth) >= getdate(today()):
|
||||||
frappe.throw(_("Date of Birth cannot be greater than today."))
|
frappe.throw(_("Date of Birth cannot be greater than today."))
|
||||||
|
|
||||||
|
if self.date_of_birth and getdate(self.date_of_birth) >= getdate(self.joining_date):
|
||||||
|
frappe.throw(_("Date of Birth cannot be greater than Joining Date."))
|
||||||
|
|
||||||
if self.joining_date and self.date_of_leaving and getdate(self.joining_date) > getdate(self.date_of_leaving):
|
if self.joining_date and self.date_of_leaving and getdate(self.joining_date) > getdate(self.date_of_leaving):
|
||||||
frappe.throw(_("Joining Date can not be greater than Leaving Date"))
|
frappe.throw(_("Joining Date can not be greater than Leaving Date"))
|
||||||
|
|
||||||
|
@ -29,10 +29,15 @@ class StudentApplicant(Document):
|
|||||||
set_name_by_naming_series(self)
|
set_name_by_naming_series(self)
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
self.validate_dates()
|
||||||
self.title = " ".join(filter(None, [self.first_name, self.middle_name, self.last_name]))
|
self.title = " ".join(filter(None, [self.first_name, self.middle_name, self.last_name]))
|
||||||
if self.student_admission and self.program and self.date_of_birth:
|
if self.student_admission and self.program and self.date_of_birth:
|
||||||
self.validation_from_student_admission()
|
self.validation_from_student_admission()
|
||||||
|
|
||||||
|
def validate_dates(self):
|
||||||
|
if self.date_of_birth and getdate(self.date_of_birth) >= getdate():
|
||||||
|
frappe.throw(_("Date of Birth cannot be greater than today."))
|
||||||
|
|
||||||
def on_update_after_submit(self):
|
def on_update_after_submit(self):
|
||||||
student = frappe.get_list("Student", filters= {"student_applicant": self.name})
|
student = frappe.get_list("Student", filters= {"student_applicant": self.name})
|
||||||
if student:
|
if student:
|
||||||
|
@ -70,6 +70,16 @@ frappe.ui.form.on("Student Group", {
|
|||||||
group_based_on: function(frm) {
|
group_based_on: function(frm) {
|
||||||
if (frm.doc.group_based_on == "Batch") {
|
if (frm.doc.group_based_on == "Batch") {
|
||||||
frm.doc.course = null;
|
frm.doc.course = null;
|
||||||
|
frm.set_df_property('program', 'reqd', 1);
|
||||||
|
frm.set_df_property('course', 'reqd', 0);
|
||||||
|
}
|
||||||
|
else if (frm.doc.group_based_on == "Course") {
|
||||||
|
frm.set_df_property('program', 'reqd', 0);
|
||||||
|
frm.set_df_property('course', 'reqd', 1);
|
||||||
|
}
|
||||||
|
else if (frm.doc.group_based_on == "Activity") {
|
||||||
|
frm.set_df_property('program', 'reqd', 0);
|
||||||
|
frm.set_df_property('course', 'reqd', 0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user