Compare commits

..

2 Commits

Author SHA1 Message Date
Ankush Menat
e8571bac00 fix: Correctly extract last message
frappe.message_log now contains plain dictionary and not JSON strings,
so no need to load them.
2023-10-20 15:18:04 +05:30
Ankush Menat
40cdde8820 ci: seutp v15 config
https://github.com/frappe/frappe/issues/22817
2023-10-19 15:55:02 +05:30
857 changed files with 4967 additions and 23921 deletions

60
.github/helper/translation.py vendored Normal file
View File

@@ -0,0 +1,60 @@
import re
import sys
errors_encounter = 0
pattern = re.compile(r"_\(([\"']{,3})(?P<message>((?!\1).)*)\1(\s*,\s*context\s*=\s*([\"'])(?P<py_context>((?!\5).)*)\5)*(\s*,(\s*?.*?\n*?)*(,\s*([\"'])(?P<js_context>((?!\11).)*)\11)*)*\)")
words_pattern = re.compile(r"_{1,2}\([\"'`]{1,3}.*?[a-zA-Z]")
start_pattern = re.compile(r"_{1,2}\([f\"'`]{1,3}")
f_string_pattern = re.compile(r"_\(f[\"']")
starts_with_f_pattern = re.compile(r"_\(f")
# skip first argument
files = sys.argv[1:]
files_to_scan = [_file for _file in files if _file.endswith(('.py', '.js'))]
for _file in files_to_scan:
with open(_file, 'r') as f:
print(f'Checking: {_file}')
file_lines = f.readlines()
for line_number, line in enumerate(file_lines, 1):
if 'frappe-lint: disable-translate' in line:
continue
start_matches = start_pattern.search(line)
if start_matches:
starts_with_f = starts_with_f_pattern.search(line)
if starts_with_f:
has_f_string = f_string_pattern.search(line)
if has_f_string:
errors_encounter += 1
print(f'\nF-strings are not supported for translations at line number {line_number}\n{line.strip()[:100]}')
continue
else:
continue
match = pattern.search(line)
error_found = False
if not match and line.endswith((',\n', '[\n')):
# concat remaining text to validate multiline pattern
line = "".join(file_lines[line_number - 1:])
line = line[start_matches.start() + 1:]
match = pattern.match(line)
if not match:
error_found = True
print(f'\nTranslation syntax error at line number {line_number}\n{line.strip()[:100]}')
if not error_found and not words_pattern.search(line):
error_found = True
print(f'\nTranslation is useless because it has no words at line number {line_number}\n{line.strip()[:100]}')
if error_found:
errors_encounter += 1
if errors_encounter > 0:
print('\nVisit "https://frappeframework.com/docs/user/en/translations" to learn about valid translation strings.')
sys.exit(1)
else:
print('\nGood To Go!')

26
.github/workflows/backport.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: Backport
on:
pull_request_target:
types:
- closed
- labeled
jobs:
main:
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Checkout Actions
uses: actions/checkout@v2
with:
repository: "frappe/backport"
path: ./actions
ref: develop
- name: Install Actions
run: npm install --production --prefix ./actions
- name: Run backport
uses: ./actions/backport
with:
token: ${{secrets.BACKPORT_BOT_TOKEN}}
labelsToAdd: "backport"
title: "{{originalTitle}}"

32
.github/workflows/initiate_release.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
# This workflow is agnostic to branches. Only maintain on develop branch.
# To add/remove versions just modify the matrix.
name: Create weekly release pull requests
on:
schedule:
# 9:30 UTC => 3 PM IST Tuesday
- cron: "30 9 * * 2"
workflow_dispatch:
jobs:
stable-release:
name: Release
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
version: ["13", "14"]
steps:
- uses: octokit/request-action@v2.x
with:
route: POST /repos/{owner}/{repo}/pulls
owner: frappe
repo: erpnext
title: |-
"chore: release v${{ matrix.version }}"
body: "Automated weekly release."
base: version-${{ matrix.version }}
head: version-${{ matrix.version }}-hotfix
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}

View File

@@ -134,6 +134,7 @@ jobs:
}
update_to_version 14
update_to_version 15
echo "Updating to latest version"
git -C "apps/frappe" checkout -q -f "${GITHUB_BASE_REF:-${GITHUB_REF##*/}}"

View File

@@ -2,23 +2,21 @@ name: Generate Semantic Release
on:
push:
branches:
- version-15
- version-13
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout Entire Repository
uses: actions/checkout@v4
uses: actions/checkout@v2
with:
fetch-depth: 0
persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: 18
- name: Setup dependencies
run: |
npm install @semantic-release/git @semantic-release/exec --no-save

View File

@@ -117,7 +117,7 @@ jobs:
FRAPPE_BRANCH: ${{ github.event.inputs.branch }}
- name: Run Tests
run: 'cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --total-builds 4 --build-number ${{ matrix.container }}'
run: 'cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --with-coverage --total-builds 4 --build-number ${{ matrix.container }}'
env:
TYPE: server
CI_BUILD_ID: ${{ github.run_id }}
@@ -126,3 +126,27 @@ jobs:
- name: Show bench output
if: ${{ always() }}
run: cat ~/frappe-bench/bench_start.log || true
- name: Upload coverage data
uses: actions/upload-artifact@v3
with:
name: coverage-${{ matrix.container }}
path: /home/runner/frappe-bench/sites/coverage.xml
coverage:
name: Coverage Wrap Up
needs: test
runs-on: ubuntu-latest
steps:
- name: Clone
uses: actions/checkout@v2
- name: Download artifacts
uses: actions/download-artifact@v3
- name: Upload coverage data
uses: codecov/codecov-action@v2
with:
name: MariaDB
fail_ci_if_error: true
verbose: true

View File

@@ -17,6 +17,7 @@ pull_request_rules:
- base=version-12
- base=version-14
- base=version-15
- base=version-16
actions:
close:
comment:
@@ -24,16 +25,6 @@ pull_request_rules:
@{{author}}, thanks for the contribution, but we do not accept pull requests on a stable branch. Please raise PR on an appropriate hotfix branch.
https://github.com/frappe/erpnext/wiki/Pull-Request-Checklist#which-branch
- name: Auto-close PRs on pre-release branch
conditions:
- base=version-13-pre-release
actions:
close:
comment:
message: |
@{{author}}, pre-release branch is not maintained anymore. Releases are directly done by merging hotfix branch to stable branches.
- name: backport to develop
conditions:
- label="backport develop"
@@ -54,13 +45,13 @@ pull_request_rules:
assignees:
- "{{ author }}"
- name: backport to version-14-pre-release
- name: backport to version-15-hotfix
conditions:
- label="backport version-14-pre-release"
- label="backport version-15-hotfix"
actions:
backport:
branches:
- version-14-pre-release
- version-15-hotfix
assignees:
- "{{ author }}"
@@ -74,35 +65,6 @@ pull_request_rules:
assignees:
- "{{ author }}"
- name: backport to version-13-pre-release
conditions:
- label="backport version-13-pre-release"
actions:
backport:
branches:
- version-13-pre-release
assignees:
- "{{ author }}"
- name: backport to version-12-hotfix
conditions:
- label="backport version-12-hotfix"
actions:
backport:
branches:
- version-12-hotfix
assignees:
- "{{ author }}"
- name: backport to version-12-pre-release
conditions:
- label="backport version-12-pre-release"
actions:
backport:
branches:
- version-12-pre-release
assignees:
- "{{ author }}"
- name: Automatic merge on CI success and review
conditions:

View File

@@ -5,7 +5,7 @@ fail_fast: false
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
rev: v4.0.1
hooks:
- id: trailing-whitespace
files: "erpnext.*"
@@ -15,10 +15,6 @@ repos:
args: ['--branch', 'develop']
- id: check-merge-conflict
- id: check-ast
- id: check-json
- id: check-toml
- id: check-yaml
- id: debug-statements
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v8.44.0

View File

@@ -1,5 +1,5 @@
{
"branches": ["version-15"],
"branches": ["version-13"],
"plugins": [
"@semantic-release/commit-analyzer", {
"preset": "angular",
@@ -21,4 +21,4 @@
],
"@semantic-release/github"
]
}
}

View File

@@ -3,7 +3,7 @@ import inspect
import frappe
__version__ = "15.8.2"
__version__ = "15.0.0-dev"
def get_default_company(user=None):

View File

@@ -23,65 +23,6 @@ class InvalidAccountMergeError(frappe.ValidationError):
class Account(NestedSet):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
account_currency: DF.Link | None
account_name: DF.Data
account_number: DF.Data | None
account_type: DF.Literal[
"",
"Accumulated Depreciation",
"Asset Received But Not Billed",
"Bank",
"Cash",
"Chargeable",
"Capital Work in Progress",
"Cost of Goods Sold",
"Current Asset",
"Current Liability",
"Depreciation",
"Direct Expense",
"Direct Income",
"Equity",
"Expense Account",
"Expenses Included In Asset Valuation",
"Expenses Included In Valuation",
"Fixed Asset",
"Income Account",
"Indirect Expense",
"Indirect Income",
"Liability",
"Payable",
"Receivable",
"Round Off",
"Stock",
"Stock Adjustment",
"Stock Received But Not Billed",
"Service Received But Not Billed",
"Tax",
"Temporary",
]
balance_must_be: DF.Literal["", "Debit", "Credit"]
company: DF.Link
disabled: DF.Check
freeze_account: DF.Literal["No", "Yes"]
include_in_gross: DF.Check
is_group: DF.Check
lft: DF.Int
old_parent: DF.Data | None
parent_account: DF.Link
report_type: DF.Literal["", "Balance Sheet", "Profit and Loss"]
rgt: DF.Int
root_type: DF.Literal["", "Asset", "Liability", "Income", "Expense", "Equity"]
tax_rate: DF.Float
# end: auto-generated types
nsm_parent_field = "parent_account"
def on_update(self):

View File

@@ -26,7 +26,7 @@
"0360 Bauliche Investitionen in fremden (gepachteten) Betriebs- und Geschäftsgebäuden": {"account_type": "Fixed Asset"},
"0370 Bauliche Investitionen in fremden (gepachteten) Wohn- und Sozialgebäuden": {"account_type": "Fixed Asset"},
"0390 Kumulierte Abschreibungen zu Grundstücken ": {"account_type": "Fixed Asset"},
"0400 Maschinen und Geräte ": {"account_type": "Fixed Asset"},
"0400 Maschinen und Geräte ": {"account_type": "Fixed Asset"},
"0500 Maschinenwerkzeuge ": {"account_type": "Fixed Asset"},
"0510 Allgemeine Werkzeuge und Handwerkzeuge ": {"account_type": "Fixed Asset"},
"0520 Prototypen, Formen, Modelle ": {"account_type": "Fixed Asset"},
@@ -65,41 +65,42 @@
"0980 Geleistete Anzahlungen auf Finanzanlagen ": {"account_type": "Fixed Asset"},
"0990 Kumulierte Abschreibungen zu Finanzanlagen ": {"account_type": "Fixed Asset"},
"root_type": "Asset"
},
},
"Klasse 1 Aktiva: Vorr\u00e4te": {
"1000 Bezugsverrechnung": {"account_type": "Stock"},
"1100 Rohstoffe": {"account_type": "Stock"},
"1200 Bezogene Teile": {"account_type": "Stock"},
"1300 Hilfsstoffe": {"account_type": "Stock"},
"1350 Betriebsstoffe": {"account_type": "Stock"},
"1360 Vorrat Energietraeger": {"account_type": "Stock"},
"1360 Vorrat Energietraeger": {"account_type": "Stock"},
"1400 Unfertige Erzeugnisse": {"account_type": "Stock"},
"1500 Fertige Erzeugnisse": {"account_type": "Stock"},
"1600 Handelswarenvorrat": {"account_type": "Stock Received But Not Billed"},
"1700 Noch nicht abrechenbare Leistungen": {"account_type": "Stock"},
"1900 Wertberichtigungen": {"account_type": "Stock"},
"1800 Geleistete Anzahlungen": {"account_type": "Stock"},
"1900 Wertberichtigungen": {"account_type": "Stock"},
"root_type": "Asset"
},
},
"Klasse 3 Passiva: Verbindlichkeiten": {
"3000 Allgemeine Verbindlichkeiten (Schuld)": {"account_type": "Payable"},
"3010 R\u00fcckstellungen f\u00fcr Pensionen": {"account_type": "Payable"},
"3020 Steuerr\u00fcckstellungen": {"account_type": "Tax"},
"3041 Sonstige R\u00fcckstellungen": {"account_type": "Payable"},
"3041 Sonstige R\u00fcckstellungen": {"account_type": "Payable"},
"3110 Verbindlichkeiten gegen\u00fcber Bank": {"account_type": "Payable"},
"3150 Verbindlichkeiten Darlehen": {"account_type": "Payable"},
"3185 Verbindlichkeiten Kreditkarte": {"account_type": "Payable"},
"3185 Verbindlichkeiten Kreditkarte": {"account_type": "Payable"},
"3380 Verbindlichkeiten aus der Annahme gezogener Wechsel u. d. Ausstellungen eigener Wechsel": {
"account_type": "Payable"
},
"3400 Verbindlichkeiten gegen\u00fc. verb. Untern., Verbindl. gegen\u00fc. Untern., mit denen eine Beteiligungsverh\u00e4lnis besteht": {},
"3460 Verbindlichkeiten gegenueber Gesellschaftern": {"account_type": "Payable"},
"3470 Einlagen stiller Gesellschafter": {"account_type": "Payable"},
"3585 Verbindlichkeiten Lohnsteuer": {"account_type": "Tax"},
"3590 Verbindlichkeiten Kommunalabgaben": {"account_type": "Tax"},
"3595 Verbindlichkeiten Dienstgeberbeitrag": {"account_type": "Tax"},
"3585 Verbindlichkeiten Lohnsteuer": {"account_type": "Tax"},
"3590 Verbindlichkeiten Kommunalabgaben": {"account_type": "Tax"},
"3595 Verbindlichkeiten Dienstgeberbeitrag": {"account_type": "Tax"},
"3600 Verbindlichkeiten Sozialversicherung": {"account_type": "Payable"},
"3640 Verbindlichkeiten Loehne und Gehaelter": {"account_type": "Payable"},
"3640 Verbindlichkeiten Loehne und Gehaelter": {"account_type": "Payable"},
"3700 Sonstige Verbindlichkeiten": {"account_type": "Payable"},
"3900 Passive Rechnungsabgrenzungsposten": {"account_type": "Payable"},
"3100 Anleihen (einschlie\u00dflich konvertibler)": {"account_type": "Payable"},
@@ -118,13 +119,13 @@
},
"3515 Umsatzsteuer Inland 10%": {
"account_type": "Tax"
},
},
"3520 Umsatzsteuer aus i.g. Erwerb 20%": {
"account_type": "Tax"
},
"3525 Umsatzsteuer aus i.g. Erwerb 10%": {
"account_type": "Tax"
},
},
"3560 Umsatzsteuer-Evidenzkonto f\u00fcr erhaltene Anzahlungen auf Bestellungen": {},
"3360 Verbindlichkeiten aus Lieferungen u. Leistungen EU": {
"account_type": "Payable"
@@ -140,7 +141,7 @@
"account_type": "Tax"
},
"root_type": "Liability"
},
},
"Klasse 2 Aktiva: Umlaufverm\u00f6gen, Rechnungsabgrenzungen": {
"2030 Forderungen aus Lieferungen und Leistungen Inland (0% USt, umsatzsteuerfrei)": {
"account_type": "Receivable"
@@ -153,7 +154,7 @@
},
"2040 Forderungen aus Lieferungen und Leistungen Inland (sonstiger USt-Satz)": {
"account_type": "Receivable"
},
},
"2100 Forderungen aus Lieferungen und Leistungen EU": {
"account_type": "Receivable"
},
@@ -191,7 +192,7 @@
"account_type": "Receivable"
},
"2570 Einfuhrumsatzsteuer (bezahlt)": {"account_type": "Tax"},
"2460 Eingeforderte aber noch nicht eingezahlte Einlagen": {
"account_type": "Receivable"
},
@@ -242,10 +243,10 @@
},
"2800 Guthaben bei Bank": {
"account_type": "Bank"
},
},
"2801 Guthaben bei Bank - Sparkonto": {
"account_type": "Bank"
},
},
"2810 Guthaben bei Paypal": {
"account_type": "Bank"
},
@@ -263,19 +264,19 @@
},
"2895 Schwebende Geldbewegugen": {
"account_type": "Bank"
},
},
"2513 Vorsteuer Inland 5%": {
"account_type": "Tax"
},
"2515 Vorsteuer Inland 20%": {
"account_type": "Tax"
},
},
"2520 Vorsteuer aus innergemeinschaftlichem Erwerb 10%": {
"account_type": "Tax"
},
"2525 Vorsteuer aus innergemeinschaftlichem Erwerb 20%": {
"account_type": "Tax"
},
},
"2530 Vorsteuer \u00a719/Art 19 ( reverse charge ) ": {
"account_type": "Tax"
},
@@ -285,16 +286,16 @@
"root_type": "Asset"
},
"Klasse 4: Betriebliche Erträge": {
"4000 Erlöse 20 %": {"account_type": "Income Account"},
"4020 Erl\u00f6se 0 % steuerbefreit": {"account_type": "Income Account"},
"4000 Erlöse 20 %": {"account_type": "Income Account"},
"4020 Erl\u00f6se 0 % steuerbefreit": {"account_type": "Income Account"},
"4010 Erl\u00f6se 10 %": {"account_type": "Income Account"},
"4030 Erl\u00f6se 13 %": {"account_type": "Income Account"},
"4040 Erl\u00f6se 0 % innergemeinschaftliche Lieferungen": {"account_type": "Income Account"},
"4400 Erl\u00f6sreduktion 0 % steuerbefreit": {"account_type": "Expense Account"},
"4030 Erl\u00f6se 13 %": {"account_type": "Income Account"},
"4040 Erl\u00f6se 0 % innergemeinschaftliche Lieferungen": {"account_type": "Income Account"},
"4400 Erl\u00f6sreduktion 0 % steuerbefreit": {"account_type": "Expense Account"},
"4410 Erl\u00f6sreduktion 10 %": {"account_type": "Expense Account"},
"4420 Erl\u00f6sreduktion 20 %": {"account_type": "Expense Account"},
"4430 Erl\u00f6sreduktion 13 %": {"account_type": "Expense Account"},
"4440 Erl\u00f6sreduktion 0 % innergemeinschaftliche Lieferungen": {"account_type": "Expense Account"},
"4430 Erl\u00f6sreduktion 13 %": {"account_type": "Expense Account"},
"4440 Erl\u00f6sreduktion 0 % innergemeinschaftliche Lieferungen": {"account_type": "Expense Account"},
"4500 Ver\u00e4nderungen des Bestandes an fertigen und unfertigen Erzeugn. sowie an noch nicht abrechenbaren Leistungen": {"account_type": "Income Account"},
"4580 Aktivierte Eigenleistungen": {"account_type": "Income Account"},
"4600 Erl\u00f6se aus dem Abgang vom Anlageverm\u00f6gen, ausgen. Finanzanlagen": {"account_type": "Income Account"},
@@ -303,15 +304,15 @@
"4700 Ertr\u00e4ge aus der Aufl\u00f6sung von R\u00fcckstellungen": {"account_type": "Income Account"},
"4800 \u00dcbrige betriebliche Ertr\u00e4ge": {"account_type": "Income Account"},
"root_type": "Income"
},
},
"Klasse 5: Aufwand f\u00fcr Material und Leistungen": {
"5000 Einkauf Partnerleistungen": {"account_type": "Cost of Goods Sold"},
"5000 Einkauf Partnerleistungen": {"account_type": "Cost of Goods Sold"},
"5100 Verbrauch an Rohstoffen": {"account_type": "Cost of Goods Sold"},
"5200 Verbrauch von bezogenen Fertig- und Einzelteilen": {"account_type": "Cost of Goods Sold"},
"5300 Verbrauch von Hilfsstoffen": {"account_type": "Cost of Goods Sold"},
"5340 Verbrauch Verpackungsmaterial": {"account_type": "Cost of Goods Sold"},
"5470 Verbrauch von Kleinmaterial": {"account_type": "Cost of Goods Sold"},
"5450 Verbrauch von Reinigungsmaterial": {"account_type": "Cost of Goods Sold"},
"5450 Verbrauch von Reinigungsmaterial": {"account_type": "Cost of Goods Sold"},
"5400 Verbrauch von Betriebsstoffen": {"account_type": "Cost of Goods Sold"},
"5500 Verbrauch von Werkzeugen und anderen Erzeugungshilfsmittel": {"account_type": "Cost of Goods Sold"},
"5600 Verbrauch von Brenn- und Treibstoffen, Energie und Wasser": {"account_type": "Cost of Goods Sold"},
@@ -339,7 +340,7 @@
"6700 Sonstige Sozialaufwendungen": {"account_type": "Payable"},
"6900 Aufwandsstellenrechnung Personal": {"account_type": "Payable"},
"root_type": "Expense"
},
},
"Klasse 7: Abschreibungen und sonstige betriebliche Aufwendungen": {
"7010 Abschreibungen auf das Anlageverm\u00f6gen (ausgenommen Finanzanlagen)": {"account_type": "Depreciation"},
"7100 Sonstige Steuern und Geb\u00fchren": {"account_type": "Tax"},
@@ -348,7 +349,7 @@
"7310 Fahrrad - Aufwand": {"account_type": "Expense Account"},
"7320 Kfz - Aufwand": {"account_type": "Expense Account"},
"7330 LKW - Aufwand": {"account_type": "Expense Account"},
"7340 Lastenrad - Aufwand": {"account_type": "Expense Account"},
"7340 Lastenrad - Aufwand": {"account_type": "Expense Account"},
"7350 Reise- und Fahraufwand": {"account_type": "Expense Account"},
"7360 Tag- und N\u00e4chtigungsgelder": {"account_type": "Expense Account"},
"7380 Nachrichtenaufwand": {"account_type": "Expense Account"},
@@ -408,7 +409,7 @@
"8990 Gewinnabfuhr bzw. Verlust\u00fcberrechnung aus Ergebnisabf\u00fchrungsvertr\u00e4gen": {"account_type": "Expense Account"},
"8350 nicht ausgenutzte Lieferantenskonti": {"account_type": "Expense Account"},
"root_type": "Income"
},
},
"Klasse 9 Passiva: Eigenkapital, R\u00fccklagen, stille Einlagen, Abschlusskonten": {
"9000 Gezeichnetes bzw. gewidmetes Kapital": {
"account_type": "Equity"
@@ -434,5 +435,5 @@
},
"root_type": "Equity"
}
}
}
}

View File

@@ -33,9 +33,7 @@
},
"Stocks": {
"Mati\u00e8res premi\u00e8res": {},
"Stock de produits fini": {
"account_type": "Stock"
},
"Stock de produits fini": {},
"Stock exp\u00e9di\u00e9 non-factur\u00e9": {},
"Travaux en cours": {},
"account_type": "Stock"
@@ -397,11 +395,9 @@
},
"Produits": {
"Revenus de ventes": {
"Escomptes de volume sur ventes": {},
" Escomptes de volume sur ventes": {},
"Autres produits d'exploitation": {},
"Ventes": {
"account_type": "Income Account"
},
"Ventes": {},
"Ventes avec des provinces harmonis\u00e9es": {},
"Ventes avec des provinces non-harmonis\u00e9es": {},
"Ventes \u00e0 l'\u00e9tranger": {}

View File

@@ -53,13 +53,8 @@
},
"II. Forderungen und sonstige Vermögensgegenstände": {
"is_group": 1,
"Forderungen aus Lieferungen und Leistungen mit Kontokorrent": {
"Ford. a. Lieferungen und Leistungen": {
"account_number": "1400",
"account_type": "Receivable",
"is_group": 1
},
"Forderungen aus Lieferungen und Leistungen ohne Kontokorrent": {
"account_number": "1410",
"account_type": "Receivable"
},
"Durchlaufende Posten": {
@@ -185,13 +180,8 @@
},
"IV. Verbindlichkeiten aus Lieferungen und Leistungen": {
"is_group": 1,
"Verbindlichkeiten aus Lieferungen und Leistungen mit Kontokorrent": {
"Verbindlichkeiten aus Lieferungen u. Leistungen": {
"account_number": "1600",
"account_type": "Payable",
"is_group": 1
},
"Verbindlichkeiten aus Lieferungen und Leistungen ohne Kontokorrent": {
"account_number": "1610",
"account_type": "Payable"
}
},

View File

@@ -407,10 +407,13 @@
"Bewertungskorrektur zu Forderungen aus Lieferungen und Leistungen": {
"account_number": "9960"
},
"Forderungen aus Lieferungen und Leistungen mit Kontokorrent": {
"Debitoren": {
"is_group": 1,
"account_number": "10000"
},
"Forderungen aus Lieferungen und Leistungen": {
"account_number": "1200",
"account_type": "Receivable",
"is_group": 1
"account_type": "Receivable"
},
"Forderungen aus Lieferungen und Leistungen ohne Kontokorrent": {
"account_number": "1210"
@@ -1135,15 +1138,18 @@
"Bewertungskorrektur zu Verb. aus Lieferungen und Leistungen": {
"account_number": "9964"
},
"Verb. aus Lieferungen und Leistungen mit Kontokorrent": {
"account_number": "3300",
"account_type": "Payable",
"Kreditoren": {
"account_number": "70000",
"is_group": 1,
"Wareneingangs-Verrechnungskonto" : {
"Wareneingangs-­Verrechnungskonto" : {
"account_number": "70001",
"account_type": "Stock Received But Not Billed"
}
},
"Verb. aus Lieferungen und Leistungen": {
"account_number": "3300",
"account_type": "Payable"
},
"Verb. aus Lieferungen und Leistungen ohne Kontokorrent": {
"account_number": "3310"
},

View File

@@ -11,29 +11,6 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
class AccountClosingBalance(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
account: DF.Link | None
account_currency: DF.Link | None
closing_date: DF.Date | None
company: DF.Link | None
cost_center: DF.Link | None
credit: DF.Currency
credit_in_account_currency: DF.Currency
debit: DF.Currency
debit_in_account_currency: DF.Currency
finance_book: DF.Link | None
is_period_closing_voucher_entry: DF.Check
period_closing_voucher: DF.Link | None
project: DF.Link | None
# end: auto-generated types
pass

View File

@@ -13,25 +13,6 @@ from frappe.utils import cstr
class AccountingDimension(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.accounting_dimension_detail.accounting_dimension_detail import (
AccountingDimensionDetail,
)
dimension_defaults: DF.Table[AccountingDimensionDetail]
disabled: DF.Check
document_type: DF.Link
fieldname: DF.Data | None
label: DF.Data | None
# end: auto-generated types
def before_insert(self):
self.set_fieldname_and_label()

View File

@@ -7,24 +7,4 @@ from frappe.model.document import Document
class AccountingDimensionDetail(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
automatically_post_balancing_accounting_entry: DF.Check
company: DF.Link | None
default_dimension: DF.DynamicLink | None
mandatory_for_bs: DF.Check
mandatory_for_pl: DF.Check
offsetting_account: DF.Link | None
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
reference_document: DF.Link | None
# end: auto-generated types
pass

View File

@@ -8,28 +8,6 @@ from frappe.model.document import Document
class AccountingDimensionFilter(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.allowed_dimension.allowed_dimension import AllowedDimension
from erpnext.accounts.doctype.applicable_on_account.applicable_on_account import (
ApplicableOnAccount,
)
accounting_dimension: DF.Literal
accounts: DF.Table[ApplicableOnAccount]
allow_or_restrict: DF.Literal["Allow", "Restrict"]
apply_restriction_on_values: DF.Check
company: DF.Link
dimensions: DF.Table[AllowedDimension]
disabled: DF.Check
# end: auto-generated types
def before_save(self):
# If restriction is not applied on values, then remove all the dimensions and set allow_or_restrict to Restrict
if not self.apply_restriction_on_values:

View File

@@ -16,23 +16,6 @@ class ClosedAccountingPeriod(frappe.ValidationError):
class AccountingPeriod(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.closed_document.closed_document import ClosedDocument
closed_documents: DF.Table[ClosedDocument]
company: DF.Link
end_date: DF.Date
period_name: DF.Data
start_date: DF.Date
# end: auto-generated types
def validate(self):
self.validate_overlap()

View File

@@ -66,12 +66,7 @@
"show_balance_in_coa",
"banking_tab",
"enable_party_matching",
"enable_fuzzy_matching",
"reports_tab",
"remarks_section",
"general_ledger_remarks_length",
"column_break_lvjk",
"receivable_payable_remarks_length"
"enable_fuzzy_matching"
],
"fields": [
{
@@ -427,34 +422,6 @@
"fieldname": "round_row_wise_tax",
"fieldtype": "Check",
"label": "Round Tax Amount Row-wise"
},
{
"fieldname": "reports_tab",
"fieldtype": "Tab Break",
"label": "Reports"
},
{
"default": "0",
"description": "Truncates 'Remarks' column to set character length",
"fieldname": "general_ledger_remarks_length",
"fieldtype": "Int",
"label": "General Ledger"
},
{
"default": "0",
"description": "Truncates 'Remarks' column to set character length",
"fieldname": "receivable_payable_remarks_length",
"fieldtype": "Int",
"label": "Accounts Receivable/Payable"
},
{
"fieldname": "column_break_lvjk",
"fieldtype": "Column Break"
},
{
"fieldname": "remarks_section",
"fieldtype": "Section Break",
"label": "Remarks Column Length"
}
],
"icon": "icon-cog",
@@ -462,7 +429,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2023-11-20 09:37:47.650347",
"modified": "2023-08-28 00:12:02.740633",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",

View File

@@ -14,52 +14,6 @@ from erpnext.stock.utils import check_pending_reposting
class AccountsSettings(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
acc_frozen_upto: DF.Date | None
add_taxes_from_item_tax_template: DF.Check
allow_multi_currency_invoices_against_single_party_account: DF.Check
allow_stale: DF.Check
auto_reconcile_payments: DF.Check
automatically_fetch_payment_terms: DF.Check
automatically_process_deferred_accounting_entry: DF.Check
book_asset_depreciation_entry_automatically: DF.Check
book_deferred_entries_based_on: DF.Literal["Days", "Months"]
book_deferred_entries_via_journal_entry: DF.Check
book_tax_discount_loss: DF.Check
check_supplier_invoice_uniqueness: DF.Check
credit_controller: DF.Link | None
delete_linked_ledger_entries: DF.Check
determine_address_tax_category_from: DF.Literal["Billing Address", "Shipping Address"]
enable_common_party_accounting: DF.Check
enable_fuzzy_matching: DF.Check
enable_party_matching: DF.Check
frozen_accounts_modifier: DF.Link | None
general_ledger_remarks_length: DF.Int
ignore_account_closing_balance: DF.Check
make_payment_via_journal_entry: DF.Check
merge_similar_account_heads: DF.Check
over_billing_allowance: DF.Currency
post_change_gl_entries: DF.Check
receivable_payable_remarks_length: DF.Int
role_allowed_to_over_bill: DF.Link | None
round_row_wise_tax: DF.Check
show_balance_in_coa: DF.Check
show_inclusive_tax_in_print: DF.Check
show_payment_schedule_in_print: DF.Check
show_taxes_as_table_in_print: DF.Check
stale_days: DF.Int
submit_journal_entries: DF.Check
unlink_advance_payment_on_cancelation_of_order: DF.Check
unlink_payment_on_cancellation_of_invoice: DF.Check
# end: auto-generated types
def validate(self):
old_doc = self.get_doc_before_save()
clear_cache = False

View File

@@ -6,22 +6,4 @@ from frappe.model.document import Document
class AdvanceTax(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
account_head: DF.Link | None
allocated_amount: DF.Currency
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
reference_detail: DF.Data | None
reference_name: DF.DynamicLink | None
reference_type: DF.Link | None
# end: auto-generated types
pass

View File

@@ -7,33 +7,4 @@ from frappe.model.document import Document
class AdvanceTaxesandCharges(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
account_head: DF.Link
add_deduct_tax: DF.Literal["Add", "Deduct"]
allocated_amount: DF.Currency
base_tax_amount: DF.Currency
base_total: DF.Currency
charge_type: DF.Literal[
"", "Actual", "On Paid Amount", "On Previous Row Amount", "On Previous Row Total"
]
cost_center: DF.Link | None
currency: DF.Link | None
description: DF.SmallText
included_in_paid_amount: DF.Check
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
rate: DF.Float
row_id: DF.Data | None
tax_amount: DF.Currency
total: DF.Currency
# end: auto-generated types
pass

View File

@@ -7,19 +7,4 @@ from frappe.model.document import Document
class AllowedDimension(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
accounting_dimension: DF.Link | None
dimension_value: DF.DynamicLink | None
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
# end: auto-generated types
pass

View File

@@ -6,18 +6,4 @@ from frappe.model.document import Document
class AllowedToTransactWith(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
company: DF.Link
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
# end: auto-generated types
pass

View File

@@ -7,19 +7,4 @@ from frappe.model.document import Document
class ApplicableOnAccount(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
applicable_on_account: DF.Link
is_mandatory: DF.Check
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
# end: auto-generated types
pass

View File

@@ -10,25 +10,6 @@ from frappe.model.document import Document
class Bank(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.bank_transaction_mapping.bank_transaction_mapping import (
BankTransactionMapping,
)
bank_name: DF.Data
bank_transaction_mapping: DF.Table[BankTransactionMapping]
plaid_access_token: DF.Data | None
swift_number: DF.Data | None
website: DF.Data | None
# end: auto-generated types
def onload(self):
"""Load address and contacts in `__onload`"""
load_address_and_contact(self)

View File

@@ -12,33 +12,6 @@ from frappe.model.document import Document
class BankAccount(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
account: DF.Link | None
account_name: DF.Data
account_subtype: DF.Link | None
account_type: DF.Link | None
bank: DF.Link
bank_account_no: DF.Data | None
branch_code: DF.Data | None
company: DF.Link | None
disabled: DF.Check
iban: DF.Data | None
integration_id: DF.Data | None
is_company_account: DF.Check
is_default: DF.Check
last_integration_date: DF.Date | None
mask: DF.Data | None
party: DF.DynamicLink | None
party_type: DF.Link | None
# end: auto-generated types
def onload(self):
"""Load address and contacts in `__onload`"""
load_address_and_contact(self)

View File

@@ -6,15 +6,4 @@ from frappe.model.document import Document
class BankAccountSubtype(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
account_subtype: DF.Data | None
# end: auto-generated types
pass

View File

@@ -7,15 +7,4 @@ from frappe.model.document import Document
class BankAccountType(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
account_type: DF.Data | None
# end: auto-generated types
pass

View File

@@ -13,28 +13,6 @@ form_grid_templates = {"journal_entries": "templates/form_grid/bank_reconciliati
class BankClearance(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.bank_clearance_detail.bank_clearance_detail import (
BankClearanceDetail,
)
account: DF.Link
account_currency: DF.Link | None
bank_account: DF.Link | None
from_date: DF.Date
include_pos_transactions: DF.Check
include_reconciled_entries: DF.Check
payment_entries: DF.Table[BankClearanceDetail]
to_date: DF.Date
# end: auto-generated types
@frappe.whitelist()
def get_payment_entries(self):
if not (self.from_date and self.to_date):

View File

@@ -6,25 +6,4 @@ from frappe.model.document import Document
class BankClearanceDetail(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
against_account: DF.Data | None
amount: DF.Data | None
cheque_date: DF.Date | None
cheque_number: DF.Data | None
clearance_date: DF.Date | None
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
payment_document: DF.Link | None
payment_entry: DF.DynamicLink | None
posting_date: DF.Date | None
# end: auto-generated types
pass

View File

@@ -8,40 +8,6 @@ from frappe.model.document import Document
class BankGuarantee(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
account: DF.Link | None
amended_from: DF.Link | None
amount: DF.Currency
bank: DF.Link | None
bank_account: DF.Link | None
bank_account_no: DF.Data | None
bank_guarantee_number: DF.Data | None
bg_type: DF.Literal["", "Receiving", "Providing"]
branch_code: DF.Data | None
charges: DF.Currency
customer: DF.Link | None
end_date: DF.Date | None
fixed_deposit_number: DF.Data | None
iban: DF.Data | None
margin_money: DF.Currency
more_information: DF.TextEditor | None
name_of_beneficiary: DF.Data | None
project: DF.Link | None
reference_docname: DF.DynamicLink | None
reference_doctype: DF.Link | None
start_date: DF.Date
supplier: DF.Link | None
swift_number: DF.Data | None
validity: DF.Int
# end: auto-generated types
def validate(self):
if not (self.customer or self.supplier):
frappe.throw(_("Select the customer or supplier."))

View File

@@ -18,30 +18,9 @@ from erpnext.accounts.report.bank_reconciliation_statement.bank_reconciliation_s
get_entries,
)
from erpnext.accounts.utils import get_account_currency, get_balance_on
from erpnext.setup.utils import get_exchange_rate
class BankReconciliationTool(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
account_currency: DF.Link | None
account_opening_balance: DF.Currency
bank_account: DF.Link | None
bank_statement_closing_balance: DF.Currency
bank_statement_from_date: DF.Date | None
bank_statement_to_date: DF.Date | None
company: DF.Link | None
filter_by_reference_date: DF.Check
from_reference_date: DF.Date | None
to_reference_date: DF.Date | None
# end: auto-generated types
pass
@@ -151,7 +130,7 @@ def create_journal_entry_bts(
bank_transaction = frappe.db.get_values(
"Bank Transaction",
bank_transaction_name,
fieldname=["name", "deposit", "withdrawal", "bank_account", "currency"],
fieldname=["name", "deposit", "withdrawal", "bank_account"],
as_dict=True,
)[0]
company_account = frappe.get_value("Bank Account", bank_transaction.bank_account, "account")
@@ -165,94 +144,29 @@ def create_journal_entry_bts(
)
company = frappe.get_value("Account", company_account, "company")
company_default_currency = frappe.get_cached_value("Company", company, "default_currency")
company_account_currency = frappe.get_cached_value("Account", company_account, "account_currency")
second_account_currency = frappe.get_cached_value("Account", second_account, "account_currency")
# determine if multi-currency Journal or not
is_multi_currency = (
True
if company_default_currency != company_account_currency
or company_default_currency != second_account_currency
or company_default_currency != bank_transaction.currency
else False
)
accounts = []
second_account_dict = {
"account": second_account,
"account_currency": second_account_currency,
"credit_in_account_currency": bank_transaction.deposit,
"debit_in_account_currency": bank_transaction.withdrawal,
"party_type": party_type,
"party": party,
"cost_center": get_default_cost_center(company),
}
# Multi Currency?
accounts.append(
{
"account": second_account,
"credit_in_account_currency": bank_transaction.deposit,
"debit_in_account_currency": bank_transaction.withdrawal,
"party_type": party_type,
"party": party,
"cost_center": get_default_cost_center(company),
}
)
company_account_dict = {
"account": company_account,
"account_currency": company_account_currency,
"bank_account": bank_transaction.bank_account,
"credit_in_account_currency": bank_transaction.withdrawal,
"debit_in_account_currency": bank_transaction.deposit,
"cost_center": get_default_cost_center(company),
}
# convert transaction amount to company currency
if is_multi_currency:
exc_rate = get_exchange_rate(bank_transaction.currency, company_default_currency, posting_date)
withdrawal_in_company_currency = flt(exc_rate * abs(bank_transaction.withdrawal))
deposit_in_company_currency = flt(exc_rate * abs(bank_transaction.deposit))
else:
withdrawal_in_company_currency = bank_transaction.withdrawal
deposit_in_company_currency = bank_transaction.deposit
# if second account is of foreign currency, convert and set debit and credit fields.
if second_account_currency != company_default_currency:
exc_rate = get_exchange_rate(second_account_currency, company_default_currency, posting_date)
second_account_dict.update(
{
"exchange_rate": exc_rate,
"credit": deposit_in_company_currency,
"debit": withdrawal_in_company_currency,
"credit_in_account_currency": flt(deposit_in_company_currency / exc_rate) or 0,
"debit_in_account_currency": flt(withdrawal_in_company_currency / exc_rate) or 0,
}
)
else:
second_account_dict.update(
{
"exchange_rate": 1,
"credit": deposit_in_company_currency,
"debit": withdrawal_in_company_currency,
"credit_in_account_currency": deposit_in_company_currency,
"debit_in_account_currency": withdrawal_in_company_currency,
}
)
# if company account is of foreign currency, convert and set debit and credit fields.
if company_account_currency != company_default_currency:
exc_rate = get_exchange_rate(company_account_currency, company_default_currency, posting_date)
company_account_dict.update(
{
"exchange_rate": exc_rate,
"credit": withdrawal_in_company_currency,
"debit": deposit_in_company_currency,
}
)
else:
company_account_dict.update(
{
"exchange_rate": 1,
"credit": withdrawal_in_company_currency,
"debit": deposit_in_company_currency,
"credit_in_account_currency": withdrawal_in_company_currency,
"debit_in_account_currency": deposit_in_company_currency,
}
)
accounts.append(second_account_dict)
accounts.append(company_account_dict)
accounts.append(
{
"account": company_account,
"bank_account": bank_transaction.bank_account,
"credit_in_account_currency": bank_transaction.withdrawal,
"debit_in_account_currency": bank_transaction.deposit,
"cost_center": get_default_cost_center(company),
}
)
journal_entry_dict = {
"voucher_type": entry_type,
@@ -262,9 +176,6 @@ def create_journal_entry_bts(
"cheque_no": reference_number,
"mode_of_payment": mode_of_payment,
}
if is_multi_currency:
journal_entry_dict.update({"multi_currency": True})
journal_entry = frappe.new_doc("Journal Entry")
journal_entry.update(journal_entry_dict)
journal_entry.set("accounts", accounts)
@@ -444,9 +355,7 @@ def reconcile_vouchers(bank_transaction_name, vouchers):
vouchers = json.loads(vouchers)
transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
transaction.add_payment_entries(vouchers)
transaction.save()
return transaction
return frappe.get_doc("Bank Transaction", bank_transaction_name)
@frappe.whitelist()

View File

@@ -20,30 +20,6 @@ INVALID_VALUES = ("", None)
class BankStatementImport(DataImport):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
bank: DF.Link | None
bank_account: DF.Link
company: DF.Link
google_sheets_url: DF.Data | None
import_file: DF.Attach | None
import_type: DF.Literal["", "Insert New Records", "Update Existing Records"]
mute_emails: DF.Check
reference_doctype: DF.Link
show_failed_logs: DF.Check
statement_import_log: DF.Code | None
status: DF.Literal["Pending", "Success", "Partial Success", "Error"]
submit_after_import: DF.Check
template_options: DF.Code | None
template_warnings: DF.Code | None
# end: auto-generated types
def __init__(self, *args, **kwargs):
super(BankStatementImport, self).__init__(*args, **kwargs)

View File

@@ -13,7 +13,6 @@
"status",
"bank_account",
"company",
"amended_from",
"section_break_4",
"deposit",
"withdrawal",
@@ -26,10 +25,10 @@
"transaction_id",
"transaction_type",
"section_break_14",
"column_break_oufv",
"payment_entries",
"section_break_18",
"allocated_amount",
"amended_from",
"column_break_17",
"unallocated_amount",
"party_section",
@@ -139,12 +138,10 @@
"fieldtype": "Section Break"
},
{
"allow_on_submit": 1,
"fieldname": "allocated_amount",
"fieldtype": "Currency",
"label": "Allocated Amount",
"options": "currency",
"read_only": 1
"options": "currency"
},
{
"fieldname": "amended_from",
@@ -160,12 +157,10 @@
"fieldtype": "Column Break"
},
{
"allow_on_submit": 1,
"fieldname": "unallocated_amount",
"fieldtype": "Currency",
"label": "Unallocated Amount",
"options": "currency",
"read_only": 1
"options": "currency"
},
{
"fieldname": "party_section",
@@ -230,15 +225,11 @@
"fieldname": "bank_party_account_number",
"fieldtype": "Data",
"label": "Party Account No. (Bank Statement)"
},
{
"fieldname": "column_break_oufv",
"fieldtype": "Column Break"
}
],
"is_submittable": 1,
"links": [],
"modified": "2023-11-18 18:32:47.203694",
"modified": "2023-06-06 13:58:12.821411",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Transaction",

View File

@@ -2,108 +2,78 @@
# For license information, please see license.txt
import frappe
from frappe import _
from frappe.utils import flt
from erpnext.controllers.status_updater import StatusUpdater
class BankTransaction(StatusUpdater):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
def after_insert(self):
self.unallocated_amount = abs(flt(self.withdrawal) - flt(self.deposit))
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.bank_transaction_payments.bank_transaction_payments import (
BankTransactionPayments,
)
allocated_amount: DF.Currency
amended_from: DF.Link | None
bank_account: DF.Link | None
bank_party_account_number: DF.Data | None
bank_party_iban: DF.Data | None
bank_party_name: DF.Data | None
company: DF.Link | None
currency: DF.Link | None
date: DF.Date | None
deposit: DF.Currency
description: DF.SmallText | None
naming_series: DF.Literal["ACC-BTN-.YYYY.-"]
party: DF.DynamicLink | None
party_type: DF.Link | None
payment_entries: DF.Table[BankTransactionPayments]
reference_number: DF.Data | None
status: DF.Literal["", "Pending", "Settled", "Unreconciled", "Reconciled", "Cancelled"]
transaction_id: DF.Data | None
transaction_type: DF.Data | None
unallocated_amount: DF.Currency
withdrawal: DF.Currency
# end: auto-generated types
def before_validate(self):
self.update_allocated_amount()
def validate(self):
self.validate_duplicate_references()
def validate_duplicate_references(self):
"""Make sure the same voucher is not allocated twice within the same Bank Transaction"""
if not self.payment_entries:
return
pe = []
for row in self.payment_entries:
reference = (row.payment_document, row.payment_entry)
if reference in pe:
frappe.throw(
_("{0} {1} is allocated twice in this Bank Transaction").format(
row.payment_document, row.payment_entry
)
)
pe.append(reference)
def update_allocated_amount(self):
self.allocated_amount = (
sum(p.allocated_amount for p in self.payment_entries) if self.payment_entries else 0.0
)
self.unallocated_amount = abs(flt(self.withdrawal) - flt(self.deposit)) - self.allocated_amount
def before_submit(self):
self.allocate_payment_entries()
def on_submit(self):
self.clear_linked_payment_entries()
self.set_status()
if frappe.db.get_single_value("Accounts Settings", "enable_party_matching"):
self.auto_set_party()
def before_update_after_submit(self):
self.validate_duplicate_references()
self.allocate_payment_entries()
self.update_allocated_amount()
_saving_flag = False
# nosemgrep: frappe-semgrep-rules.rules.frappe-modifying-but-not-comitting
def on_update_after_submit(self):
"Run on save(). Avoid recursion caused by multiple saves"
if not self._saving_flag:
self._saving_flag = True
self.clear_linked_payment_entries()
self.update_allocations()
self._saving_flag = False
def on_cancel(self):
for payment_entry in self.payment_entries:
self.clear_linked_payment_entry(payment_entry, for_cancel=True)
self.clear_linked_payment_entries(for_cancel=True)
self.set_status(update=True)
def update_allocations(self):
"The doctype does not allow modifications after submission, so write to the db direct"
if self.payment_entries:
allocated_amount = sum(p.allocated_amount for p in self.payment_entries)
else:
allocated_amount = 0.0
amount = abs(flt(self.withdrawal) - flt(self.deposit))
self.db_set("allocated_amount", flt(allocated_amount))
self.db_set("unallocated_amount", amount - flt(allocated_amount))
self.reload()
self.set_status(update=True)
def add_payment_entries(self, vouchers):
"Add the vouchers with zero allocation. Save() will perform the allocations and clearance"
if 0.0 >= self.unallocated_amount:
frappe.throw(_("Bank Transaction {0} is already fully reconciled").format(self.name))
frappe.throw(frappe._("Bank Transaction {0} is already fully reconciled").format(self.name))
added = False
for voucher in vouchers:
self.append(
"payment_entries",
{
# Can't add same voucher twice
found = False
for pe in self.payment_entries:
if (
pe.payment_document == voucher["payment_doctype"]
and pe.payment_entry == voucher["payment_name"]
):
found = True
if not found:
pe = {
"payment_document": voucher["payment_doctype"],
"payment_entry": voucher["payment_name"],
"allocated_amount": 0.0, # Temporary
},
)
}
child = self.append("payment_entries", pe)
added = True
# runs on_update_after_submit
if added:
self.save()
def allocate_payment_entries(self):
"""Refactored from bank reconciliation tool.
@@ -119,8 +89,8 @@ class BankTransaction(StatusUpdater):
- 0 > a: Error: already over-allocated
- clear means: set the latest transaction date as clearance date
"""
gl_bank_account = frappe.db.get_value("Bank Account", self.bank_account, "account")
remaining_amount = self.unallocated_amount
to_remove = []
for payment_entry in self.payment_entries:
if payment_entry.allocated_amount == 0.0:
unallocated_amount, should_clear, latest_transaction = get_clearance_details(
@@ -130,39 +100,49 @@ class BankTransaction(StatusUpdater):
if 0.0 == unallocated_amount:
if should_clear:
latest_transaction.clear_linked_payment_entry(payment_entry)
to_remove.append(payment_entry)
self.db_delete_payment_entry(payment_entry)
elif remaining_amount <= 0.0:
to_remove.append(payment_entry)
self.db_delete_payment_entry(payment_entry)
elif 0.0 < unallocated_amount <= remaining_amount:
payment_entry.allocated_amount = unallocated_amount
elif 0.0 < unallocated_amount and unallocated_amount <= remaining_amount:
payment_entry.db_set("allocated_amount", unallocated_amount)
remaining_amount -= unallocated_amount
if should_clear:
latest_transaction.clear_linked_payment_entry(payment_entry)
elif 0.0 < unallocated_amount:
payment_entry.allocated_amount = remaining_amount
elif 0.0 < unallocated_amount and unallocated_amount > remaining_amount:
payment_entry.db_set("allocated_amount", remaining_amount)
remaining_amount = 0.0
elif 0.0 > unallocated_amount:
frappe.throw(_("Voucher {0} is over-allocated by {1}").format(unallocated_amount))
self.db_delete_payment_entry(payment_entry)
frappe.throw(frappe._("Voucher {0} is over-allocated by {1}").format(unallocated_amount))
for payment_entry in to_remove:
self.remove(to_remove)
self.reload()
def db_delete_payment_entry(self, payment_entry):
frappe.db.delete("Bank Transaction Payments", {"name": payment_entry.name})
@frappe.whitelist()
def remove_payment_entries(self):
for payment_entry in self.payment_entries:
self.remove_payment_entry(payment_entry)
self.save() # runs before_update_after_submit
# runs on_update_after_submit
self.save()
def remove_payment_entry(self, payment_entry):
"Clear payment entry and clearance"
self.clear_linked_payment_entry(payment_entry, for_cancel=True)
self.remove(payment_entry)
def clear_linked_payment_entries(self, for_cancel=False):
if for_cancel:
for payment_entry in self.payment_entries:
self.clear_linked_payment_entry(payment_entry, for_cancel)
else:
self.allocate_payment_entries()
def clear_linked_payment_entry(self, payment_entry, for_cancel=False):
clearance_date = None if for_cancel else self.date
set_voucher_clearance(
@@ -183,10 +163,11 @@ class BankTransaction(StatusUpdater):
deposit=self.deposit,
).match()
if not result:
return
self.party_type, self.party = result
if result:
party_type, party = result
frappe.db.set_value(
"Bank Transaction", self.name, field={"party_type": party_type, "party": party}
)
@frappe.whitelist()
@@ -218,7 +199,9 @@ def get_clearance_details(transaction, payment_entry):
if gle["gl_account"] == gl_bank_account:
if gle["amount"] <= 0.0:
frappe.throw(
_("Voucher {0} value is broken: {1}").format(payment_entry.payment_entry, gle["amount"])
frappe._("Voucher {0} value is broken: {1}").format(
payment_entry.payment_entry, gle["amount"]
)
)
unmatched_gles -= 1
@@ -239,7 +222,7 @@ def get_clearance_details(transaction, payment_entry):
def get_related_bank_gl_entries(doctype, docname):
# nosemgrep: frappe-semgrep-rules.rules.frappe-using-db-sql
return frappe.db.sql(
result = frappe.db.sql(
"""
SELECT
ABS(gle.credit_in_account_currency - gle.debit_in_account_currency) AS amount,
@@ -257,6 +240,7 @@ def get_related_bank_gl_entries(doctype, docname):
dict(doctype=doctype, docname=docname),
as_dict=True,
)
return result
def get_total_allocated_amount(doctype, docname):
@@ -382,7 +366,6 @@ def set_voucher_clearance(doctype, docname, clearance_date, self):
if clearance_date:
vouchers = [{"payment_doctype": "Bank Transaction", "payment_name": self.name}]
bt.add_payment_entries(vouchers)
bt.save()
else:
for pe in bt.payment_entries:
if pe.payment_document == self.doctype and pe.payment_entry == self.name:

View File

@@ -6,19 +6,4 @@ from frappe.model.document import Document
class BankTransactionMapping(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
bank_transaction_field: DF.Literal
file_field: DF.Data
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
# end: auto-generated types
pass

View File

@@ -6,21 +6,4 @@ from frappe.model.document import Document
class BankTransactionPayments(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
allocated_amount: DF.Currency
clearance_date: DF.Date | None
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
payment_document: DF.Link
payment_entry: DF.DynamicLink
# end: auto-generated types
pass

View File

@@ -22,36 +22,6 @@ class DuplicateBudgetError(frappe.ValidationError):
class Budget(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.budget_account.budget_account import BudgetAccount
accounts: DF.Table[BudgetAccount]
action_if_accumulated_monthly_budget_exceeded: DF.Literal["", "Stop", "Warn", "Ignore"]
action_if_accumulated_monthly_budget_exceeded_on_mr: DF.Literal["", "Stop", "Warn", "Ignore"]
action_if_accumulated_monthly_budget_exceeded_on_po: DF.Literal["", "Stop", "Warn", "Ignore"]
action_if_annual_budget_exceeded: DF.Literal["", "Stop", "Warn", "Ignore"]
action_if_annual_budget_exceeded_on_mr: DF.Literal["", "Stop", "Warn", "Ignore"]
action_if_annual_budget_exceeded_on_po: DF.Literal["", "Stop", "Warn", "Ignore"]
amended_from: DF.Link | None
applicable_on_booking_actual_expenses: DF.Check
applicable_on_material_request: DF.Check
applicable_on_purchase_order: DF.Check
budget_against: DF.Literal["", "Cost Center", "Project"]
company: DF.Link
cost_center: DF.Link | None
fiscal_year: DF.Link
monthly_distribution: DF.Link | None
naming_series: DF.Data | None
project: DF.Link | None
# end: auto-generated types
def validate(self):
if not self.get(frappe.scrub(self.budget_against)):
frappe.throw(_("{0} is mandatory").format(self.budget_against))

View File

@@ -6,19 +6,4 @@ from frappe.model.document import Document
class BudgetAccount(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
account: DF.Link
budget_amount: DF.Currency
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
# end: auto-generated types
pass

View File

@@ -6,18 +6,4 @@ from frappe.model.document import Document
class CampaignItem(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
campaign: DF.Link | None
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
# end: auto-generated types
pass

View File

@@ -9,32 +9,6 @@ from frappe.utils import flt
class CashierClosing(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.cashier_closing_payments.cashier_closing_payments import (
CashierClosingPayments,
)
amended_from: DF.Link | None
custody: DF.Float
date: DF.Date | None
expense: DF.Float
from_time: DF.Time
naming_series: DF.Literal["POS-CLO-"]
net_amount: DF.Float
outstanding_amount: DF.Float
payments: DF.Table[CashierClosingPayments]
returns: DF.Float
time: DF.Time
user: DF.Link
# end: auto-generated types
def validate(self):
self.validate_time()

View File

@@ -6,19 +6,4 @@ from frappe.model.document import Document
class CashierClosingPayments(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
amount: DF.Float
mode_of_payment: DF.Link
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
# end: auto-generated types
pass

View File

@@ -53,18 +53,10 @@ frappe.ui.form.on('Chart of Accounts Importer', {
of Accounts. Please enter the account names and add more rows as per your requirement.`);
}
}
},
{
label : "Company",
fieldname: "company",
fieldtype: "Link",
reqd: 1,
hidden: 1,
default: frm.doc.company,
},
}
],
primary_action: function() {
let data = d.get_values();
var data = d.get_values();
if (!data.template_type) {
frappe.throw(__('Please select <b>Template Type</b> to download template'));
@@ -74,8 +66,7 @@ frappe.ui.form.on('Chart of Accounts Importer', {
'/api/method/erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.download_template',
{
file_type: data.file_type,
template_type: data.template_type,
company: data.company
template_type: data.template_type
}
);

View File

@@ -8,7 +8,6 @@ from functools import reduce
import frappe
from frappe import _
from frappe.desk.form.linked_with import get_linked_fields
from frappe.model.document import Document
from frappe.utils import cint, cstr
from frappe.utils.csvutils import UnicodeWriter
@@ -24,18 +23,6 @@ from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import
class ChartofAccountsImporter(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
company: DF.Link | None
import_file: DF.Attach | None
# end: auto-generated types
def validate(self):
if self.import_file:
get_coa(
@@ -125,7 +112,7 @@ def generate_data_from_csv(file_doc, as_dict=False):
if as_dict:
data.append({frappe.scrub(header): row[index] for index, header in enumerate(headers)})
else:
if not row[1] and len(row) > 1:
if not row[1]:
row[1] = row[0]
row[3] = row[2]
data.append(row)
@@ -307,8 +294,10 @@ def build_response_as_excel(writer):
@frappe.whitelist()
def download_template(file_type, template_type, company):
writer = get_template(template_type, company)
def download_template(file_type, template_type):
data = frappe._dict(frappe.local.form_dict)
writer = get_template(template_type)
if file_type == "CSV":
# download csv file
@@ -319,7 +308,8 @@ def download_template(file_type, template_type, company):
build_response_as_excel(writer)
def get_template(template_type, company):
def get_template(template_type):
fields = [
"Account Name",
"Parent Account",
@@ -345,17 +335,34 @@ def get_template(template_type, company):
["", "", "", "", 0, account_type.get("account_type"), account_type.get("root_type")]
)
else:
writer = get_sample_template(writer, company)
writer = get_sample_template(writer)
return writer
def get_sample_template(writer, company):
currency = frappe.db.get_value("Company", company, "default_currency")
with open(os.path.join(os.path.dirname(__file__), "coa_sample_template.csv"), "r") as f:
for row in f:
row = row.strip().split(",") + [currency]
writer.writerow(row)
def get_sample_template(writer):
template = [
["Application Of Funds(Assets)", "", "", "", 1, "", "Asset"],
["Sources Of Funds(Liabilities)", "", "", "", 1, "", "Liability"],
["Equity", "", "", "", 1, "", "Equity"],
["Expenses", "", "", "", 1, "", "Expense"],
["Income", "", "", "", 1, "", "Income"],
["Bank Accounts", "Application Of Funds(Assets)", "", "", 1, "Bank", "Asset"],
["Cash In Hand", "Application Of Funds(Assets)", "", "", 1, "Cash", "Asset"],
["Stock Assets", "Application Of Funds(Assets)", "", "", 1, "Stock", "Asset"],
["Cost Of Goods Sold", "Expenses", "", "", 0, "Cost of Goods Sold", "Expense"],
["Asset Depreciation", "Expenses", "", "", 0, "Depreciation", "Expense"],
["Fixed Assets", "Application Of Funds(Assets)", "", "", 0, "Fixed Asset", "Asset"],
["Accounts Payable", "Sources Of Funds(Liabilities)", "", "", 0, "Payable", "Liability"],
["Accounts Receivable", "Application Of Funds(Assets)", "", "", 1, "Receivable", "Asset"],
["Stock Expenses", "Expenses", "", "", 0, "Stock Adjustment", "Expense"],
["Sample Bank", "Bank Accounts", "", "", 0, "Bank", "Asset"],
["Cash", "Cash In Hand", "", "", 0, "Cash", "Asset"],
["Stores", "Stock Assets", "", "", 0, "Stock", "Asset"],
]
for row in template:
writer.writerow(row)
return writer
@@ -446,11 +453,14 @@ def get_mandatory_account_types():
def unset_existing_data(company):
# remove accounts data from company
linked = frappe.db.sql(
'''select fieldname from tabDocField
where fieldtype="Link" and options="Account" and parent="Company"''',
as_dict=True,
)
fieldnames = get_linked_fields("Account").get("Company", {}).get("fieldname", [])
linked = [{"fieldname": name} for name in fieldnames]
update_values = {d.get("fieldname"): "" for d in linked}
# remove accounts data from company
update_values = {d.fieldname: "" for d in linked}
frappe.db.set_value("Company", company, update_values, update_values)
# remove accounts data from various doctypes

View File

@@ -1,17 +0,0 @@
Application Of Funds(Assets),,,,1,,Asset
Sources Of Funds(Liabilities),,,,1,,Liability
Equity,,,,1,,Equity
Expenses,,,,1,Expense Account,Expense
Income,,,,1,Income Account,Income
Bank Accounts,Application Of Funds(Assets),,,1,Bank,Asset
Cash In Hand,Application Of Funds(Assets),,,1,Cash,Asset
Stock Assets,Application Of Funds(Assets),,,1,Stock,Asset
Cost Of Goods Sold,Expenses,,,0,Cost of Goods Sold,Expense
Asset Depreciation,Expenses,,,0,Depreciation,Expense
Fixed Assets,Application Of Funds(Assets),,,0,Fixed Asset,Asset
Accounts Payable,Sources Of Funds(Liabilities),,,0,Payable,Liability
Accounts Receivable,Application Of Funds(Assets),,,1,Receivable,Asset
Stock Expenses,Expenses,,,0,Stock Adjustment,Expense
Sample Bank,Bank Accounts,,,0,Bank,Asset
Cash,Cash In Hand,,,0,Cash,Asset
Stores,Stock Assets,,,0,Stock,Asset
1 Application Of Funds(Assets) 1 Asset
2 Sources Of Funds(Liabilities) 1 Liability
3 Equity 1 Equity
4 Expenses 1 Expense Account Expense
5 Income 1 Income Account Income
6 Bank Accounts Application Of Funds(Assets) 1 Bank Asset
7 Cash In Hand Application Of Funds(Assets) 1 Cash Asset
8 Stock Assets Application Of Funds(Assets) 1 Stock Asset
9 Cost Of Goods Sold Expenses 0 Cost of Goods Sold Expense
10 Asset Depreciation Expenses 0 Depreciation Expense
11 Fixed Assets Application Of Funds(Assets) 0 Fixed Asset Asset
12 Accounts Payable Sources Of Funds(Liabilities) 0 Payable Liability
13 Accounts Receivable Application Of Funds(Assets) 1 Receivable Asset
14 Stock Expenses Expenses 0 Stock Adjustment Expense
15 Sample Bank Bank Accounts 0 Bank Asset
16 Cash Cash In Hand 0 Cash Asset
17 Stores Stock Assets 0 Stock Asset

View File

@@ -8,41 +8,6 @@ from frappe.model.document import Document
class ChequePrintTemplate(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
acc_no_dist_from_left_edge: DF.Float
acc_no_dist_from_top_edge: DF.Float
acc_pay_dist_from_left_edge: DF.Float
acc_pay_dist_from_top_edge: DF.Float
amt_in_figures_from_left_edge: DF.Float
amt_in_figures_from_top_edge: DF.Float
amt_in_word_width: DF.Float
amt_in_words_from_left_edge: DF.Float
amt_in_words_from_top_edge: DF.Float
amt_in_words_line_spacing: DF.Float
bank_name: DF.Data
cheque_height: DF.Float
cheque_size: DF.Literal["", "Regular", "A4"]
cheque_width: DF.Float
date_dist_from_left_edge: DF.Float
date_dist_from_top_edge: DF.Float
has_print_format: DF.Check
is_account_payable: DF.Check
message_to_show: DF.Data | None
payer_name_from_left_edge: DF.Float
payer_name_from_top_edge: DF.Float
scanned_cheque: DF.Attach | None
signatory_from_left_edge: DF.Float
signatory_from_top_edge: DF.Float
starting_position_from_top_edge: DF.Float
# end: auto-generated types
pass

View File

@@ -6,19 +6,4 @@ from frappe.model.document import Document
class ClosedDocument(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
closed: DF.Check
document_type: DF.Link
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
# end: auto-generated types
pass

View File

@@ -10,25 +10,6 @@ from erpnext.accounts.utils import validate_field_number
class CostCenter(NestedSet):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
company: DF.Link
cost_center_name: DF.Data
cost_center_number: DF.Data | None
disabled: DF.Check
is_group: DF.Check
lft: DF.Int
old_parent: DF.Link | None
parent_cost_center: DF.Link
rgt: DF.Int
# end: auto-generated types
nsm_parent_field = "parent_cost_center"
def autoname(self):

View File

@@ -28,25 +28,6 @@ class InvalidDateError(frappe.ValidationError):
class CostCenterAllocation(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.cost_center_allocation_percentage.cost_center_allocation_percentage import (
CostCenterAllocationPercentage,
)
allocation_percentages: DF.Table[CostCenterAllocationPercentage]
amended_from: DF.Link | None
company: DF.Link
main_cost_center: DF.Link
valid_from: DF.Date
# end: auto-generated types
def __init__(self, *args, **kwargs):
super(CostCenterAllocation, self).__init__(*args, **kwargs)
self._skip_from_date_validation = False

View File

@@ -6,19 +6,4 @@ from frappe.model.document import Document
class CostCenterAllocationPercentage(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
cost_center: DF.Link
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
percentage: DF.Percent
# end: auto-generated types
pass

View File

@@ -9,27 +9,6 @@ from frappe.utils import strip
class CouponCode(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
amended_from: DF.Link | None
coupon_code: DF.Data | None
coupon_name: DF.Data
coupon_type: DF.Literal["Promotional", "Gift Card"]
customer: DF.Link | None
description: DF.TextEditor | None
maximum_use: DF.Int
pricing_rule: DF.Link
used: DF.Int
valid_from: DF.Date | None
valid_upto: DF.Date | None
# end: auto-generated types
def autoname(self):
self.coupon_name = strip(self.coupon_name)
self.name = self.coupon_name

View File

@@ -9,30 +9,6 @@ from frappe.utils import nowdate
class CurrencyExchangeSettings(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.currency_exchange_settings_details.currency_exchange_settings_details import (
CurrencyExchangeSettingsDetails,
)
from erpnext.accounts.doctype.currency_exchange_settings_result.currency_exchange_settings_result import (
CurrencyExchangeSettingsResult,
)
access_key: DF.Data | None
api_endpoint: DF.Data
disabled: DF.Check
req_params: DF.Table[CurrencyExchangeSettingsDetails]
result_key: DF.Table[CurrencyExchangeSettingsResult]
service_provider: DF.Literal["frankfurter.app", "exchangerate.host", "Custom"]
url: DF.Data | None
# end: auto-generated types
def validate(self):
self.set_parameters_and_result()
if frappe.flags.in_test or frappe.flags.in_install or frappe.flags.in_setup_wizard:

View File

@@ -6,19 +6,4 @@ from frappe.model.document import Document
class CurrencyExchangeSettingsDetails(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
key: DF.Data
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
value: DF.Data
# end: auto-generated types
pass

View File

@@ -6,18 +6,4 @@ from frappe.model.document import Document
class CurrencyExchangeSettingsResult(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
key: DF.Data
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
# end: auto-generated types
pass

View File

@@ -6,18 +6,4 @@ from frappe.model.document import Document
class CustomerGroupItem(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
customer_group: DF.Link | None
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
# end: auto-generated types
pass

View File

@@ -6,18 +6,4 @@ from frappe.model.document import Document
class CustomerItem(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
customer: DF.Link | None
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
# end: auto-generated types
pass

View File

@@ -7,22 +7,4 @@ from frappe.model.document import Document
class DiscountedInvoice(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
customer: DF.Link | None
debit_to: DF.Link | None
outstanding_amount: DF.Currency
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
posting_date: DF.Date | None
sales_invoice: DF.Link
# end: auto-generated types
pass

View File

@@ -22,52 +22,6 @@ from erpnext.controllers.accounts_controller import AccountsController
class Dunning(AccountsController):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.overdue_payment.overdue_payment import OverduePayment
address_display: DF.SmallText | None
amended_from: DF.Link | None
base_dunning_amount: DF.Currency
body_text: DF.TextEditor | None
closing_text: DF.TextEditor | None
company: DF.Link
company_address: DF.Link | None
company_address_display: DF.SmallText | None
contact_display: DF.SmallText | None
contact_email: DF.Data | None
contact_mobile: DF.SmallText | None
contact_person: DF.Link | None
conversion_rate: DF.Float
cost_center: DF.Link | None
currency: DF.Link | None
customer: DF.Link
customer_address: DF.Link | None
customer_name: DF.Data | None
dunning_amount: DF.Currency
dunning_fee: DF.Currency
dunning_type: DF.Link | None
grand_total: DF.Currency
income_account: DF.Link | None
language: DF.Link | None
letter_head: DF.Link | None
naming_series: DF.Literal["DUNN-.MM.-.YY.-"]
overdue_payments: DF.Table[OverduePayment]
posting_date: DF.Date
posting_time: DF.Time | None
rate_of_interest: DF.Float
spacer: DF.Data | None
status: DF.Literal["Draft", "Resolved", "Unresolved", "Cancelled"]
total_interest: DF.Currency
total_outstanding: DF.Currency
# end: auto-generated types
def validate(self):
self.validate_same_currency()
self.validate_overdue_payments()

View File

@@ -7,21 +7,4 @@ from frappe.model.document import Document
class DunningLetterText(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
body_text: DF.TextEditor | None
closing_text: DF.TextEditor | None
is_default_language: DF.Check
language: DF.Link | None
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
# end: auto-generated types
pass

View File

@@ -7,26 +7,6 @@ from frappe.model.document import Document
class DunningType(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.dunning_letter_text.dunning_letter_text import DunningLetterText
company: DF.Link
cost_center: DF.Link | None
dunning_fee: DF.Currency
dunning_letter_text: DF.Table[DunningLetterText]
dunning_type: DF.Data
income_account: DF.Link | None
is_default: DF.Check
rate_of_interest: DF.Float
# end: auto-generated types
def autoname(self):
company_abbr = frappe.get_value("Company", self.company, "abbr")
self.name = f"{self.dunning_type} - {company_abbr}"

View File

@@ -17,28 +17,6 @@ from erpnext.setup.utils import get_exchange_rate
class ExchangeRateRevaluation(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.exchange_rate_revaluation_account.exchange_rate_revaluation_account import (
ExchangeRateRevaluationAccount,
)
accounts: DF.Table[ExchangeRateRevaluationAccount]
amended_from: DF.Link | None
company: DF.Link
gain_loss_booked: DF.Currency
gain_loss_unbooked: DF.Currency
posting_date: DF.Date
rounding_loss_allowance: DF.Float
total_gain_loss: DF.Currency
# end: auto-generated types
def validate(self):
self.validate_rounding_loss_allowance()
self.set_total_gain_loss()
@@ -214,7 +192,7 @@ class ExchangeRateRevaluation(Document):
# round off balance based on currency precision
# and consider debit-credit difference allowance
currency_precision = get_currency_precision()
rounding_loss_allowance = float(rounding_loss_allowance)
rounding_loss_allowance = float(rounding_loss_allowance) or 0.05
for acc in account_details:
acc.balance_in_account_currency = flt(acc.balance_in_account_currency, currency_precision)
if abs(acc.balance_in_account_currency) <= rounding_loss_allowance:

View File

@@ -6,29 +6,4 @@ from frappe.model.document import Document
class ExchangeRateRevaluationAccount(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
account: DF.Link
account_currency: DF.Link | None
balance_in_account_currency: DF.Currency
balance_in_base_currency: DF.Currency
current_exchange_rate: DF.Float
gain_loss: DF.Currency
new_balance_in_account_currency: DF.Currency
new_balance_in_base_currency: DF.Currency
new_exchange_rate: DF.Float
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
party: DF.DynamicLink | None
party_type: DF.Link | None
zero_balance: DF.Check
# end: auto-generated types
pass

View File

@@ -6,15 +6,4 @@ from frappe.model.document import Document
class FinanceBook(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
finance_book_name: DF.Data | None
# end: auto-generated types
pass

View File

@@ -10,25 +10,6 @@ from frappe.utils import add_days, add_years, cstr, getdate
class FiscalYear(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.fiscal_year_company.fiscal_year_company import FiscalYearCompany
auto_created: DF.Check
companies: DF.Table[FiscalYearCompany]
disabled: DF.Check
is_short_year: DF.Check
year: DF.Data
year_end_date: DF.Date
year_start_date: DF.Date
# end: auto-generated types
def validate(self):
self.validate_dates()
self.validate_overlap()

View File

@@ -6,18 +6,4 @@ from frappe.model.document import Document
class FiscalYearCompany(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
company: DF.Link | None
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
# end: auto-generated types
pass

View File

@@ -142,7 +142,8 @@
"label": "Against Voucher Type",
"oldfieldname": "against_voucher_type",
"oldfieldtype": "Data",
"options": "DocType"
"options": "DocType",
"search_index": 1
},
{
"fieldname": "against_voucher",
@@ -161,7 +162,8 @@
"label": "Voucher Type",
"oldfieldname": "voucher_type",
"oldfieldtype": "Select",
"options": "DocType"
"options": "DocType",
"search_index": 1
},
{
"fieldname": "voucher_no",
@@ -319,4 +321,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}
}

View File

@@ -28,47 +28,6 @@ exclude_from_linked_with = True
class GLEntry(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
account: DF.Link | None
account_currency: DF.Link | None
against: DF.Text | None
against_voucher: DF.DynamicLink | None
against_voucher_type: DF.Link | None
company: DF.Link | None
cost_center: DF.Link | None
credit: DF.Currency
credit_in_account_currency: DF.Currency
credit_in_transaction_currency: DF.Currency
debit: DF.Currency
debit_in_account_currency: DF.Currency
debit_in_transaction_currency: DF.Currency
due_date: DF.Date | None
finance_book: DF.Link | None
fiscal_year: DF.Link | None
is_advance: DF.Literal["No", "Yes"]
is_cancelled: DF.Check
is_opening: DF.Literal["No", "Yes"]
party: DF.DynamicLink | None
party_type: DF.Link | None
posting_date: DF.Date | None
project: DF.Link | None
remarks: DF.Text | None
to_rename: DF.Check
transaction_currency: DF.Link | None
transaction_date: DF.Date | None
transaction_exchange_rate: DF.Float
voucher_detail_no: DF.Data | None
voucher_no: DF.DynamicLink | None
voucher_type: DF.Link | None
# end: auto-generated types
def autoname(self):
"""
Temporarily name doc for fast insertion

View File

@@ -17,34 +17,6 @@ from erpnext.controllers.accounts_controller import AccountsController
class InvoiceDiscounting(AccountsController):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.discounted_invoice.discounted_invoice import DiscountedInvoice
accounts_receivable_credit: DF.Link
accounts_receivable_discounted: DF.Link
accounts_receivable_unpaid: DF.Link
amended_from: DF.Link | None
bank_account: DF.Link
bank_charges: DF.Currency
bank_charges_account: DF.Link
company: DF.Link
invoices: DF.Table[DiscountedInvoice]
loan_end_date: DF.Date | None
loan_period: DF.Int
loan_start_date: DF.Date | None
posting_date: DF.Date
short_term_loan: DF.Link
status: DF.Literal["Draft", "Sanctioned", "Disbursed", "Settled", "Cancelled"]
total_amount: DF.Currency
# end: auto-generated types
def validate(self):
self.validate_mandatory()
self.validate_invoices()

View File

@@ -8,24 +8,6 @@ from frappe.model.document import Document
class ItemTaxTemplate(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.item_tax_template_detail.item_tax_template_detail import (
ItemTaxTemplateDetail,
)
company: DF.Link
disabled: DF.Check
taxes: DF.Table[ItemTaxTemplateDetail]
title: DF.Data
# end: auto-generated types
def validate(self):
self.validate_tax_accounts()

View File

@@ -6,19 +6,4 @@ from frappe.model.document import Document
class ItemTaxTemplateDetail(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
tax_rate: DF.Float
tax_type: DF.Link
# end: auto-generated types
pass

View File

@@ -8,7 +8,7 @@ frappe.provide("erpnext.journal_entry");
frappe.ui.form.on("Journal Entry", {
setup: function(frm) {
frm.add_fetch("bank_account", "account", "account");
frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', "Repost Payment Ledger", 'Asset', 'Asset Movement', 'Asset Depreciation Schedule', "Repost Accounting Ledger", "Unreconcile Payment", "Unreconcile Payment Entries"];
frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', "Repost Payment Ledger", 'Asset', 'Asset Movement', 'Asset Depreciation Schedule', "Repost Accounting Ledger"];
},
refresh: function(frm) {
@@ -51,7 +51,7 @@ frappe.ui.form.on("Journal Entry", {
}, __('Make'));
}
erpnext.accounts.unreconcile_payment.add_unreconcile_btn(frm);
erpnext.accounts.unreconcile_payments.add_unreconcile_btn(frm);
},
before_save: function(frm) {
if ((frm.doc.docstatus == 0) && (!frm.doc.is_system_generated)) {

View File

@@ -548,16 +548,8 @@
"icon": "fa fa-file-text",
"idx": 176,
"is_submittable": 1,
"links": [
{
"is_child_table": 1,
"link_doctype": "Bank Transaction Payments",
"link_fieldname": "payment_entry",
"parent_doctype": "Bank Transaction",
"table_fieldname": "payment_entries"
}
],
"modified": "2023-11-23 12:11:04.128015",
"links": [],
"modified": "2023-08-10 14:32:22.366895",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry",

View File

@@ -35,78 +35,6 @@ class StockAccountInvalidTransaction(frappe.ValidationError):
class JournalEntry(AccountsController):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.journal_entry_account.journal_entry_account import (
JournalEntryAccount,
)
accounts: DF.Table[JournalEntryAccount]
amended_from: DF.Link | None
apply_tds: DF.Check
auto_repeat: DF.Link | None
bill_date: DF.Date | None
bill_no: DF.Data | None
cheque_date: DF.Date | None
cheque_no: DF.Data | None
clearance_date: DF.Date | None
company: DF.Link
difference: DF.Currency
due_date: DF.Date | None
finance_book: DF.Link | None
from_template: DF.Link | None
inter_company_journal_entry_reference: DF.Link | None
is_opening: DF.Literal["No", "Yes"]
is_system_generated: DF.Check
letter_head: DF.Link | None
mode_of_payment: DF.Link | None
multi_currency: DF.Check
naming_series: DF.Literal["ACC-JV-.YYYY.-"]
paid_loan: DF.Data | None
pay_to_recd_from: DF.Data | None
payment_order: DF.Link | None
posting_date: DF.Date
process_deferred_accounting: DF.Link | None
remark: DF.SmallText | None
reversal_of: DF.Link | None
select_print_heading: DF.Link | None
stock_entry: DF.Link | None
tax_withholding_category: DF.Link | None
title: DF.Data | None
total_amount: DF.Currency
total_amount_currency: DF.Link | None
total_amount_in_words: DF.Data | None
total_credit: DF.Currency
total_debit: DF.Currency
user_remark: DF.SmallText | None
voucher_type: DF.Literal[
"Journal Entry",
"Inter Company Journal Entry",
"Bank Entry",
"Cash Entry",
"Credit Card Entry",
"Debit Note",
"Credit Note",
"Contra Entry",
"Excise Entry",
"Write Off Entry",
"Opening Entry",
"Depreciation Entry",
"Exchange Rate Revaluation",
"Exchange Gain Or Loss",
"Deferred Revenue",
"Deferred Expense",
]
write_off_amount: DF.Currency
write_off_based_on: DF.Literal["Accounts Receivable", "Accounts Payable"]
# end: auto-generated types
def __init__(self, *args, **kwargs):
super(JournalEntry, self).__init__(*args, **kwargs)
@@ -170,8 +98,6 @@ class JournalEntry(AccountsController):
"Repost Payment Ledger Items",
"Repost Accounting Ledger",
"Repost Accounting Ledger Items",
"Unreconcile Payment",
"Unreconcile Payment Entries",
)
self.make_gl_entries(1)
self.update_advance_paid()
@@ -582,7 +508,7 @@ class JournalEntry(AccountsController):
).format(d.reference_name, d.account)
)
else:
dr_or_cr = "debit" if flt(d.credit) > 0 else "credit"
dr_or_cr = "debit" if d.credit > 0 else "credit"
valid = False
for jvd in against_entries:
if flt(jvd[dr_or_cr]) > 0:
@@ -942,7 +868,7 @@ class JournalEntry(AccountsController):
party_account_currency = d.account_currency
elif frappe.get_cached_value("Account", d.account, "account_type") in ["Bank", "Cash"]:
bank_amount += flt(d.debit_in_account_currency) or flt(d.credit_in_account_currency)
bank_amount += d.debit_in_account_currency or d.credit_in_account_currency
bank_account_currency = d.account_currency
if party_type and pay_to_recd_from:

View File

@@ -1,94 +1,97 @@
[
{
"cheque_date": "2013-03-14",
"cheque_no": "33",
"company": "_Test Company",
"doctype": "Journal Entry",
"accounts": [
{
"account": "Debtors - _TC",
"party_type": "Customer",
"party": "_Test Customer",
"credit_in_account_currency": 400.0,
"debit_in_account_currency": 0.0,
"doctype": "Journal Entry Account",
"parentfield": "accounts",
"cost_center": "_Test Cost Center - _TC"
},
{
"account": "_Test Bank - _TC",
"credit_in_account_currency": 0.0,
"debit_in_account_currency": 400.0,
"doctype": "Journal Entry Account",
"parentfield": "accounts",
"cost_center": "_Test Cost Center - _TC"
}
],
"naming_series": "_T-Journal Entry-",
"posting_date": "2013-02-14",
"user_remark": "test",
"voucher_type": "Bank Entry"
},
{
"cheque_date": "2013-02-14",
"cheque_no": "33",
"company": "_Test Company",
"doctype": "Journal Entry",
"accounts": [
{
"account": "_Test Payable - _TC",
"party_type": "Supplier",
"party": "_Test Supplier",
"credit_in_account_currency": 0.0,
"debit_in_account_currency": 400.0,
"doctype": "Journal Entry Account",
"parentfield": "accounts",
"cost_center": "_Test Cost Center - _TC"
},
{
"account": "_Test Bank - _TC",
"credit_in_account_currency": 400.0,
"debit_in_account_currency": 0.0,
"doctype": "Journal Entry Account",
"parentfield": "accounts",
"cost_center": "_Test Cost Center - _TC"
}
],
"naming_series": "_T-Journal Entry-",
"posting_date": "2013-02-14",
"user_remark": "test",
"voucher_type": "Bank Entry"
},
{
"cheque_date": "2013-02-14",
"cheque_no": "33",
"company": "_Test Company",
"doctype": "Journal Entry",
"accounts": [
{
"account": "Debtors - _TC",
"party_type": "Customer",
"party": "_Test Customer",
"credit_in_account_currency": 0.0,
"debit_in_account_currency": 400.0,
"doctype": "Journal Entry Account",
"parentfield": "accounts",
"cost_center": "_Test Cost Center - _TC"
},
{
"account": "Sales - _TC",
"credit_in_account_currency": 400.0,
"debit_in_account_currency": 0.0,
"doctype": "Journal Entry Account",
"parentfield": "accounts",
"cost_center": "_Test Cost Center - _TC"
}
],
"naming_series": "_T-Journal Entry-",
"posting_date": "2013-02-14",
"user_remark": "test",
"voucher_type": "Bank Entry"
}
{
"cheque_date": "2013-03-14",
"cheque_no": "33",
"company": "_Test Company",
"doctype": "Journal Entry",
"accounts": [
{
"account": "Debtors - _TC",
"party_type": "Customer",
"party": "_Test Customer",
"credit_in_account_currency": 400.0,
"debit_in_account_currency": 0.0,
"doctype": "Journal Entry Account",
"parentfield": "accounts",
"cost_center": "_Test Cost Center - _TC"
},
{
"account": "_Test Bank - _TC",
"credit_in_account_currency": 0.0,
"debit_in_account_currency": 400.0,
"doctype": "Journal Entry Account",
"parentfield": "accounts",
"cost_center": "_Test Cost Center - _TC"
}
],
"naming_series": "_T-Journal Entry-",
"posting_date": "2013-02-14",
"user_remark": "test",
"voucher_type": "Bank Entry"
},
{
"cheque_date": "2013-02-14",
"cheque_no": "33",
"company": "_Test Company",
"doctype": "Journal Entry",
"accounts": [
{
"account": "_Test Payable - _TC",
"party_type": "Supplier",
"party": "_Test Supplier",
"credit_in_account_currency": 0.0,
"debit_in_account_currency": 400.0,
"doctype": "Journal Entry Account",
"parentfield": "accounts",
"cost_center": "_Test Cost Center - _TC"
},
{
"account": "_Test Bank - _TC",
"credit_in_account_currency": 400.0,
"debit_in_account_currency": 0.0,
"doctype": "Journal Entry Account",
"parentfield": "accounts",
"cost_center": "_Test Cost Center - _TC"
}
],
"naming_series": "_T-Journal Entry-",
"posting_date": "2013-02-14",
"user_remark": "test",
"voucher_type": "Bank Entry"
},
{
"cheque_date": "2013-02-14",
"cheque_no": "33",
"company": "_Test Company",
"doctype": "Journal Entry",
"accounts": [
{
"account": "Debtors - _TC",
"party_type": "Customer",
"party": "_Test Customer",
"credit_in_account_currency": 0.0,
"debit_in_account_currency": 400.0,
"doctype": "Journal Entry Account",
"parentfield": "accounts",
"cost_center": "_Test Cost Center - _TC"
},
{
"account": "Sales - _TC",
"cost_center": "_Test Cost Center - _TC",
"credit_in_account_currency": 400.0,
"debit_in_account_currency": 0.0,
"doctype": "Journal Entry Account",
"parentfield": "accounts",
"cost_center": "_Test Cost Center - _TC"
}
],
"naming_series": "_T-Journal Entry-",
"posting_date": "2013-02-14",
"user_remark": "test",
"voucher_type": "Bank Entry"
}
]

View File

@@ -203,8 +203,7 @@
"fieldtype": "Select",
"label": "Reference Type",
"no_copy": 1,
"options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation\nInvoice Discounting\nFees\nFull and Final Statement\nPayment Entry",
"search_index": 1
"options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation\nInvoice Discounting\nFees\nFull and Final Statement\nPayment Entry"
},
{
"fieldname": "reference_name",
@@ -212,8 +211,7 @@
"in_list_view": 1,
"label": "Reference Name",
"no_copy": 1,
"options": "reference_type",
"search_index": 1
"options": "reference_type"
},
{
"depends_on": "eval:doc.reference_type&&!in_list(doc.reference_type, ['Expense Claim', 'Asset', 'Employee Loan', 'Employee Advance'])",
@@ -280,14 +278,13 @@
"fieldtype": "Data",
"hidden": 1,
"label": "Reference Detail No",
"no_copy": 1,
"search_index": 1
"no_copy": 1
}
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2023-11-23 11:44:25.841187",
"modified": "2023-06-16 14:11:13.507807",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry Account",

View File

@@ -6,56 +6,4 @@ from frappe.model.document import Document
class JournalEntryAccount(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
account: DF.Link
account_currency: DF.Link | None
account_type: DF.Data | None
against_account: DF.Text | None
balance: DF.Currency
bank_account: DF.Link | None
cost_center: DF.Link | None
credit: DF.Currency
credit_in_account_currency: DF.Currency
debit: DF.Currency
debit_in_account_currency: DF.Currency
exchange_rate: DF.Float
is_advance: DF.Literal["No", "Yes"]
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
party: DF.DynamicLink | None
party_balance: DF.Currency
party_type: DF.Link | None
project: DF.Link | None
reference_detail_no: DF.Data | None
reference_due_date: DF.Date | None
reference_name: DF.DynamicLink | None
reference_type: DF.Literal[
"",
"Sales Invoice",
"Purchase Invoice",
"Journal Entry",
"Sales Order",
"Purchase Order",
"Expense Claim",
"Asset",
"Loan",
"Payroll Entry",
"Employee Advance",
"Exchange Rate Revaluation",
"Invoice Discounting",
"Fees",
"Full and Final Statement",
"Payment Entry",
]
user_remark: DF.SmallText | None
# end: auto-generated types
pass

View File

@@ -7,41 +7,6 @@ from frappe.model.document import Document
class JournalEntryTemplate(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.journal_entry_template_account.journal_entry_template_account import (
JournalEntryTemplateAccount,
)
accounts: DF.Table[JournalEntryTemplateAccount]
company: DF.Link
is_opening: DF.Literal["No", "Yes"]
multi_currency: DF.Check
naming_series: DF.Literal
template_title: DF.Data
voucher_type: DF.Literal[
"Journal Entry",
"Inter Company Journal Entry",
"Bank Entry",
"Cash Entry",
"Credit Card Entry",
"Debit Note",
"Credit Note",
"Contra Entry",
"Excise Entry",
"Write Off Entry",
"Opening Entry",
"Depreciation Entry",
"Exchange Rate Revaluation",
]
# end: auto-generated types
pass

View File

@@ -7,18 +7,4 @@ from frappe.model.document import Document
class JournalEntryTemplateAccount(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
account: DF.Link
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
# end: auto-generated types
pass

View File

@@ -10,27 +10,6 @@ from erpnext.accounts.doctype.account.account import merge_account
class LedgerMerge(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.ledger_merge_accounts.ledger_merge_accounts import (
LedgerMergeAccounts,
)
account: DF.Link
account_name: DF.Data
company: DF.Link
is_group: DF.Check
merge_accounts: DF.Table[LedgerMergeAccounts]
root_type: DF.Literal["", "Asset", "Liability", "Income", "Expense", "Equity"]
status: DF.Literal["Pending", "Success", "Partial Success", "Error"]
# end: auto-generated types
def start_merge(self):
from frappe.utils.background_jobs import enqueue
from frappe.utils.scheduler import is_scheduler_inactive

View File

@@ -6,20 +6,4 @@ from frappe.model.document import Document
class LedgerMergeAccounts(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
account: DF.Link
account_name: DF.Data
merged: DF.Check
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
# end: auto-generated types
pass

View File

@@ -10,27 +10,6 @@ exclude_from_linked_with = True
class LoyaltyPointEntry(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
company: DF.Link | None
customer: DF.Link | None
expiry_date: DF.Date | None
invoice: DF.DynamicLink | None
invoice_type: DF.Link | None
loyalty_points: DF.Int
loyalty_program: DF.Link | None
loyalty_program_tier: DF.Data | None
posting_date: DF.Date | None
purchase_amount: DF.Currency
redeem_against: DF.Link | None
# end: auto-generated types
pass

View File

@@ -6,20 +6,4 @@ from frappe.model.document import Document
class LoyaltyPointEntryRedemption(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
redeemed_points: DF.Int
redemption_date: DF.Date | None
sales_invoice: DF.Data | None
# end: auto-generated types
pass

View File

@@ -9,33 +9,6 @@ from frappe.utils import flt, today
class LoyaltyProgram(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.loyalty_program_collection.loyalty_program_collection import (
LoyaltyProgramCollection,
)
auto_opt_in: DF.Check
collection_rules: DF.Table[LoyaltyProgramCollection]
company: DF.Link | None
conversion_factor: DF.Float
cost_center: DF.Link | None
customer_group: DF.Link | None
customer_territory: DF.Link | None
expense_account: DF.Link | None
expiry_duration: DF.Int
from_date: DF.Date
loyalty_program_name: DF.Data
loyalty_program_type: DF.Literal["Single Tier Program", "Multiple Tier Program"]
to_date: DF.Date | None
# end: auto-generated types
pass

View File

@@ -6,20 +6,4 @@ from frappe.model.document import Document
class LoyaltyProgramCollection(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
collection_factor: DF.Currency
min_spent: DF.Currency
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
tier_name: DF.Data
# end: auto-generated types
pass

View File

@@ -8,24 +8,6 @@ from frappe.model.document import Document
class ModeofPayment(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.mode_of_payment_account.mode_of_payment_account import (
ModeofPaymentAccount,
)
accounts: DF.Table[ModeofPaymentAccount]
enabled: DF.Check
mode_of_payment: DF.Data
type: DF.Literal["Cash", "Bank", "General", "Phone"]
# end: auto-generated types
def validate(self):
self.validate_accounts()
self.validate_repeating_companies()

View File

@@ -6,19 +6,4 @@ from frappe.model.document import Document
class ModeofPaymentAccount(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
company: DF.Link | None
default_account: DF.Link | None
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
# end: auto-generated types
pass

View File

@@ -9,23 +9,6 @@ from frappe.utils import add_months, flt
class MonthlyDistribution(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.monthly_distribution_percentage.monthly_distribution_percentage import (
MonthlyDistributionPercentage,
)
distribution_id: DF.Data
fiscal_year: DF.Link | None
percentages: DF.Table[MonthlyDistributionPercentage]
# end: auto-generated types
@frappe.whitelist()
def get_months(self):
month_list = [

View File

@@ -6,19 +6,4 @@ from frappe.model.document import Document
class MonthlyDistributionPercentage(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
month: DF.Data
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
percentage_allocation: DF.Float
# end: auto-generated types
pass

View File

@@ -14,25 +14,6 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
class OpeningInvoiceCreationTool(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.opening_invoice_creation_tool_item.opening_invoice_creation_tool_item import (
OpeningInvoiceCreationToolItem,
)
company: DF.Link
cost_center: DF.Link | None
create_missing_party: DF.Check
invoice_type: DF.Literal["Sales", "Purchase"]
invoices: DF.Table[OpeningInvoiceCreationToolItem]
# end: auto-generated types
def onload(self):
"""Load the Opening Invoice summary"""
summary, max_count = self.get_opening_invoice_summary()

View File

@@ -6,27 +6,4 @@ from frappe.model.document import Document
class OpeningInvoiceCreationToolItem(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
cost_center: DF.Link | None
due_date: DF.Date | None
invoice_number: DF.Data | None
item_name: DF.Data | None
outstanding_amount: DF.Currency
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
party: DF.DynamicLink
party_type: DF.Link | None
posting_date: DF.Date | None
qty: DF.Data | None
temporary_opening_account: DF.Link | None
# end: auto-generated types
pass

View File

@@ -6,31 +6,4 @@ from frappe.model.document import Document
class OverduePayment(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
description: DF.SmallText | None
discounted_amount: DF.Currency
due_date: DF.Date | None
dunning_level: DF.Int
interest: DF.Currency
invoice_portion: DF.Percent
mode_of_payment: DF.Link | None
outstanding: DF.Currency
overdue_days: DF.Data | None
paid_amount: DF.Currency
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
payment_amount: DF.Currency
payment_schedule: DF.Data | None
payment_term: DF.Link | None
sales_invoice: DF.Link
# end: auto-generated types
pass

View File

@@ -6,20 +6,4 @@ from frappe.model.document import Document
class PartyAccount(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
account: DF.Link | None
advance_account: DF.Link | None
company: DF.Link
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
# end: auto-generated types
pass

View File

@@ -7,20 +7,6 @@ from frappe.model.document import Document
class PartyLink(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
primary_party: DF.DynamicLink | None
primary_role: DF.Link
secondary_party: DF.DynamicLink | None
secondary_role: DF.Link | None
# end: auto-generated types
def validate(self):
if self.primary_role not in ["Customer", "Supplier"]:
frappe.throw(

View File

@@ -9,7 +9,7 @@ erpnext.accounts.taxes.setup_tax_filters("Advance Taxes and Charges");
frappe.ui.form.on('Payment Entry', {
onload: function(frm) {
frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', 'Repost Payment Ledger','Repost Accounting Ledger', 'Unreconcile Payment', 'Unreconcile Payment Entries'];
frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', 'Repost Payment Ledger','Repost Accounting Ledger', 'Unreconcile Payments', 'Unreconcile Payment Entries'];
if(frm.doc.__islocal) {
if (!frm.doc.paid_from) frm.set_value("paid_from_account_currency", null);
@@ -154,13 +154,13 @@ frappe.ui.form.on('Payment Entry', {
frm.events.set_dynamic_labels(frm);
frm.events.show_general_ledger(frm);
erpnext.accounts.ledger_preview.show_accounting_ledger_preview(frm);
if((frm.doc.references) && (frm.doc.references.find((elem) => {return elem.exchange_gain_loss != 0}))) {
if(frm.doc.references.find((elem) => {return elem.exchange_gain_loss != 0})) {
frm.add_custom_button(__("View Exchange Gain/Loss Journals"), function() {
frappe.set_route("List", "Journal Entry", {"voucher_type": "Exchange Gain Or Loss", "reference_name": frm.doc.name});
}, __('Actions'));
}
erpnext.accounts.unreconcile_payment.add_unreconcile_btn(frm);
erpnext.accounts.unreconcile_payments.add_unreconcile_btn(frm);
},
validate_company: (frm) => {
@@ -853,7 +853,6 @@ frappe.ui.form.on('Payment Entry', {
var allocated_positive_outstanding = paid_amount + allocated_negative_outstanding;
} else if (in_list(["Customer", "Supplier"], frm.doc.party_type)) {
total_negative_outstanding = flt(total_negative_outstanding, precision("outstanding_amount"))
if(paid_amount > total_negative_outstanding) {
if(total_negative_outstanding == 0) {
frappe.msgprint(

View File

@@ -595,7 +595,6 @@
"fieldname": "status",
"fieldtype": "Select",
"label": "Status",
"no_copy": 1,
"options": "\nDraft\nSubmitted\nCancelled",
"read_only": 1
},
@@ -750,16 +749,8 @@
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [
{
"is_child_table": 1,
"link_doctype": "Bank Transaction Payments",
"link_fieldname": "payment_entry",
"parent_doctype": "Bank Transaction",
"table_fieldname": "payment_entries"
}
],
"modified": "2023-11-23 12:07:20.887885",
"links": [],
"modified": "2023-06-23 18:07:38.023010",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",

View File

@@ -9,8 +9,6 @@ import frappe
from frappe import ValidationError, _, qb, scrub, throw
from frappe.utils import cint, comma_or, flt, getdate, nowdate
from frappe.utils.data import comma_and, fmt_money
from pypika import Case
from pypika.functions import Coalesce, Sum
import erpnext
from erpnext.accounts.doctype.bank_account.bank_account import (
@@ -35,7 +33,6 @@ from erpnext.accounts.utils import (
get_account_currency,
get_balance_on,
get_outstanding_invoices,
get_party_types_from_account_type,
)
from erpnext.controllers.accounts_controller import (
AccountsController,
@@ -86,6 +83,7 @@ class PaymentEntry(AccountsController):
self.apply_taxes()
self.set_amounts_after_tax()
self.clear_unallocated_reference_document_rows()
self.validate_payment_against_negative_invoice()
self.validate_transaction_reference()
self.set_title()
self.set_remarks()
@@ -106,17 +104,9 @@ class PaymentEntry(AccountsController):
self.set_status()
def set_liability_account(self):
# Auto setting liability account should only be done during 'draft' status
if self.docstatus > 0:
if not self.book_advance_payments_in_separate_party_account:
return
if not frappe.db.get_value(
"Company", self.company, "book_advance_payments_in_separate_party_account"
):
return
# Important to set this flag for the gl building logic to work properly
self.book_advance_payments_in_separate_party_account = True
account_type = frappe.get_value(
"Account", {"name": self.party_account, "company": self.company}, "account_type"
)
@@ -126,13 +116,11 @@ class PaymentEntry(AccountsController):
):
return
if self.references:
allowed_types = frozenset(["Sales Order", "Purchase Order"])
reference_types = set([x.reference_doctype for x in self.references])
# If there are referencers other than `allowed_types`, treat this as a normal payment entry
if reference_types - allowed_types:
self.book_advance_payments_in_separate_party_account = False
if self.unallocated_amount == 0:
for d in self.references:
if d.reference_doctype in ["Sales Order", "Purchase Order"]:
break
else:
return
liability_account = get_party_account(
@@ -160,7 +148,7 @@ class PaymentEntry(AccountsController):
"Repost Payment Ledger Items",
"Repost Accounting Ledger",
"Repost Accounting Ledger Items",
"Unreconcile Payment",
"Unreconcile Payments",
"Unreconcile Payment Entries",
)
super(PaymentEntry, self).on_cancel()
@@ -964,6 +952,35 @@ class PaymentEntry(AccountsController):
self.name,
)
def validate_payment_against_negative_invoice(self):
if (self.payment_type != "Pay" or self.party_type != "Customer") and (
self.payment_type != "Receive" or self.party_type != "Supplier"
):
return
total_negative_outstanding = sum(
abs(flt(d.outstanding_amount)) for d in self.get("references") if flt(d.outstanding_amount) < 0
)
paid_amount = self.paid_amount if self.payment_type == "Receive" else self.received_amount
additional_charges = sum(flt(d.amount) for d in self.deductions)
if not total_negative_outstanding:
if self.party_type == "Customer":
msg = _("Cannot pay to Customer without any negative outstanding invoice")
else:
msg = _("Cannot receive from Supplier without any negative outstanding invoice")
frappe.throw(msg, InvalidPaymentEntry)
elif paid_amount - additional_charges > total_negative_outstanding:
frappe.throw(
_("Paid Amount cannot be greater than total negative outstanding amount {0}").format(
fmt_money(total_negative_outstanding)
),
InvalidPaymentEntry,
)
def set_title(self):
if frappe.flags.in_import and self.title:
# do not set title dynamically if title exists during data import.
@@ -1034,7 +1051,6 @@ class PaymentEntry(AccountsController):
self.add_bank_gl_entries(gl_entries)
self.add_deductions_gl_entries(gl_entries)
self.add_tax_gl_entries(gl_entries)
add_regional_gl_entries(gl_entries, self)
return gl_entries
def make_gl_entries(self, cancel=0, adv_adj=0):
@@ -1067,105 +1083,98 @@ class PaymentEntry(AccountsController):
item=self,
)
dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
if self.book_advance_payments_in_separate_party_account:
dr_or_cr = (
"credit" if erpnext.get_party_account_type(self.party_type) == "Receivable" else "debit"
)
for d in self.get("references"):
cost_center = self.cost_center
if d.reference_doctype == "Sales Invoice" and not cost_center:
cost_center = frappe.db.get_value(d.reference_doctype, d.reference_name, "cost_center")
gle = party_gl_dict.copy()
if self.payment_type == "Receive":
amount = self.base_paid_amount
else:
amount = self.base_received_amount
allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference(d)
if self.book_advance_payments_in_separate_party_account:
against_voucher_type = "Payment Entry"
against_voucher = self.name
else:
against_voucher_type = d.reference_doctype
against_voucher = d.reference_name
exchange_rate = self.get_exchange_rate()
amount_in_account_currency = amount * exchange_rate
gle.update(
{
dr_or_cr: amount,
dr_or_cr + "_in_account_currency": amount_in_account_currency,
"against_voucher_type": "Payment Entry",
"against_voucher": self.name,
"cost_center": self.cost_center,
dr_or_cr: allocated_amount_in_company_currency,
dr_or_cr + "_in_account_currency": d.allocated_amount,
"against_voucher_type": against_voucher_type,
"against_voucher": against_voucher,
"cost_center": cost_center,
}
)
gl_entries.append(gle)
else:
for d in self.get("references"):
# re-defining dr_or_cr for every reference in order to avoid the last value affecting calculation of reverse
dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
cost_center = self.cost_center
if d.reference_doctype == "Sales Invoice" and not cost_center:
cost_center = frappe.db.get_value(d.reference_doctype, d.reference_name, "cost_center")
gle = party_gl_dict.copy()
if self.unallocated_amount:
exchange_rate = self.get_exchange_rate()
base_unallocated_amount = self.unallocated_amount * exchange_rate
allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference(d)
reverse_dr_or_cr = 0
gle = party_gl_dict.copy()
gle.update(
{
dr_or_cr + "_in_account_currency": self.unallocated_amount,
dr_or_cr: base_unallocated_amount,
}
)
if d.reference_doctype in ["Sales Invoice", "Purchase Invoice"]:
is_return = frappe.db.get_value(d.reference_doctype, d.reference_name, "is_return")
payable_party_types = get_party_types_from_account_type("Payable")
receivable_party_types = get_party_types_from_account_type("Receivable")
if is_return and self.party_type in receivable_party_types and (self.payment_type == "Pay"):
reverse_dr_or_cr = 1
elif (
is_return and self.party_type in payable_party_types and (self.payment_type == "Receive")
):
reverse_dr_or_cr = 1
gl_entries.append(gle)
if is_return and not reverse_dr_or_cr:
dr_or_cr = "debit" if dr_or_cr == "credit" else "credit"
gle.update(
{
dr_or_cr: abs(allocated_amount_in_company_currency),
dr_or_cr + "_in_account_currency": abs(d.allocated_amount),
"against_voucher_type": d.reference_doctype,
"against_voucher": d.reference_name,
"cost_center": cost_center,
}
)
gl_entries.append(gle)
if self.unallocated_amount:
dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
exchange_rate = self.get_exchange_rate()
base_unallocated_amount = self.unallocated_amount * exchange_rate
gle = party_gl_dict.copy()
gle.update(
{
dr_or_cr + "_in_account_currency": self.unallocated_amount,
dr_or_cr: base_unallocated_amount,
}
)
gl_entries.append(gle)
def make_advance_gl_entries(
self, entry: object | dict = None, cancel: bool = 0, update_outstanding: str = "Yes"
):
gl_entries = []
self.add_advance_gl_entries(gl_entries, entry)
if cancel:
make_reverse_gl_entries(gl_entries, partial_cancel=True)
else:
make_gl_entries(gl_entries, update_outstanding=update_outstanding)
def add_advance_gl_entries(self, gl_entries: list, entry: object | dict | None):
"""
If 'entry' is passed, GL enties only for that reference is added.
"""
def make_advance_gl_entries(self, against_voucher_type=None, against_voucher=None, cancel=0):
if self.book_advance_payments_in_separate_party_account:
references = [x for x in self.get("references")]
if entry:
references = [x for x in self.get("references") if x.name == entry.name]
gl_entries = []
for d in self.get("references"):
if d.reference_doctype in ("Sales Invoice", "Purchase Invoice", "Journal Entry"):
if not (against_voucher_type and against_voucher) or (
d.reference_doctype == against_voucher_type and d.reference_name == against_voucher
):
self.make_invoice_liability_entry(gl_entries, d)
for ref in references:
if ref.reference_doctype in ("Sales Invoice", "Purchase Invoice", "Journal Entry"):
self.add_advance_gl_for_reference(gl_entries, ref)
if cancel:
for entry in gl_entries:
frappe.db.set_value(
"GL Entry",
{
"voucher_no": self.name,
"voucher_type": self.doctype,
"voucher_detail_no": entry.voucher_detail_no,
"against_voucher_type": entry.against_voucher_type,
"against_voucher": entry.against_voucher,
},
"is_cancelled",
1,
)
def add_advance_gl_for_reference(self, gl_entries, invoice):
make_reverse_gl_entries(gl_entries=gl_entries, partial_cancel=True)
return
# same reference added to payment entry
for gl_entry in gl_entries.copy():
if frappe.db.exists(
"GL Entry",
{
"account": gl_entry.account,
"voucher_type": gl_entry.voucher_type,
"voucher_no": gl_entry.voucher_no,
"voucher_detail_no": gl_entry.voucher_detail_no,
"debit": gl_entry.debit,
"credit": gl_entry.credit,
"is_cancelled": 0,
},
):
gl_entries.remove(gl_entry)
make_gl_entries(gl_entries)
def make_invoice_liability_entry(self, gl_entries, invoice):
args_dict = {
"party_type": self.party_type,
"party": self.party,
@@ -1689,43 +1698,13 @@ def get_outstanding_reference_documents(args, validate=False):
return data
def split_invoices_based_on_payment_terms(outstanding_invoices, company) -> list:
"""Split a list of invoices based on their payment terms."""
exc_rates = get_currency_data(outstanding_invoices, company)
def split_invoices_based_on_payment_terms(outstanding_invoices, company):
invoice_ref_based_on_payment_terms = {}
outstanding_invoices_after_split = []
for entry in outstanding_invoices:
if entry.voucher_type in ["Sales Invoice", "Purchase Invoice"]:
if payment_term_template := frappe.db.get_value(
entry.voucher_type, entry.voucher_no, "payment_terms_template"
):
split_rows = get_split_invoice_rows(entry, payment_term_template, exc_rates)
if not split_rows:
continue
if len(split_rows) > 1:
frappe.msgprint(
_("Splitting {0} {1} into {2} rows as per Payment Terms").format(
_(entry.voucher_type), frappe.bold(entry.voucher_no), len(split_rows)
),
alert=True,
)
outstanding_invoices_after_split += split_rows
continue
# If not an invoice or no payment terms template, add as it is
outstanding_invoices_after_split.append(entry)
return outstanding_invoices_after_split
def get_currency_data(outstanding_invoices: list, company: str = None) -> dict:
"""Get currency and conversion data for a list of invoices."""
exc_rates = frappe._dict()
company_currency = (
frappe.db.get_value("Company", company, "default_currency") if company else None
)
exc_rates = frappe._dict()
for doctype in ["Sales Invoice", "Purchase Invoice"]:
invoices = [x.voucher_no for x in outstanding_invoices if x.voucher_type == doctype]
for x in frappe.db.get_all(
@@ -1740,54 +1719,72 @@ def get_currency_data(outstanding_invoices: list, company: str = None) -> dict:
company_currency=company_currency,
)
return exc_rates
def get_split_invoice_rows(invoice: dict, payment_term_template: str, exc_rates: dict) -> list:
"""Split invoice based on its payment schedule table."""
split_rows = []
allocate_payment_based_on_payment_terms = frappe.db.get_value(
"Payment Terms Template", payment_term_template, "allocate_payment_based_on_payment_terms"
)
if not allocate_payment_based_on_payment_terms:
return [invoice]
payment_schedule = frappe.get_all(
"Payment Schedule", filters={"parent": invoice.voucher_no}, fields=["*"], order_by="due_date"
)
for payment_term in payment_schedule:
if not payment_term.outstanding > 0.1:
continue
doc_details = exc_rates.get(payment_term.parent, None)
is_multi_currency_acc = (doc_details.currency != doc_details.company_currency) and (
doc_details.party_account_currency != doc_details.company_currency
)
payment_term_outstanding = flt(payment_term.outstanding)
if not is_multi_currency_acc:
payment_term_outstanding = doc_details.conversion_rate * flt(payment_term.outstanding)
split_rows.append(
frappe._dict(
{
"due_date": invoice.due_date,
"currency": invoice.currency,
"voucher_no": invoice.voucher_no,
"voucher_type": invoice.voucher_type,
"posting_date": invoice.posting_date,
"invoice_amount": flt(invoice.invoice_amount),
"outstanding_amount": payment_term_outstanding
if payment_term_outstanding
else invoice.outstanding_amount,
"payment_term_outstanding": payment_term_outstanding,
"payment_amount": payment_term.payment_amount,
"payment_term": payment_term.payment_term,
}
for idx, d in enumerate(outstanding_invoices):
if d.voucher_type in ["Sales Invoice", "Purchase Invoice"]:
payment_term_template = frappe.db.get_value(
d.voucher_type, d.voucher_no, "payment_terms_template"
)
)
if payment_term_template:
allocate_payment_based_on_payment_terms = frappe.get_cached_value(
"Payment Terms Template", payment_term_template, "allocate_payment_based_on_payment_terms"
)
if allocate_payment_based_on_payment_terms:
payment_schedule = frappe.get_all(
"Payment Schedule", filters={"parent": d.voucher_no}, fields=["*"]
)
return split_rows
for payment_term in payment_schedule:
if payment_term.outstanding > 0.1:
doc_details = exc_rates.get(payment_term.parent, None)
is_multi_currency_acc = (doc_details.currency != doc_details.company_currency) and (
doc_details.party_account_currency != doc_details.company_currency
)
payment_term_outstanding = flt(payment_term.outstanding)
if not is_multi_currency_acc:
payment_term_outstanding = doc_details.conversion_rate * flt(payment_term.outstanding)
invoice_ref_based_on_payment_terms.setdefault(idx, [])
invoice_ref_based_on_payment_terms[idx].append(
frappe._dict(
{
"due_date": d.due_date,
"currency": d.currency,
"voucher_no": d.voucher_no,
"voucher_type": d.voucher_type,
"posting_date": d.posting_date,
"invoice_amount": flt(d.invoice_amount),
"outstanding_amount": payment_term_outstanding
if payment_term_outstanding
else d.outstanding_amount,
"payment_term_outstanding": payment_term_outstanding,
"payment_amount": payment_term.payment_amount,
"payment_term": payment_term.payment_term,
"account": d.account,
}
)
)
outstanding_invoices_after_split = []
if invoice_ref_based_on_payment_terms:
for idx, ref in invoice_ref_based_on_payment_terms.items():
voucher_no = ref[0]["voucher_no"]
voucher_type = ref[0]["voucher_type"]
frappe.msgprint(
_("Spliting {} {} into {} row(s) as per Payment Terms").format(
voucher_type, voucher_no, len(ref)
),
alert=True,
)
outstanding_invoices_after_split += invoice_ref_based_on_payment_terms[idx]
existing_row = list(filter(lambda x: x.get("voucher_no") == voucher_no, outstanding_invoices))
index = outstanding_invoices.index(existing_row[0])
outstanding_invoices.pop(index)
outstanding_invoices_after_split += outstanding_invoices
return outstanding_invoices_after_split
def get_orders_to_be_billed(
@@ -1992,24 +1989,18 @@ def get_company_defaults(company):
def get_outstanding_on_journal_entry(name):
gl = frappe.qb.DocType("GL Entry")
res = (
frappe.qb.from_(gl)
.select(
Case()
.when(
gl.party_type == "Customer",
Coalesce(Sum(gl.debit_in_account_currency - gl.credit_in_account_currency), 0),
)
.else_(Coalesce(Sum(gl.credit_in_account_currency - gl.debit_in_account_currency), 0))
.as_("outstanding_amount")
)
.where(
(Coalesce(gl.party_type, "") != "")
& (gl.is_cancelled == 0)
& ((gl.voucher_no == name) | (gl.against_voucher == name))
)
).run(as_dict=True)
res = frappe.db.sql(
"SELECT "
'CASE WHEN party_type IN ("Customer") '
"THEN ifnull(sum(debit_in_account_currency - credit_in_account_currency), 0) "
"ELSE ifnull(sum(credit_in_account_currency - debit_in_account_currency), 0) "
"END as outstanding_amount "
"FROM `tabGL Entry` WHERE (voucher_no=%s OR against_voucher=%s) "
"AND party_type IS NOT NULL "
'AND party_type != ""',
(name, name),
as_dict=1,
)
outstanding_amount = res[0].get("outstanding_amount", 0) if res else 0
@@ -2634,8 +2625,3 @@ def make_payment_order(source_name, target_doc=None):
)
return doclist
@erpnext.allow_regional
def add_regional_gl_entries(gl_entries, doc):
return

View File

@@ -6,12 +6,10 @@ import unittest
import frappe
from frappe import qb
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import add_days, flt, nowdate
from frappe.utils import flt, nowdate
from erpnext.accounts.doctype.account.test_account import create_account
from erpnext.accounts.doctype.payment_entry.payment_entry import (
InvalidPaymentEntry,
get_outstanding_reference_documents,
get_payment_entry,
get_reference_details,
)
@@ -685,6 +683,17 @@ class TestPaymentEntry(FrappeTestCase):
self.validate_gl_entries(pe.name, expected_gle)
def test_payment_against_negative_sales_invoice(self):
pe1 = frappe.new_doc("Payment Entry")
pe1.payment_type = "Pay"
pe1.company = "_Test Company"
pe1.party_type = "Customer"
pe1.party = "_Test Customer"
pe1.paid_from = "_Test Cash - _TC"
pe1.paid_amount = 100
pe1.received_amount = 100
self.assertRaises(InvalidPaymentEntry, pe1.validate)
si1 = create_sales_invoice()
# create full payment entry against si1
@@ -742,6 +751,8 @@ class TestPaymentEntry(FrappeTestCase):
# pay more than outstanding against si1
pe3 = get_payment_entry("Sales Invoice", si1.name, bank_account="_Test Cash - _TC")
pe3.paid_amount = pe3.received_amount = 300
self.assertRaises(InvalidPaymentEntry, pe3.validate)
# pay negative outstanding against si1
pe3.paid_to = "Debtors - _TC"
@@ -1251,266 +1262,6 @@ class TestPaymentEntry(FrappeTestCase):
so.reload()
self.assertEqual(so.advance_paid, so.rounded_total)
def test_receive_payment_from_payable_party_type(self):
"""
Checks GL entries generated while receiving payments from a Payable Party Type.
"""
pe = create_payment_entry(
party_type="Supplier",
party="_Test Supplier",
payment_type="Receive",
paid_from="Creditors - _TC",
paid_to="_Test Cash - _TC",
save=True,
submit=True,
)
self.voucher_no = pe.name
self.expected_gle = [
{"account": "Creditors - _TC", "debit": 0.0, "credit": 1000.0},
{"account": "_Test Cash - _TC", "debit": 1000.0, "credit": 0.0},
]
self.check_gl_entries()
def test_payment_against_partial_return_invoice(self):
"""
Checks GL entries generated for partial return invoice payments.
"""
si = create_sales_invoice(qty=10, rate=10, customer="_Test Customer")
credit_note = create_sales_invoice(
qty=-4, rate=10, customer="_Test Customer", is_return=1, return_against=si.name
)
pe = create_payment_entry(
party_type="Customer",
party="_Test Customer",
payment_type="Receive",
paid_from="Debtors - _TC",
paid_to="_Test Cash - _TC",
)
pe.set(
"references",
[
{
"reference_doctype": "Sales Invoice",
"reference_name": si.name,
"due_date": si.get("due_date"),
"total_amount": si.grand_total,
"outstanding_amount": si.outstanding_amount,
"allocated_amount": si.outstanding_amount,
},
{
"reference_doctype": "Sales Invoice",
"reference_name": credit_note.name,
"due_date": credit_note.get("due_date"),
"total_amount": credit_note.grand_total,
"outstanding_amount": credit_note.outstanding_amount,
"allocated_amount": credit_note.outstanding_amount,
},
],
)
pe.save()
pe.submit()
self.assertEqual(pe.total_allocated_amount, 60)
self.assertEqual(pe.unallocated_amount, 940)
self.voucher_no = pe.name
self.expected_gle = [
{"account": "Debtors - _TC", "debit": 40.0, "credit": 0.0},
{"account": "Debtors - _TC", "debit": 0.0, "credit": 940.0},
{"account": "Debtors - _TC", "debit": 0.0, "credit": 100.0},
{"account": "_Test Cash - _TC", "debit": 1000.0, "credit": 0.0},
]
self.check_gl_entries()
def test_ledger_entries_for_advance_as_liability(self):
from erpnext.accounts.doctype.account.test_account import create_account
company = "_Test Company"
advance_account = create_account(
parent_account="Current Assets - _TC",
account_name="Advances Received",
company=company,
account_type="Receivable",
)
frappe.db.set_value(
"Company",
company,
{
"book_advance_payments_in_separate_party_account": 1,
"default_advance_received_account": advance_account,
},
)
# Advance Payment
pe = create_payment_entry(
party_type="Customer",
party="_Test Customer",
payment_type="Receive",
paid_from="Debtors - _TC",
paid_to="_Test Cash - _TC",
)
pe.save() # use save() to trigger set_liability_account()
pe.submit()
# Normal Invoice
si = create_sales_invoice(qty=10, rate=100, customer="_Test Customer")
pre_reconciliation_gle = [
{"account": advance_account, "debit": 0.0, "credit": 1000.0},
{"account": "_Test Cash - _TC", "debit": 1000.0, "credit": 0.0},
]
pre_reconciliation_ple = [
{
"account": advance_account,
"voucher_no": pe.name,
"against_voucher_no": pe.name,
"amount": -1000.0,
}
]
self.voucher_no = pe.name
self.expected_gle = pre_reconciliation_gle
self.expected_ple = pre_reconciliation_ple
self.check_gl_entries()
self.check_pl_entries()
# Partially reconcile advance against invoice
pr = frappe.get_doc("Payment Reconciliation")
pr.company = company
pr.party_type = "Customer"
pr.party = "_Test Customer"
pr.receivable_payable_account = si.debit_to
pr.default_advance_account = advance_account
pr.payment_name = pe.name
pr.invoice_name = si.name
pr.get_unreconciled_entries()
self.assertEqual(len(pr.invoices), 1)
self.assertEqual(len(pr.payments), 1)
invoices = [x.as_dict() for x in pr.get("invoices")]
payments = [x.as_dict() for x in pr.get("payments")]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
pr.allocation[0].allocated_amount = 400
pr.reconcile()
# assert General and Payment Ledger entries post partial reconciliation
self.expected_gle = [
{"account": si.debit_to, "debit": 0.0, "credit": 400.0},
{"account": advance_account, "debit": 400.0, "credit": 0.0},
{"account": advance_account, "debit": 0.0, "credit": 1000.0},
{"account": "_Test Cash - _TC", "debit": 1000.0, "credit": 0.0},
]
self.expected_ple = [
{
"account": advance_account,
"voucher_no": pe.name,
"against_voucher_no": pe.name,
"amount": -1000.0,
},
{
"account": si.debit_to,
"voucher_no": pe.name,
"against_voucher_no": si.name,
"amount": -400.0,
},
{
"account": advance_account,
"voucher_no": pe.name,
"against_voucher_no": pe.name,
"amount": 400.0,
},
]
self.check_gl_entries()
self.check_pl_entries()
# Unreconcile
unrecon = (
frappe.get_doc(
{
"doctype": "Unreconcile Payment",
"company": company,
"voucher_type": pe.doctype,
"voucher_no": pe.name,
"allocations": [{"reference_doctype": si.doctype, "reference_name": si.name}],
}
)
.save()
.submit()
)
self.voucher_no = pe.name
self.expected_gle = pre_reconciliation_gle
self.expected_ple = pre_reconciliation_ple
self.check_gl_entries()
self.check_pl_entries()
def check_pl_entries(self):
ple = frappe.qb.DocType("Payment Ledger Entry")
pl_entries = (
frappe.qb.from_(ple)
.select(ple.account, ple.voucher_no, ple.against_voucher_no, ple.amount)
.where((ple.voucher_no == self.voucher_no) & (ple.delinked == 0))
.orderby(ple.creation)
).run(as_dict=True)
for row in range(len(self.expected_ple)):
for field in ["account", "voucher_no", "against_voucher_no", "amount"]:
self.assertEqual(self.expected_ple[row][field], pl_entries[row][field])
def check_gl_entries(self):
gle = frappe.qb.DocType("GL Entry")
gl_entries = (
frappe.qb.from_(gle)
.select(
gle.account,
gle.debit,
gle.credit,
)
.where((gle.voucher_no == self.voucher_no) & (gle.is_cancelled == 0))
.orderby(gle.account, gle.debit, gle.credit, order=frappe.qb.desc)
).run(as_dict=True)
for row in range(len(self.expected_gle)):
for field in ["account", "debit", "credit"]:
self.assertEqual(self.expected_gle[row][field], gl_entries[row][field])
def test_outstanding_invoices_api(self):
"""
Test if `get_outstanding_reference_documents` fetches invoices in the right order.
"""
customer = create_customer("Max Mustermann", "INR")
create_payment_terms_template()
# SI has an earlier due date and SI2 has a later due date
si = create_sales_invoice(
qty=1, rate=100, customer=customer, posting_date=add_days(nowdate(), -4)
)
si2 = create_sales_invoice(do_not_save=1, qty=1, rate=100, customer=customer)
si2.payment_terms_template = "Test Receivable Template"
si2.submit()
args = {
"posting_date": nowdate(),
"company": "_Test Company",
"party_type": "Customer",
"payment_type": "Pay",
"party": customer,
"party_account": "Debtors - _TC",
}
args.update(
{
"get_outstanding_invoices": True,
"from_posting_date": add_days(nowdate(), -4),
"to_posting_date": add_days(nowdate(), 2),
}
)
references = get_outstanding_reference_documents(args)
self.assertEqual(len(references), 3)
self.assertEqual(references[0].voucher_no, si.name)
self.assertEqual(references[1].voucher_no, si2.name)
self.assertEqual(references[2].voucher_no, si2.name)
self.assertEqual(references[1].payment_term, "Basic Amount Receivable")
self.assertEqual(references[2].payment_term, "Tax Receivable")
def create_payment_entry(**args):
payment_entry = frappe.new_doc("Payment Entry")
@@ -1571,9 +1322,6 @@ def create_payment_terms_template():
def create_payment_terms_template_with_discount(
name=None, discount_type=None, discount=None, template_name=None
):
"""
Create a Payment Terms Template with % or amount discount.
"""
create_payment_term(name or "30 Credit Days with 10% Discount")
template_name = template_name or "Test Discount Template"

Some files were not shown because too many files have changed in this diff Show More