diff --git a/.github/workflows/server-tests-mariadb.yml b/.github/workflows/server-tests-mariadb.yml
index e3b92fd269..ed731b8a31 100644
--- a/.github/workflows/server-tests-mariadb.yml
+++ b/.github/workflows/server-tests-mariadb.yml
@@ -120,7 +120,7 @@ jobs:
FRAPPE_BRANCH: ${{ github.event.inputs.branch }}
- name: Run Tests
- run: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --use-orchestrator --with-coverage
+ 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 }}
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/unverified/at_austria_chart_template.json b/erpnext/accounts/doctype/account/chart_of_accounts/unverified/at_austria_chart_template.json
index 3b07d5181e..58d67beb67 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/unverified/at_austria_chart_template.json
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/unverified/at_austria_chart_template.json
@@ -2,397 +2,438 @@
"country_code": "at",
"name": "Austria - Chart of Accounts",
"tree": {
- "Summe Abschreibungen und Aufwendungen": {
- "7010 bis 7080 Abschreibungen auf das Anlageverm\u00f6gen (ausgenommen Finanzanlagen)": {},
- "7100 bis 7190 Sonstige Steuern": {
- "account_type": "Tax"
- },
- "7200 bis 7290 Instandhaltung u. Reinigung durh Dritte, Entsorgung, Beleuchtung": {},
- "7300 bis 7310 Transporte durch Dritte": {},
- "7320 bis 7330 Kfz - Aufwand": {},
- "7340 bis 7350 Reise- und Fahraufwand": {},
- "7360 bis 7370 Tag- und N\u00e4chtigungsgelder": {},
- "7380 bis 7390 Nachrichtenaufwand": {},
- "7400 bis 7430 Miet- und Pachtaufwand": {},
- "7440 bis 7470 Leasingaufwand": {},
- "7480 bis 7490 Lizenzaufwand": {},
- "7500 bis 7530 Aufwand f\u00fcr beigestelltes Personal": {},
- "7540 bis 7570 Provisionen an Dritte": {},
- "7580 bis 7590 Aufsichtsratsverg\u00fctungen": {},
- "7610 bis 7620 Druckerzeugnisse und Vervielf\u00e4ltigungen": {},
- "7650 bis 7680 Werbung und Repr\u00e4sentationen": {},
- "7700 bis 7740 Versicherungen": {},
- "7750 bis 7760 Beratungs- und Pr\u00fcfungsaufwand": {},
- "7800 bis 7810 Schadensf\u00e4lle": {},
- "7840 bis 7880 Verschiedene betriebliche Aufwendungen": {},
- "7910 bis 7950 Aufwandsstellenrechung der Hersteller": {},
- "Abschreibungen auf aktivierte Aufwendungen f\u00fcr das Ingangs. u. Erweitern des Betriebes": {},
- "Abschreibungen vom Umlaufverm\u00f6gen, soweit diese die im Unternehmen \u00fcblichen Abschreibungen \u00fcbersteigen": {},
- "Aufwandsstellenrechnung": {},
- "Aus- und Fortbildung": {},
- "Buchwert abgegangener Anlagen, ausgenommen Finanzanlagen": {},
- "B\u00fcromaterial und Drucksorten": {},
- "Fachliteratur und Zeitungen ": {},
- "Herstellungskosten der zur Erzielung der Umsatzerl\u00f6se erbrachten Leistungen": {},
- "Mitgliedsbeitr\u00e4ge": {},
- "Skontoertr\u00e4ge auf sonstige betriebliche Aufwendungen": {},
- "Sonstige betrieblichen Aufwendungen": {},
- "Spenden und Trinkgelder": {},
- "Spesen des Geldverkehrs": {},
- "Verluste aus dem Abgang vom Anlageverm\u00f6gen, ausgenommen Finanzanlagen": {},
- "Vertriebskosten": {},
- "Verwaltungskosten": {},
- "root_type": "Expense"
- },
- "Summe Betriebliche Ertr\u00e4ge": {
- "4400 bis 4490 Erl\u00f6sschm\u00e4lerungen": {},
- "4500 bis 4570 Ver\u00e4nderungen des Bestandes an fertigen und unfertigen Erzeugn. sowie an noch nicht abrechenbaren Leistungen": {},
- "4580 bis 4590 andere aktivierte Eigenleistungen": {},
- "4600 bis 4620 Erl\u00f6se aus dem Abgang vom Anlageverm\u00f6gen, ausgen. Finanzanlagen": {},
- "4630 bis 4650 Ertr\u00e4ge aus dem Abgang vom Anlageverm\u00f6gen, ausgen. Finanzanlagen": {},
- "4660 bis 4670 Ertr\u00e4ge aus der Zuschreibung zum Anlageverm\u00f6gen, ausgen. Finanzanlagen": {},
- "4700 bis 4790 Ertr\u00e4ge aus der Aufl\u00f6sung von R\u00fcckstellungen": {},
- "4800 bis 4990 \u00dcbrige betriebliche Ertr\u00e4ge": {},
- "Erl\u00f6se 0 % Ausfuhrlieferungen/Drittl\u00e4nder": {},
- "Erl\u00f6se 10 %": {},
- "Erl\u00f6se 20 %": {},
- "Erl\u00f6se aus im Inland stpfl. EG Lieferungen 10 % USt": {},
- "Erl\u00f6se aus im Inland stpfl. EG Lieferungen 20 % USt": {},
- "Erl\u00f6se i.g. Lieferungen (stfr)": {},
- "root_type": "Income"
- },
- "Summe Eigenkapital R\u00fccklagen Abschlusskonten": {
- "9000 bis 9180 Gezeichnetes bzw. gewidmetes Kapital": {
- "account_type": "Equity"
- },
- "9200 bis 9290 Kapitalr\u00fccklagen": {
- "account_type": "Equity"
- },
- "9300 bis 9380 Gewinnr\u00fccklagen": {
- "account_type": "Equity"
- },
- "9400 bis 9590 Bewertungsreserven uns sonst. unversteuerte R\u00fccklagen": {
- "account_type": "Equity"
- },
- "9600 bis 9690 Privat und Verrechnungskonten bei Einzelunternehmen und Personengesellschaften": {},
- "9700 bis 9790 Einlagen stiller Gesellschafter ": {},
- "9900 bis 9999 Evidenzkonten": {},
- "Bilanzgewinn (-verlust )": {
- "account_type": "Equity"
- },
- "Er\u00f6ffnungsbilanz": {},
- "Gewinn- und Verlustrechnung": {},
- "Schlussbilanz": {},
- "nicht eingeforderte ausstehende Einlagen": {
- "account_type": "Equity"
- },
- "root_type": "Equity"
- },
- "Summe Finanzertr\u00e4ge und Aufwendungen": {
- "8000 bis 8040 Ertr\u00e4ge aus Beteiligungen": {},
- "8050 bis 8090 Ertr\u00e4ge aus anderen Wertpapieren und Ausleihungen des Finanzanlageverm\u00f6gens": {},
- "8100 bis 8130 Sonstige Zinsen und \u00e4hnliche Ertr\u00e4ge": {},
- "8220 bis 8250 Aufwendungen aus Beteiligungen": {},
- "8260 bis 8270 Aufwendungen aus sonst. Fiananzanlagen und aus Wertpapieren des Umlaufverm\u00f6gens": {},
- "8280 bis 8340 Zinsen und \u00e4hnliche Aufwendungem": {},
- "8400 bis 8440 Au\u00dferordentliche Ertr\u00e4ge": {},
- "8450 bis 8490 Au\u00dferordentliche Aufwendungen": {},
- "8500 bis 8590 Steuern vom Einkommen und vom Ertrag": {
- "account_type": "Tax"
- },
- "8600 bis 8690 Aufl\u00f6sung unversteuerten R\u00fccklagen": {},
- "8700 bis 8740 Aufl\u00f6sung von Kapitalr\u00fccklagen": {},
- "8750 bis 8790 Aufl\u00f6sung von Gewinnr\u00fccklagen": {},
- "8800 bis 8890 Zuweisung von unversteuerten R\u00fccklagen": {},
- "Buchwert abgegangener Beteiligungen": {},
- "Buchwert abgegangener Wertpapiere des Umlaufverm\u00f6gens": {},
- "Buchwert abgegangener sonstiger Finanzanlagen": {},
- "Erl\u00f6se aus dem Abgang von Beteiligungen": {},
- "Erl\u00f6se aus dem Abgang von Wertpapieren des Umlaufverm\u00f6gens": {},
- "Erl\u00f6se aus dem Abgang von sonstigen Finanzanlagen": {},
- "Ertr\u00e4ge aus dem Abgang von und der Zuschreibung zu Finanzanlagen": {},
- "Ertr\u00e4ge aus dem Abgang von und der Zuschreibung zu Wertpapieren des Umlaufverm\u00f6gens": {},
- "Gewinabfuhr bzw. Verlust\u00fcberrechnung aus Ergebnisabf\u00fchrungsvertr\u00e4gen": {},
- "nicht ausgenutzte Lieferantenskonti": {},
- "root_type": "Income"
- },
- "Summe Fremdkapital": {
- "3020 bis 3030 Steuerr\u00fcckstellungen": {},
- "3040 bis 3090 Sonstige R\u00fcckstellungen": {},
- "3110 bis 3170 Verbindlichkeiten gegen\u00fcber Kredidinstituten": {},
- "3180 bis 3190 Verbindlichkeiten gegen\u00fcber Finanzinstituten": {},
- "3380 bis 3390 Verbindlichkeiten aus der Annahme gezogener Wechsel u. d. Ausstellungen eigener Wechsel": {
+ "Klasse 0 Aktiva: Anlageverm\u00f6gen": {
+ "0100 Konzessionen ": {"account_type": "Fixed Asset"},
+ "0110 Patentrechte und Lizenzen ": {"account_type": "Fixed Asset"},
+ "0120 Datenverarbeitungsprogramme ": {"account_type": "Fixed Asset"},
+ "0130 Marken, Warenzeichen und Musterschutzrechte, sonstige Urheberrechte ": {"account_type": "Fixed Asset"},
+ "0140 Pacht- und Mietrechte ": {"account_type": "Fixed Asset"},
+ "0150 Bezugs- und ähnliche Rechte ": {"account_type": "Fixed Asset"},
+ "0160 Geschäfts-/Firmenwert ": {"account_type": "Fixed Asset"},
+ "0170 Umgründungsmehrwert ": {"account_type": "Fixed Asset"},
+ "0180 Geleistete Anzahlungen auf immaterielle Vermögensgegenstände": {"account_type": "Fixed Asset"},
+ "0190 Kumulierte Abschreibungen zu immateriellen Vermögensgegenständen ": {"account_type": "Fixed Asset"},
+ "0200 Unbebaute Grundstücke, soweit nicht landwirtschaftlich genutzt ": {"account_type": "Fixed Asset"},
+ "0210 Bebaute Grundstücke (Grundwert) ": {"account_type": "Fixed Asset"},
+ "0220 Landwirtschaftlich genutzte Grundstücke ": {"account_type": "Fixed Asset"},
+ "0230 Grundstücksgleiche Rechte ": {"account_type": "Fixed Asset"},
+ "0300 Betriebs- und Geschäftsgebäude auf eigenem Grund ": {"account_type": "Fixed Asset"},
+ "0310 Wohn- und Sozialgebäude auf eigenem Grund ": {"account_type": "Fixed Asset"},
+ "0320 Betriebs- und Geschäftsgebäude auf fremdem Grund ": {"account_type": "Fixed Asset"},
+ "0330 Wohn- und Sozialgebäude auf fremdem Grund ": {"account_type": "Fixed Asset"},
+ "0340 Grundstückseinrichtungen auf eigenem Grund ": {"account_type": "Fixed Asset"},
+ "0350 Grundstückseinrichtungen auf fremdem Grund ": {"account_type": "Fixed Asset"},
+ "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"},
+ "0500 Maschinenwerkzeuge ": {"account_type": "Fixed Asset"},
+ "0510 Allgemeine Werkzeuge und Handwerkzeuge ": {"account_type": "Fixed Asset"},
+ "0520 Prototypen, Formen, Modelle ": {"account_type": "Fixed Asset"},
+ "0530 Andere Erzeugungshilfsmittel (auch Softwarewerkzeuge)": {"account_type": "Fixed Asset"},
+ "0540 Hebezeuge und Montageanlagen ": {"account_type": "Fixed Asset"},
+ "0550 Geringwertige Vermögensgegenstände, soweit im Erzeugungsprozess ": {"account_type": "Fixed Asset"},
+ "0560 Festwerte technische Anlagen und Maschinen ": {"account_type": "Fixed Asset"},
+ "0590 Kumulierte Abschreibungen zu technischen Anlagen und Maschinen ": {"account_type": "Fixed Asset"},
+ "0600 Betriebs- und Geschäftsausstattung, soweit nicht gesondert angeführt ": {"account_type": "Fixed Asset"},
+ "0610 Andere Anlagen, soweit nicht gesondert angeführt ": {"account_type": "Fixed Asset"},
+ "0620 Büromaschinen, EDV-Anlagen ": {"account_type": "Fixed Asset"},
+ "0630 PKW und Kombis ": {"account_type": "Fixed Asset"},
+ "0640 LKW ": {"account_type": "Fixed Asset"},
+ "0650 Andere Beförderungsmittel ": {"account_type": "Fixed Asset"},
+ "0660 Gebinde ": {"account_type": "Fixed Asset"},
+ "0670 Geringwertige Vermögensgegenstände, soweit nicht im Erzeugungssprozess verwendet": {"account_type": "Fixed Asset"},
+ "0680 Festwerte außer technische Anlagen und Maschinen ": {"account_type": "Fixed Asset"},
+ "0690 Kumulierte Abschreibungen zu anderen Anlagen, Betriebs- und Geschäftsausstattung": {"account_type": "Fixed Asset"},
+ "0700 Geleistete Anzahlungen auf Sachanlagen ": {"account_type": "Fixed Asset"},
+ "0710 Anlagen in Bau ": {"account_type": "Fixed Asset"},
+ "0790 Kumulierte Abschreibungen zu geleisteten Anzahlungen auf Sachanlagen ": {"account_type": "Fixed Asset"},
+ "0800 Anteile an verbundenen Unternehmen ": {"account_type": "Fixed Asset"},
+ "0810 Beteiligungen an Gemeinschaftsunternehmen ": {"account_type": "Fixed Asset"},
+ "0820 Beteiligungen an angeschlossenen (assoziierten) Unternehmen ": {"account_type": "Fixed Asset"},
+ "0830 Eigene Anteile, Anteile an herrschenden oder mit Mehrheit beteiligten ": {"account_type": "Fixed Asset"},
+ "0840 Sonstige Beteiligungen ": {"account_type": "Fixed Asset"},
+ "0850 Ausleihungen an verbundene Unternehmen ": {"account_type": "Fixed Asset"},
+ "0860 Ausleihungen an Unternehmen mit Beteiligungsverhältnis": {"account_type": "Fixed Asset"},
+ "0870 Ausleihungen an Gesellschafter ": {"account_type": "Fixed Asset"},
+ "0880 Sonstige Ausleihungen ": {"account_type": "Fixed Asset"},
+ "0890 Anteile an Kapitalgesellschaften ohne Beteiligungscharakter ": {"account_type": "Fixed Asset"},
+ "0900 Anteile an Personengesellschaften ohne Beteiligungscharakter ": {"account_type": "Fixed Asset"},
+ "0910 Genossenschaftsanteile ohne Beteiligungscharakter ": {"account_type": "Fixed Asset"},
+ "0920 Anteile an Investmentfonds ": {"account_type": "Fixed Asset"},
+ "0930 Festverzinsliche Wertpapiere des Anlagevermögens ": {"account_type": "Fixed Asset"},
+ "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"},
+ "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"},
+ "3110 Verbindlichkeiten gegen\u00fcber Bank": {"account_type": "Payable"},
+ "3150 Verbindlichkeiten Darlehen": {"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 bis 3470 Verbindlichkeiten gegen\u00fc. verb. Untern., Verbindl. gegen\u00fc. Untern., mit denen eine Beteiligungsverh\u00e4lnis besteht": {},
- "3600 bis 3690 Verbindlichkeiten im Rahmen der sozialen Sicherheit": {},
- "3700 bis 3890 \u00dcbrige sonstige Verbindlichkeiten": {},
- "3900 bis 3990 Passive Rechnungsabgrenzungsposten": {},
- "Anleihen (einschlie\u00dflich konvertibler)": {},
- "Erhaltene Anzahlungenauf Bestellungen": {},
- "R\u00fcckstellungen f\u00fcr Abfertigung": {},
- "R\u00fcckstellungen f\u00fcr Pensionen": {},
- "USt. \u00a719 /art (reverse charge)": {
+ "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"},
+ "3600 Verbindlichkeiten Sozialversicherung": {"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"},
+ "3200 Erhaltene Anzahlungen auf Bestellungen": {"account_type": "Payable"},
+ "3040 R\u00fcckstellungen f\u00fcr Abfertigung": {"account_type": "Payable"},
+
+ "3530 USt. \u00a719 (reverse charge)": {
"account_type": "Tax"
},
- "Umsatzsteuer": {},
- "Umsatzsteuer Zahllast": {
+ "3500 Verbindlichkeiten aus Umsatzsteuer": {"account_type": "Tax"},
+ "3580 Umsatzsteuer Zahllast": {
"account_type": "Tax"
},
- "Umsatzsteuer aus i.g. Erwerb 10%": {
+ "3510 Umsatzsteuer Inland 20%": {
"account_type": "Tax"
},
- "Umsatzsteuer aus i.g. Erwerb 20%": {
+ "3515 Umsatzsteuer Inland 10%": {
+ "account_type": "Tax"
+ },
+ "3520 Umsatzsteuer aus i.g. Erwerb 20%": {
"account_type": "Tax"
},
- "Umsatzsteuer aus i.g. Lieferungen 10%": {
+ "3525 Umsatzsteuer aus i.g. Erwerb 10%": {
"account_type": "Tax"
- },
- "Umsatzsteuer aus i.g. Lieferungen 20%": {
- "account_type": "Tax"
- },
- "Umsatzsteuer-Evidenzkonto f\u00fcr erhaltene Anzahlungen auf Bestellungen": {},
- "Verbindlichkeiten aus Lieferungen u. Leistungen EU": {
+ },
+ "3560 Umsatzsteuer-Evidenzkonto f\u00fcr erhaltene Anzahlungen auf Bestellungen": {},
+ "3360 Verbindlichkeiten aus Lieferungen u. Leistungen EU": {
"account_type": "Payable"
},
- "Verbindlichkeiten aus Lieferungen u. Leistungen Inland": {
+ "3000 Verbindlichkeiten aus Lieferungen u. Leistungen Inland": {
"account_type": "Payable"
},
- "Verbindlichkeiten aus Lieferungen u. Leistungen sonst. Ausland": {
+ "3370 Verbindlichkeiten aus Lieferungen u. Leistungen sonst. Ausland": {
"account_type": "Payable"
},
- "Verbindlichkeiten gegen\u00fcber Gesellschaften": {},
- "Verrechnung Finanzamt": {
+ "3400 Verbindlichkeiten gegen\u00fcber verbundenen Unternehmen": {},
+ "3570 Verrechnung Finanzamt": {
"account_type": "Tax"
},
"root_type": "Liability"
- },
- "Summe Kontoklasse 0 Anlageverm\u00f6gen": {
- "44 bis 49 Sonstige Maschinen und maschinelle Anlagen": {},
- "920 bis 930 Festverzinsliche Wertpapiere des Anlageverm\u00f6gens": {},
- "940 bis 970 Sonstige Finanzanlagen, Wertrechte": {},
- "Allgemeine Werkzeuge und Handwerkzeuge": {},
- "Andere Bef\u00f6rderungsmittel": {},
- "Andere Betriebs- und Gesch\u00e4ftsausstattung": {},
- "Andere Erzeugungshilfsmittel": {},
- "Anlagen im Bau": {},
- "Anteile an Investmentfonds": {},
- "Anteile an Kapitalgesellschaften ohne Beteiligungscharakter": {},
- "Anteile an Personengesellschaften ohne Beteiligungscharakter": {},
- "Anteile an verbundenen Unternehmen": {},
- "Antriebsmaschinen": {},
- "Aufwendungen f\u00fcs das Ingangssetzen u. Erweitern eines Betriebes": {},
- "Ausleihungen an verbundene Unternehmen": {},
- "Ausleihungen an verbundene Unternehmen, mit denen ein Beteiligungsverh\u00e4lnis besteht": {},
- "Bauliche Investitionen in fremden (gepachteten) Betriebs- und Gesch\u00e4ftsgeb\u00e4uden": {},
- "Bauliche Investitionen in fremden (gepachteten) Wohn- und Sozialgeb\u00e4uden": {},
- "Bebaute Grundst\u00fccke (Grundwert)": {},
- "Beheizungs- und Beleuchtungsanlagen": {},
- "Beteiligungen an Gemeinschaftunternehmen": {},
- "Beteiligungen an angeschlossenen (assoziierten) Unternehmen": {},
- "Betriebs- und Gesch\u00e4ftsgeb\u00e4ude auf eigenem Grund": {},
- "Betriebs- und Gesch\u00e4ftsgeb\u00e4ude auf fremdem Grund": {},
- "B\u00fcromaschinen, EDV - Anlagen": {},
- "Datenverarbeitungsprogramme": {},
- "Energieversorgungsanlagen": {},
- "Fertigungsmaschinen": {},
- "Gebinde": {},
- "Geleistete Anzahlungen": {},
- "Genossenschaften ohne Beteiligungscharakter": {},
- "Geringwertige Verm\u00f6gensgegenst\u00e4nde, soweit im Erzeugerprozess verwendet": {},
- "Geringwertige Verm\u00f6gensgegenst\u00e4nde, soweit nicht im Erzeugungsprozess verwendet": {},
- "Gesch\u00e4fts(Firmen)wert": {},
- "Grundst\u00fcckseinrichtunten auf eigenem Grund": {},
- "Grundst\u00fcckseinrichtunten auf fremdem Grund": {},
- "Grundst\u00fccksgleiche Rechte": {},
- "Hebezeuge und Montageanlagen": {},
- "Konzessionen": {},
- "Kumulierte Abschreibungen": {},
- "LKW": {},
- "Marken, Warenzeichen und Musterschutzrechte": {},
- "Maschinenwerkzeuge": {},
- "Nachrichten- und Kontrollanlagen": {},
- "PKW": {},
- "Pacht- und Mietrechte": {},
- "Patentrechte und Lizenzen": {},
- "Sonstige Ausleihungen": {},
- "Sonstige Beteiligungen": {},
- "Transportanlagen": {},
- "Unbebaute Grundst\u00fccke": {},
- "Vorrichtungen, Formen und Modelle": {},
- "Wohn- und Sozialgeb\u00e4ude auf eigenem Grund": {},
- "Wohn- und Sozialgeb\u00e4ude auf fremdem Grund": {},
+ },
+ "Klasse 2 Aktiva: Umlaufverm\u00f6gen, Rechnungsabgrenzungen": {
+ "2030 Forderungen aus Lieferungen und Leistungen Inland (0% USt, umsatzsteuerfrei)": {
+ "account_type": "Receivable"
+ },
+ "2010 Forderungen aus Lieferungen und Leistungen Inland (10% USt, umsatzsteuerfrei)": {
+ "account_type": "Receivable"
+ },
+ "2000 Forderungen aus Lieferungen und Leistungen Inland (20% USt, umsatzsteuerfrei)": {
+ "account_type": "Receivable"
+ },
+ "2040 Forderungen aus Lieferungen und Leistungen Inland (sonstiger USt-Satz)": {
+ "account_type": "Receivable"
+ },
+ "2100 Forderungen aus Lieferungen und Leistungen EU": {
+ "account_type": "Receivable"
+ },
+ "2150 Forderungen aus Lieferungen und Leistungen Ausland (Nicht-EU)": {
+ "account_type": "Receivable"
+ },
+ "2200 Forderungen gegen\u00fcber verbundenen Unternehmen": {
+ "account_type": "Receivable"
+ },
+ "2250 Forderungen gegen\u00fcber Unternehmen, mit denen ein Beteiligungsverh\u00e4ltnis besteht": {
+ "account_type": "Receivable"
+ },
+ "2300 Sonstige Forderungen und Verm\u00f6gensgegenst\u00e4nde": {
+ "account_type": "Receivable"
+ },
+ "2630 Sonstige Wertpapiere": {
+ "account_type": "Stock"
+ },
+ "2750 Kassenbest\u00e4nde in Fremdw\u00e4hrung": {
+ "account_type": "Cash"
+ },
+ "2900 Aktive Rechnungsabrenzungsposten": {
+ "account_type": "Receivable"
+ },
+ "2600 Anteile an verbundenen Unternehmen": {
+ "account_type": "Equity"
+ },
+ "2680 Besitzwechsel ohne Forderungen": {
+ "account_type": "Receivable"
+ },
+ "2950 Aktiviertes Disagio": {
+ "account_type": "Receivable"
+ },
+ "2610 Eigene Anteile und Wertpapiere an mit Mehrheit beteiligten Unternehmen": {
+ "account_type": "Receivable"
+ },
+ "2570 Einfuhrumsatzsteuer (bezahlt)": {"account_type": "Tax"},
+
+ "2460 Eingeforderte aber noch nicht eingezahlte Einlagen": {
+ "account_type": "Receivable"
+ },
+ "2180 Einzelwertberichtigungen zu Forderungen aus Lief. und Leist. Ausland": {
+ "account_type": "Receivable"
+ },
+ "2130 Einzelwertberichtigungen zu Forderungen aus Lief. und Leist. EU": {
+ "account_type": "Receivable"
+ },
+ "2080 Einzelwertberichtigungen zu Forderungen aus Lief. und Leist. Inland ": {
+ "account_type": "Receivable"
+ },
+ "2270 Einzelwertberichtigungen zu Forderungen gegen\u00fcber Unternehmen mit denen ein Beteiligungsverh\u00e4ltnis besteht": {
+ "account_type": "Receivable"
+ },
+ "2230 Einzelwertberichtigungen zu Forderungen gegen\u00fcber verbundenen Unternehmen": {
+ "account_type": "Receivable"
+ },
+ "2470 Einzelwertberichtigungen zu sonstigen Forderungen und Verm\u00f6gensgegenst\u00e4nden": {
+ "account_type": "Receivable"
+ },
+ "2700 Kassenbestand": {
+ "account_type": "Cash"
+ },
+ "2190 Pauschalwertberichtigungen zu Forderungen aus Lief. und Leist. sonstiges Ausland": {
+ "account_type": "Receivable"
+ },
+ "2130 Pauschalwertberichtigungen zu Forderungen aus Lief. und Leist. EU": {
+ "account_type": "Receivable"
+ },
+ "2100 Pauschalwertberichtigungen zu Forderungen aus Lief. und Leist. Inland ": {
+ "account_type": "Receivable"
+ },
+ "2280 Pauschalwertberichtigungen zu Forderungen gegen\u00fcber Unternehmen mit denen ein Beteiligungsverh\u00e4ltnis besteht": {
+ "account_type": "Receivable"
+ },
+ "2240 Pauschalwertberichtigungen zu Forderungen gegen\u00fcber verbundenen Unternehmen": {
+ "account_type": "Receivable"
+ },
+ "2480 Pauschalwertberichtigungen zu sonstigen Forderungen und Verm\u00f6gensgegenst\u00e4nden": {
+ "account_type": "Receivable"
+ },
+ "2740 Postwertzeichen": {
+ "account_type": "Cash"
+ },
+ "2780 Schecks in Euro": {
+ "account_type": "Cash"
+ },
+ "2800 Guthaben bei Bank": {
+ "account_type": "Bank"
+ },
+ "2801 Guthaben bei Bank - Sparkonto": {
+ "account_type": "Bank"
+ },
+ "2810 Guthaben bei Paypal": {
+ "account_type": "Bank"
+ },
+ "2930 Mietvorauszahlungen": {
+ "account_type": "Receivable"
+ },
+ "2980 Abgrenzung latenter Steuern": {
+ "account_type": "Receivable"
+ },
+ "2500 Vorsteuer": {
+ "account_type": "Receivable"
+ },
+ "2510 Vorsteuer Inland 10%": {
+ "account_type": "Tax"
+ },
+ "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"
+ },
+ "2690 Wertberichtigungen zu Wertpapieren und Anteilen": {
+ "account_type": "Receivable"
+ },
"root_type": "Asset"
},
- "Summe Personalaufwand": {
- "6000 bis 6190 L\u00f6hne": {},
- "6200 bis 6390 Geh\u00e4lter": {},
- "6400 bis 6440 Aufwendungen f\u00fcr Abfertigungen": {},
- "6450 bis 6490 Aufwendungen f\u00fcr Altersversorgung": {},
- "6500 bis 6550 Gesetzlicher Sozialaufwand Arbeiter": {},
- "6560 bis 6590 Gesetzlicher Sozialaufwand Angestellte": {},
- "6600 bis 6650 Lohnabh\u00e4ngige Abgaben und Pflichtbeitr\u00e4gte": {},
- "6660 bis 6690 Gehaltsabh\u00e4ngige Abgaben und Pflichtbeitr\u00e4gte": {},
- "6700 bis 6890 Sonstige Sozialaufwendungen": {},
- "Aufwandsstellenrechnung": {},
+ "Klasse 4: Betriebliche Erträge": {
+ "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"},
+ "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"},
+ "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"},
+ "4630 Ertr\u00e4ge aus dem Abgang vom Anlageverm\u00f6gen, ausgen. Finanzanlagen": {"account_type": "Income Account"},
+ "4660 Ertr\u00e4ge aus der Zuschreibung zum Anlageverm\u00f6gen, ausgen. Finanzanlagen": {"account_type": "Income Account"},
+ "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"},
+ "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"},
+ "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"},
+ "5700 Bearbeitung durch Dritte": {"account_type": "Cost of Goods Sold"},
+ "5900 Aufwandsstellenrechnung Material": {"account_type": "Cost of Goods Sold"},
+ "5820 Skontoertr\u00e4ge (20% USt.)": {"account_type": "Income Account"},
+ "5810 Skontoertr\u00e4ge (10% USt.)": {"account_type": "Income Account"},
+ "5010 Handelswareneinkauf 10 %": {"account_type": "Cost of Goods Sold"},
+ "5020 Handelswareneinkauf 20 %": {"account_type": "Cost of Goods Sold"},
+ "5040 Handelswareneinkauf innergemeinschaftlicher Erwerb 10 % VSt/10 % USt": {"account_type": "Cost of Goods Sold"},
+ "5050 Handelswareneinkauf innergemeinschaftlicher Erwerb 20 % VSt/20 % USt": {"account_type": "Cost of Goods Sold"},
+ "5070 Handelswareneinkauf innergemeinschaftlicher Erwerb ohne Vorsteuerabzug und 10 % USt": {"account_type": "Cost of Goods Sold"},
+ "5080 Handelswareneinkauf innergemeinschaftlicher Erwerb ohne Vorsteuerabzug und 20 % USt": {"account_type": "Cost of Goods Sold"},
"root_type": "Expense"
},
- "Summe Umlaufverm\u00f6gen": {
- "2000 bis 2007 Forderungen aus Lief. und Leist. Inland": {
- "account_type": "Receivable"
- },
- "2100 bis 2120 Forderungen aus Lief. und Leist. EU": {
- "account_type": "Receivable"
- },
- "2150 bis 2170 Forderungen aus Lief. und Leist. Ausland": {
- "account_type": "Receivable"
- },
- "2200 bis 2220 Forderungen gegen\u00fcber verbundenen Unternehmen": {
- "account_type": "Receivable"
- },
- "2250 bis 2270 Forderungen gegen\u00fcber Unternehmen, mit denen ein Beteiligungsverh\u00e4ltnis besteht": {
- "account_type": "Receivable"
- },
- "2300 bis 2460 Sonstige Forderungen und Verm\u00f6gensgegenst\u00e4nde": {
- "account_type": "Receivable"
- },
- "2630 bis 2670 Sonstige Wertpapiere": {
- "account_type": "Receivable"
- },
- "2750 bis 2770 Kassenbest\u00e4nde in Fremdw\u00e4hrung": {
- "account_type": "Receivable"
- },
- "Aktive Rechnungsabrenzungsposten": {
- "account_type": "Receivable"
- },
- "Anteile an verbundenen Unternehmen": {
- "account_type": "Receivable"
- },
- "Bank / Guthaben bei Kreditinstituten": {
- "account_type": "Receivable"
- },
- "Besitzwechsel ...": {
- "account_type": "Receivable"
- },
- "Disagio": {
- "account_type": "Receivable"
- },
- "Eigene Anteile (Wertpapiere)": {
- "account_type": "Receivable"
- },
- "Einfuhrumsatzsteuer (bezahlt)": {},
- "Eingeforderte aber noch nicht eingezahlte Einlagen": {
- "account_type": "Receivable"
- },
- "Einzelwertberichtigungen zu Forderungen aus Lief. und Leist. Ausland": {
- "account_type": "Receivable"
- },
- "Einzelwertberichtigungen zu Forderungen aus Lief. und Leist. EU": {
- "account_type": "Receivable"
- },
- "Einzelwertberichtigungen zu Forderungen aus Lief. und Leist. Inland ": {
- "account_type": "Receivable"
- },
- "Einzelwertberichtigungen zu Forderungen gegen\u00fcber Unternehmen mit denen ein Beteiligungsverh\u00e4ltnis besteht": {
- "account_type": "Receivable"
- },
- "Einzelwertberichtigungen zu Forderungen gegen\u00fcber verbundenen Unternehmen": {
- "account_type": "Receivable"
- },
- "Einzelwertberichtigungen zu sonstigen Forderungen und Verm\u00f6gensgegenst\u00e4nden": {
- "account_type": "Receivable"
- },
- "Kassenbestand": {
- "account_type": "Receivable"
- },
- "Pauschalwertberichtigungen zu Forderungen aus Lief. und Leist. Ausland": {
- "account_type": "Receivable"
- },
- "Pauschalwertberichtigungen zu Forderungen aus Lief. und Leist. EU": {
- "account_type": "Receivable"
- },
- "Pauschalwertberichtigungen zu Forderungen aus Lief. und Leist. Inland ": {
- "account_type": "Receivable"
- },
- "Pauschalwertberichtigungen zu Forderungen gegen\u00fcber Unternehmen mit denen ein Beteiligungsverh\u00e4ltnis besteht": {
- "account_type": "Receivable"
- },
- "Pauschalwertberichtigungen zu Forderungen gegen\u00fcber verbundenen Unternehmen": {
- "account_type": "Receivable"
- },
- "Pauschalwertberichtigungen zu sonstigen Forderungen und Verm\u00f6gensgegenst\u00e4nden": {
- "account_type": "Receivable"
- },
- "Postwertzeichen": {
- "account_type": "Receivable"
- },
- "Schecks in Inlandsw\u00e4hrung": {
- "account_type": "Receivable"
- },
- "Sonstige Anteile": {
- "account_type": "Receivable"
- },
- "Stempelmarken": {
- "account_type": "Receivable"
- },
- "Steuerabgrenzung": {
- "account_type": "Receivable"
- },
- "Unterschiedsbetrag gem. Abschnitt XII Pensionskassengesetz": {
- "account_type": "Receivable"
- },
- "Unterschiedsbetrag zur gebotenen Pensionsr\u00fcckstellung": {
- "account_type": "Receivable"
- },
- "Vorsteuer": {
- "account_type": "Receivable"
- },
- "Vorsteuer aus ig. Erwerb 10%": {
- "account_type": "Tax"
- },
- "Vorsteuer aus ig. Erwerb 20%": {
- "account_type": "Tax"
- },
- "Vorsteuer \u00a719/Art 19 ( reverse charge ) ": {
- "account_type": "Tax"
- },
- "Wertberichtigungen": {
- "account_type": "Receivable"
- },
- "root_type": "Asset"
- },
- "Summe Vorr\u00e4te": {
- "1000 bis 1090 Bezugsverrechnung": {},
- "1100 bis 1190 Rohstoffe": {},
- "1200 bis 1290 Bezogene Teile": {},
- "1300 bis 1340 Hilfsstoffe": {},
- "1350 bis 1390 Betriebsstoffe": {},
- "1400 bis 1490 Unfertige Erzeugniss": {},
- "1500 bis 1590 Fertige Erzeugniss": {},
- "1600 bis 1690 Waren": {},
- "1700 bis 1790 Noch nicht abgerechenbare Leistungen": {},
- "1900 bis 1990 Wertberichtigungen": {},
- "geleistete Anzahlungen": {},
- "root_type": "Asset"
- },
- "Summe Wareneinsatz": {
- "5100 bis 5190 Verbrauch an Rohstoffen": {},
- "5200 bis 5290 Verbrauch von bezogenen Fertig- und Einzelteilen": {},
- "5300 bis 5390 Verbrauch von Hilfsstoffen": {},
- "5400 bis 5490 Verbrauch von Betriebsstoffen": {},
- "5500 bis 5590 Verbrauch von Werkzeugen und anderen Erzeugungshilfsmittel": {},
- "5600 bis 5690 Verbrauch von Brenn- und Treibstoffen, Energie und Wasser": {},
- "5700 bis 5790 Sonstige bezogene Herstellungsleistungen": {},
- "Aufwandsstellenrechnung": {},
- "Skontoertr\u00e4ge auf Materialaufwand": {},
- "Skontoertr\u00e4ge auf sonstige bezogene Herstellungsleistungen": {},
- "Wareneinkauf 10 %": {},
- "Wareneinkauf 20 %": {},
- "Wareneinkauf igErwerb 10 % VSt/10 % USt": {},
- "Wareneinkauf igErwerb 20 % VSt/20 % USt": {},
- "Wareneinkauf igErwerb ohne Vorsteuerabzug und 10 % USt": {},
- "Wareneinkauf igErwerb ohne Vorsteuerabzug und 20 % USt": {},
+ "Klasse 6: Personalaufwand": {
+ "6000 L\u00f6hne": {"account_type": "Payable"},
+ "6200 Geh\u00e4lter": {"account_type": "Payable"},
+ "6400 Aufwendungen f\u00fcr Abfertigungen": {"account_type": "Payable"},
+ "6450 Aufwendungen f\u00fcr Altersversorgung": {"account_type": "Payable"},
+ "6500 Gesetzlicher Sozialaufwand Arbeiter": {"account_type": "Payable"},
+ "6560 Gesetzlicher Sozialaufwand Angestellte": {"account_type": "Payable"},
+ "6600 Lohnabh\u00e4ngige Abgaben und Pflichtbeitr\u00e4gte": {"account_type": "Payable"},
+ "6660 Gehaltsabh\u00e4ngige Abgaben und Pflichtbeitr\u00e4gte": {"account_type": "Payable"},
+ "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"},
+ "7200 Instandhaltung u. Reinigung durch Dritte, Entsorgung, Energie": {"account_type": "Expense Account"},
+ "7300 Transporte durch Dritte": {"account_type": "Expense Account"},
+ "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"},
+ "7350 Reise- und Fahraufwand": {"account_type": "Expense Account"},
+ "7360 Tag- und N\u00e4chtigungsgelder": {"account_type": "Expense Account"},
+ "7380 Nachrichtenaufwand": {"account_type": "Expense Account"},
+ "7400 Miet- und Pachtaufwand": {"account_type": "Expense Account"},
+ "7440 Leasingaufwand": {"account_type": "Expense Account"},
+ "7480 Lizenzaufwand": {"account_type": "Expense Account"},
+ "7500 Aufwand f\u00fcr beigestelltes Personal": {"account_type": "Expense Account"},
+ "7540 Provisionen an Dritte": {"account_type": "Expense Account"},
+ "7580 Aufsichtsratsverg\u00fctungen": {"account_type": "Expense Account"},
+ "7610 Druckerzeugnisse und Vervielf\u00e4ltigungen": {"account_type": "Expense Account"},
+ "7650 Werbung und Repr\u00e4sentationen": {"account_type": "Expense Account"},
+ "7700 Versicherungen": {"account_type": "Expense Account"},
+ "7750 Beratungs- und Pr\u00fcfungsaufwand": {"account_type": "Expense Account"},
+ "7800 Forderungsverluste und Schadensf\u00e4lle": {"account_type": "Expense Account"},
+ "7840 Verschiedene betriebliche Aufwendungen": {"account_type": "Expense Account"},
+ "7910 Aufwandsstellenrechung der Hersteller": {"account_type": "Expense Account"},
+ "7060 Sofortabschreibungen geringwertig": {"account_type": "Expense Account"},
+ "7070 Abschreibungen vom Umlaufverm\u00f6gen, soweit diese die im Unternehmen \u00fcblichen Abschreibungen \u00fcbersteigen": {"account_type": "Depreciation"},
+ "7900 Aufwandsstellenrechnung": {"account_type": "Expense Account"},
+ "7770 Aus- und Fortbildung": {"account_type": "Expense Account"},
+ "7820 Buchwert abgegangener Anlagen, ausgenommen Finanzanlagen": {"account_type": "Expense Account"},
+ "7600 B\u00fcromaterial und Drucksorten": {"account_type": "Expense Account"},
+ "7630 Fachliteratur und Zeitungen ": {"account_type": "Expense Account"},
+ "7960 Herstellungskosten der zur Erzielung der Umsatzerl\u00f6se erbrachten Leistungen": {"account_type": "Expense Account"},
+ "7780 Mitgliedsbeitr\u00e4ge": {"account_type": "Expense Account"},
+ "7880 Skontoertr\u00e4ge auf sonstige betriebliche Aufwendungen": {"account_type": "Expense Account"},
+ "7990 Sonstige betrieblichen Aufwendungen": {"account_type": "Expense Account"},
+ "7680 Spenden und Trinkgelder": {"account_type": "Expense Account"},
+ "7790 Spesen des Geldverkehrs": {"account_type": "Expense Account"},
+ "7830 Verluste aus dem Abgang vom Anlageverm\u00f6gen, ausgenommen Finanzanlagen": {"account_type": "Expense Account"},
+ "7970 Vertriebskosten": {"account_type": "Expense Account"},
+ "7980 Verwaltungskosten": {"account_type": "Expense Account"},
+ "root_type": "Expense"
+ },
+ "Klasse 8: Finanz- und ausserordentliche Ertr\u00e4ge und Aufwendungen": {
+ "8000 Ertr\u00e4ge aus Beteiligungen": {"account_type": "Income Account"},
+ "8050 Ertr\u00e4ge aus anderen Wertpapieren und Ausleihungen des Finanzanlageverm\u00f6gens": {"account_type": "Income Account"},
+ "8100 Zinsen aus Bankguthaben": {"account_type": "Income Account"},
+ "8110 Zinsen aus gewaehrten Darlehen": {"account_type": "Income Account"},
+ "8130 Verzugszinsenertraege": {"account_type": "Income Account"},
+ "8220 Aufwendungen aus Beteiligungen": {"account_type": "Expense Account"},
+ "8260 Aufwendungen aus sonst. Fiananzanlagen und aus Wertpapieren des Umlaufverm\u00f6gens": {},
+ "8280 Zinsen und \u00e4hnliche Aufwendungem": {"account_type": "Expense Account"},
+ "8400 Au\u00dferordentliche Ertr\u00e4ge": {"account_type": "Income Account"},
+ "8450 Au\u00dferordentliche Aufwendungen": {"account_type": "Expense Account"},
+ "8500 Steuern vom Einkommen und vom Ertrag": {
+ "account_type": "Tax"
+ },
+ "8600 Aufl\u00f6sung unversteuerten R\u00fccklagen": {"account_type": "Income Account"},
+ "8700 Aufl\u00f6sung von Kapitalr\u00fccklagen": {"account_type": "Income Account"},
+ "8750 Aufl\u00f6sung von Gewinnr\u00fccklagen": {"account_type": "Income Account"},
+ "8800 Zuweisung zu unversteuerten R\u00fccklagen": {"account_type": "Expense Account"},
+ "8900 Zuweisung zu Gewinnr\u00fccklagen": {"account_type": "Expense Account"},
+ "8100 Buchwert abgegangener Beteiligungen": {"account_type": "Expense Account"},
+ "8130 Buchwert abgegangener Wertpapiere des Umlaufverm\u00f6gens": {"account_type": "Expense Account"},
+ "8120 Buchwert abgegangener sonstiger Finanzanlagen": {"account_type": "Expense Account"},
+ "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"
+ },
+ "9200 Kapitalr\u00fccklagen": {
+ "account_type": "Equity"
+ },
+ "9300 Gewinnr\u00fccklagen": {
+ "account_type": "Equity"
+ },
+ "9400 Bewertungsreserven uns sonst. unversteuerte R\u00fccklagen": {
+ "account_type": "Equity"
+ },
+ "9600 Private Entnahmen": {"account_type": "Equity"},
+ "9610 Privatsteuern": {"account_type": "Equity"},
+ "9700 Einlagen stiller Gesellschafter ": {"account_type": "Equity"},
+ "9900 Evidenzkonto": {"account_type": "Equity"},
+ "9800 Er\u00f6ffnungsbilanzkonto (EBK)": {"account_type": "Equity"},
+ "9880 Jahresergebnis laut Gewinn- und Verlustrechnung (G+V)": {"account_type": "Equity"},
+ "9850 Schlussbilanzkonto (SBK)": {"account_type": "Round Off"},
+ "9190 nicht eingeforderte ausstehende Einlagen und berechtigte Entnahmen von Gesellschaftern": {
+ "account_type": "Equity"
+ },
+ "root_type": "Equity"
}
- }
-}
+ }
+ }
diff --git a/erpnext/accounts/doctype/budget/budget.json b/erpnext/accounts/doctype/budget/budget.json
index fc4dd200ea..f0566f4436 100644
--- a/erpnext/accounts/doctype/budget/budget.json
+++ b/erpnext/accounts/doctype/budget/budget.json
@@ -1,6 +1,7 @@
{
"actions": [],
"allow_import": 1,
+ "autoname": "naming_series:",
"creation": "2016-05-16 11:42:29.632528",
"doctype": "DocType",
"editable_grid": 1,
@@ -9,6 +10,7 @@
"budget_against",
"company",
"cost_center",
+ "naming_series",
"project",
"fiscal_year",
"column_break_3",
@@ -190,15 +192,26 @@
"label": "Budget Accounts",
"options": "Budget Account",
"reqd": 1
+ },
+ {
+ "fieldname": "naming_series",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Series",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1,
+ "set_only_once": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-10-06 15:13:54.055854",
+ "modified": "2022-10-10 22:14:36.361509",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Budget",
+ "naming_rule": "By \"Naming Series\" field",
"owner": "Administrator",
"permissions": [
{
@@ -220,5 +233,6 @@
],
"sort_field": "modified",
"sort_order": "DESC",
+ "states": [],
"track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/budget/budget.py b/erpnext/accounts/doctype/budget/budget.py
index 5527f9fb99..6ac3350c3b 100644
--- a/erpnext/accounts/doctype/budget/budget.py
+++ b/erpnext/accounts/doctype/budget/budget.py
@@ -5,7 +5,6 @@
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.model.naming import make_autoname
from frappe.utils import add_months, flt, fmt_money, get_last_day, getdate
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
@@ -23,11 +22,6 @@ class DuplicateBudgetError(frappe.ValidationError):
class Budget(Document):
- def autoname(self):
- self.name = make_autoname(
- self.get(frappe.scrub(self.budget_against)) + "/" + self.fiscal_year + "/.###"
- )
-
def validate(self):
if not self.get(frappe.scrub(self.budget_against)):
frappe.throw(_("{0} is mandatory").format(self.budget_against))
@@ -109,6 +103,9 @@ class Budget(Document):
):
self.applicable_on_booking_actual_expenses = 1
+ def before_naming(self):
+ self.naming_series = f"{{{frappe.scrub(self.budget_against)}}}./.{self.fiscal_year}/.###"
+
def validate_expense_against_budget(args):
args = frappe._dict(args)
diff --git a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
index dff883aef9..a0ea43332c 100644
--- a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
+++ b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
@@ -202,6 +202,7 @@
"fieldname": "reference_type",
"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"
},
{
@@ -209,13 +210,15 @@
"fieldtype": "Dynamic Link",
"in_list_view": 1,
"label": "Reference Name",
+ "no_copy": 1,
"options": "reference_type"
},
{
"depends_on": "eval:doc.reference_type&&!in_list(doc.reference_type, ['Expense Claim', 'Asset', 'Employee Loan', 'Employee Advance'])",
"fieldname": "reference_due_date",
"fieldtype": "Select",
- "label": "Reference Due Date"
+ "label": "Reference Due Date",
+ "no_copy": 1
},
{
"fieldname": "project",
@@ -274,19 +277,22 @@
"fieldname": "reference_detail_no",
"fieldtype": "Data",
"hidden": 1,
- "label": "Reference Detail No"
+ "label": "Reference Detail No",
+ "no_copy": 1
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2021-08-30 21:27:32.200299",
+ "modified": "2022-10-13 17:07:17.999191",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry Account",
+ "naming_rule": "Random",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
+ "states": [],
"track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 7f245fd083..94874894b0 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -995,7 +995,9 @@ class PaymentEntry(AccountsController):
if self.payment_type in ("Receive", "Pay") and self.party:
for d in self.get("references"):
if d.allocated_amount and d.reference_doctype in frappe.get_hooks("advance_payment_doctypes"):
- frappe.get_doc(d.reference_doctype, d.reference_name).set_total_advance_paid()
+ frappe.get_doc(
+ d.reference_doctype, d.reference_name, for_update=True
+ ).set_total_advance_paid()
def on_recurring(self, reference_doc, auto_repeat_doc):
self.reference_no = reference_doc.name
diff --git a/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
index 70f128e0e3..3132fdd259 100644
--- a/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
@@ -495,6 +495,67 @@ class TestPOSInvoice(unittest.TestCase):
self.assertRaises(frappe.ValidationError, pos.submit)
+ def test_value_error_on_serial_no_validation(self):
+ from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
+
+ se = make_serialized_item(
+ company="_Test Company",
+ target_warehouse="Stores - _TC",
+ cost_center="Main - _TC",
+ expense_account="Cost of Goods Sold - _TC",
+ )
+ serial_nos = se.get("items")[0].serial_no
+
+ # make a pos invoice
+ pos = create_pos_invoice(
+ company="_Test Company",
+ debit_to="Debtors - _TC",
+ account_for_change_amount="Cash - _TC",
+ warehouse="Stores - _TC",
+ income_account="Sales - _TC",
+ expense_account="Cost of Goods Sold - _TC",
+ cost_center="Main - _TC",
+ item=se.get("items")[0].item_code,
+ rate=1000,
+ qty=1,
+ do_not_save=1,
+ )
+ pos.get("items")[0].has_serial_no = 1
+ pos.get("items")[0].serial_no = serial_nos.split("\n")[0]
+ pos.set("payments", [])
+ pos.append(
+ "payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 1000, "default": 1}
+ )
+ pos = pos.save().submit()
+
+ # make a return
+ pos_return = make_sales_return(pos.name)
+ pos_return.paid_amount = pos_return.grand_total
+ pos_return.save()
+ pos_return.submit()
+
+ # set docstatus to 2 for pos to trigger this issue
+ frappe.db.set_value("POS Invoice", pos.name, "docstatus", 2)
+
+ pos2 = create_pos_invoice(
+ company="_Test Company",
+ debit_to="Debtors - _TC",
+ account_for_change_amount="Cash - _TC",
+ warehouse="Stores - _TC",
+ income_account="Sales - _TC",
+ expense_account="Cost of Goods Sold - _TC",
+ cost_center="Main - _TC",
+ item=se.get("items")[0].item_code,
+ rate=1000,
+ qty=1,
+ do_not_save=1,
+ )
+
+ pos2.get("items")[0].has_serial_no = 1
+ pos2.get("items")[0].serial_no = serial_nos.split("\n")[0]
+ # Value error should not be triggered on validation
+ pos2.save()
+
def test_loyalty_points(self):
from erpnext.accounts.doctype.loyalty_program.loyalty_program import (
get_loyalty_program_details_with_points,
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index 9af3188e47..826d71b12e 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -268,6 +268,18 @@ def get_serial_no_for_item(args):
return item_details
+def update_pricing_rule_uom(pricing_rule, args):
+ child_doc = {"Item Code": "items", "Item Group": "item_groups", "Brand": "brands"}.get(
+ pricing_rule.apply_on
+ )
+
+ apply_on_field = frappe.scrub(pricing_rule.apply_on)
+
+ for row in pricing_rule.get(child_doc):
+ if row.get(apply_on_field) == args.get(apply_on_field):
+ pricing_rule.uom = row.uom
+
+
def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=False):
from erpnext.accounts.doctype.pricing_rule.utils import (
get_applied_pricing_rules,
@@ -324,6 +336,7 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=Fa
if isinstance(pricing_rule, str):
pricing_rule = frappe.get_cached_doc("Pricing Rule", pricing_rule)
+ update_pricing_rule_uom(pricing_rule, args)
pricing_rule.apply_rule_on_other_items = get_pricing_rule_items(pricing_rule) or []
if pricing_rule.get("suggestion"):
@@ -440,12 +453,15 @@ def apply_price_discount_rule(pricing_rule, item_details, args):
if pricing_rule.currency == args.currency:
pricing_rule_rate = pricing_rule.rate
+ # TODO https://github.com/frappe/erpnext/pull/23636 solve this in some other way.
if pricing_rule_rate:
+ is_blank_uom = pricing_rule.get("uom") != args.get("uom")
# Override already set price list rate (from item price)
# if pricing_rule_rate > 0
item_details.update(
{
- "price_list_rate": pricing_rule_rate * args.get("conversion_factor", 1),
+ "price_list_rate": pricing_rule_rate
+ * (args.get("conversion_factor", 1) if is_blank_uom else 1),
}
)
item_details.update({"discount_percentage": 0.0})
diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
index 0a9db6b0f5..fbe567824f 100644
--- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
@@ -595,6 +595,121 @@ class TestPricingRule(unittest.TestCase):
frappe.get_doc("Item Price", {"item_code": "Water Flask"}).delete()
item.delete()
+ def test_item_price_with_blank_uom_pricing_rule(self):
+ properties = {
+ "item_code": "Item Blank UOM",
+ "stock_uom": "Nos",
+ "sales_uom": "Box",
+ "uoms": [dict(uom="Box", conversion_factor=10)],
+ }
+ item = make_item(properties=properties)
+
+ make_item_price("Item Blank UOM", "_Test Price List", 100)
+
+ pricing_rule_record = {
+ "doctype": "Pricing Rule",
+ "title": "_Test Item Blank UOM Rule",
+ "apply_on": "Item Code",
+ "items": [
+ {
+ "item_code": "Item Blank UOM",
+ }
+ ],
+ "selling": 1,
+ "currency": "INR",
+ "rate_or_discount": "Rate",
+ "rate": 101,
+ "company": "_Test Company",
+ }
+ rule = frappe.get_doc(pricing_rule_record)
+ rule.insert()
+
+ si = create_sales_invoice(
+ do_not_save=True, item_code="Item Blank UOM", uom="Box", conversion_factor=10
+ )
+ si.selling_price_list = "_Test Price List"
+ si.save()
+
+ # If UOM is blank consider it as stock UOM and apply pricing_rule on all UOM.
+ # rate is 101, Selling UOM is Box that have conversion_factor of 10 so 101 * 10 = 1010
+ self.assertEqual(si.items[0].price_list_rate, 1010)
+ self.assertEqual(si.items[0].rate, 1010)
+
+ si.delete()
+
+ si = create_sales_invoice(do_not_save=True, item_code="Item Blank UOM", uom="Nos")
+ si.selling_price_list = "_Test Price List"
+ si.save()
+
+ # UOM is blank so consider it as stock UOM and apply pricing_rule on all UOM.
+ # rate is 101, Selling UOM is Nos that have conversion_factor of 1 so 101 * 1 = 101
+ self.assertEqual(si.items[0].price_list_rate, 101)
+ self.assertEqual(si.items[0].rate, 101)
+
+ si.delete()
+ rule.delete()
+ frappe.get_doc("Item Price", {"item_code": "Item Blank UOM"}).delete()
+
+ item.delete()
+
+ def test_item_price_with_selling_uom_pricing_rule(self):
+ properties = {
+ "item_code": "Item UOM other than Stock",
+ "stock_uom": "Nos",
+ "sales_uom": "Box",
+ "uoms": [dict(uom="Box", conversion_factor=10)],
+ }
+ item = make_item(properties=properties)
+
+ make_item_price("Item UOM other than Stock", "_Test Price List", 100)
+
+ pricing_rule_record = {
+ "doctype": "Pricing Rule",
+ "title": "_Test Item UOM other than Stock Rule",
+ "apply_on": "Item Code",
+ "items": [
+ {
+ "item_code": "Item UOM other than Stock",
+ "uom": "Box",
+ }
+ ],
+ "selling": 1,
+ "currency": "INR",
+ "rate_or_discount": "Rate",
+ "rate": 101,
+ "company": "_Test Company",
+ }
+ rule = frappe.get_doc(pricing_rule_record)
+ rule.insert()
+
+ si = create_sales_invoice(
+ do_not_save=True, item_code="Item UOM other than Stock", uom="Box", conversion_factor=10
+ )
+ si.selling_price_list = "_Test Price List"
+ si.save()
+
+ # UOM is Box so apply pricing_rule only on Box UOM.
+ # Selling UOM is Box and as both UOM are same no need to multiply by conversion_factor.
+ self.assertEqual(si.items[0].price_list_rate, 101)
+ self.assertEqual(si.items[0].rate, 101)
+
+ si.delete()
+
+ si = create_sales_invoice(do_not_save=True, item_code="Item UOM other than Stock", uom="Nos")
+ si.selling_price_list = "_Test Price List"
+ si.save()
+
+ # UOM is Box so pricing_rule won't apply as selling_uom is Nos.
+ # As Pricing Rule is not applied price of 100 will be fetched from Item Price List.
+ self.assertEqual(si.items[0].price_list_rate, 100)
+ self.assertEqual(si.items[0].rate, 100)
+
+ si.delete()
+ rule.delete()
+ frappe.get_doc("Item Price", {"item_code": "Item UOM other than Stock"}).delete()
+
+ item.delete()
+
def test_pricing_rule_for_different_currency(self):
make_item("Test Sanitizer Item")
diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py
index 1f29d732ba..4c78d7261d 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -111,6 +111,12 @@ def _get_pricing_rules(apply_on, args, values):
)
if apply_on_field == "item_code":
+ if args.get("uom", None):
+ item_conditions += (
+ " and ({child_doc}.uom='{item_uom}' or IFNULL({child_doc}.uom, '')='')".format(
+ child_doc=child_doc, item_uom=args.get("uom")
+ )
+ )
if "variant_of" not in args:
args.variant_of = frappe.get_cached_value("Item", args.item_code, "variant_of")
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index ec861a2787..c3a9855ff4 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -31,7 +31,7 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
super.onload();
// Ignore linked advances
- this.frm.ignore_doctypes_on_cancel_all = ['Journal Entry', 'Payment Entry'];
+ this.frm.ignore_doctypes_on_cancel_all = ['Journal Entry', 'Payment Entry', 'Purchase Invoice'];
if(!this.frm.doc.__islocal) {
// show credit_to in print format
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 1e477776e2..e73d602332 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -12,39 +12,23 @@
"supplier",
"supplier_name",
"tax_id",
- "due_date",
- "tax_withholding_category",
- "column_break1",
"company",
+ "column_break_6",
"posting_date",
"posting_time",
"set_posting_time",
+ "due_date",
+ "column_break1",
"is_paid",
"is_return",
+ "return_against",
"apply_tds",
+ "tax_withholding_category",
"amended_from",
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"project",
- "supplier_invoice_details",
- "bill_no",
- "column_break_15",
- "bill_date",
- "returns",
- "return_against",
- "section_addresses",
- "supplier_address",
- "address_display",
- "contact_person",
- "contact_display",
- "contact_mobile",
- "contact_email",
- "col_break_address",
- "shipping_address",
- "shipping_address_display",
- "billing_address",
- "billing_address_display",
"currency_and_price_list",
"currency",
"conversion_rate",
@@ -54,39 +38,33 @@
"plc_conversion_rate",
"ignore_pricing_rule",
"sec_warehouse",
- "set_warehouse",
- "rejected_warehouse",
- "col_break_warehouse",
- "set_from_warehouse",
- "supplier_warehouse",
- "is_subcontracted",
- "items_section",
- "update_stock",
"scan_barcode",
+ "col_break_warehouse",
+ "update_stock",
+ "set_warehouse",
+ "set_from_warehouse",
+ "is_subcontracted",
+ "rejected_warehouse",
+ "supplier_warehouse",
+ "items_section",
"items",
- "pricing_rule_details",
- "pricing_rules",
- "raw_materials_supplied",
- "supplied_items",
"section_break_26",
"total_qty",
+ "total_net_weight",
+ "column_break_50",
"base_total",
"base_net_total",
"column_break_28",
- "total_net_weight",
"total",
"net_total",
"taxes_section",
+ "taxes_and_charges",
+ "column_break_58",
"tax_category",
"column_break_49",
"shipping_rule",
"section_break_51",
- "taxes_and_charges",
"taxes",
- "tax_withheld_vouchers_section",
- "tax_withheld_vouchers",
- "sec_tax_breakup",
- "other_charges_calculation",
"totals",
"base_taxes_and_charges_added",
"base_taxes_and_charges_deducted",
@@ -95,12 +73,6 @@
"taxes_and_charges_added",
"taxes_and_charges_deducted",
"total_taxes_and_charges",
- "section_break_44",
- "apply_discount_on",
- "base_discount_amount",
- "column_break_46",
- "additional_discount_percentage",
- "discount_amount",
"section_break_49",
"base_grand_total",
"base_rounding_adjustment",
@@ -114,24 +86,58 @@
"total_advance",
"outstanding_amount",
"disable_rounded_total",
+ "section_break_44",
+ "apply_discount_on",
+ "base_discount_amount",
+ "additional_discount_account",
+ "column_break_46",
+ "additional_discount_percentage",
+ "discount_amount",
+ "tax_withheld_vouchers_section",
+ "tax_withheld_vouchers",
+ "sec_tax_breakup",
+ "other_charges_calculation",
+ "pricing_rule_details",
+ "pricing_rules",
+ "raw_materials_supplied",
+ "supplied_items",
+ "payments_tab",
"payments_section",
"mode_of_payment",
- "cash_bank_account",
+ "base_paid_amount",
"clearance_date",
"col_br_payments",
+ "cash_bank_account",
"paid_amount",
- "base_paid_amount",
+ "advances_section",
+ "allocate_advances_automatically",
+ "get_advances",
+ "advances",
+ "advance_tax",
"write_off",
"write_off_amount",
"base_write_off_amount",
"column_break_61",
"write_off_account",
"write_off_cost_center",
- "advances_section",
- "allocate_advances_automatically",
- "get_advances",
- "advances",
- "advance_tax",
+ "address_and_contact_tab",
+ "section_addresses",
+ "supplier_address",
+ "address_display",
+ "col_break_address",
+ "contact_person",
+ "contact_display",
+ "contact_mobile",
+ "contact_email",
+ "company_shipping_address_section",
+ "shipping_address",
+ "column_break_126",
+ "shipping_address_display",
+ "company_billing_address_section",
+ "billing_address",
+ "column_break_130",
+ "billing_address_display",
+ "terms_tab",
"payment_schedule_section",
"payment_terms_template",
"ignore_default_payment_terms_template",
@@ -139,23 +145,15 @@
"terms_section_break",
"tc_name",
"terms",
- "printing_settings",
- "letter_head",
- "select_print_heading",
- "column_break_112",
- "group_same_items",
- "language",
- "sb_14",
- "on_hold",
- "release_date",
- "cb_17",
- "hold_comment",
- "more_info",
+ "more_info_tab",
+ "status_section",
"status",
- "inter_company_invoice_reference",
- "represents_company",
- "column_break_147",
- "is_internal_supplier",
+ "column_break_177",
+ "per_received",
+ "supplier_invoice_details",
+ "bill_no",
+ "column_break_15",
+ "bill_date",
"accounting_details_section",
"credit_to",
"party_account_currency",
@@ -163,15 +161,32 @@
"against_expense_account",
"column_break_63",
"unrealized_profit_loss_account",
- "remarks",
"subscription_section",
- "from_date",
- "to_date",
- "column_break_114",
"auto_repeat",
"update_auto_repeat_reference",
- "per_received",
- "is_old_subcontracting_flow"
+ "column_break_114",
+ "from_date",
+ "to_date",
+ "printing_settings",
+ "letter_head",
+ "group_same_items",
+ "column_break_112",
+ "select_print_heading",
+ "language",
+ "sb_14",
+ "on_hold",
+ "release_date",
+ "cb_17",
+ "hold_comment",
+ "additional_info_section",
+ "is_internal_supplier",
+ "represents_company",
+ "column_break_147",
+ "inter_company_invoice_reference",
+ "is_old_subcontracting_flow",
+ "remarks",
+ "connections_tab",
+ "column_break_38"
],
"fields": [
{
@@ -354,7 +369,7 @@
"collapsible_depends_on": "bill_no",
"fieldname": "supplier_invoice_details",
"fieldtype": "Section Break",
- "label": "Supplier Invoice Details"
+ "label": "Supplier Invoice"
},
{
"fieldname": "bill_no",
@@ -377,12 +392,6 @@
"oldfieldtype": "Date",
"print_hide": 1
},
- {
- "depends_on": "return_against",
- "fieldname": "returns",
- "fieldtype": "Section Break",
- "label": "Returns"
- },
{
"depends_on": "return_against",
"fieldname": "return_against",
@@ -394,10 +403,9 @@
"read_only": 1
},
{
- "collapsible": 1,
"fieldname": "section_addresses",
"fieldtype": "Section Break",
- "label": "Address and Contact"
+ "label": "Supplier Address"
},
{
"fieldname": "supplier_address",
@@ -518,11 +526,12 @@
},
{
"fieldname": "sec_warehouse",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "hide_border": 1,
+ "label": "Items"
},
{
"depends_on": "update_stock",
- "description": "Sets 'Accepted Warehouse' in each row of the items table.",
"fieldname": "set_warehouse",
"fieldtype": "Link",
"label": "Set Accepted Warehouse",
@@ -531,7 +540,6 @@
},
{
"depends_on": "update_stock",
- "description": "Warehouse where you are maintaining stock of rejected items",
"fieldname": "rejected_warehouse",
"fieldtype": "Link",
"label": "Rejected Warehouse",
@@ -554,6 +562,7 @@
{
"fieldname": "items_section",
"fieldtype": "Section Break",
+ "hide_border": 1,
"oldfieldtype": "Section Break",
"options": "fa fa-shopping-cart"
},
@@ -581,6 +590,7 @@
"reqd": 1
},
{
+ "collapsible": 1,
"fieldname": "pricing_rule_details",
"fieldtype": "Section Break",
"label": "Pricing Rules"
@@ -593,6 +603,7 @@
"read_only": 1
},
{
+ "collapsible": 1,
"collapsible_depends_on": "supplied_items",
"fieldname": "raw_materials_supplied",
"fieldtype": "Section Break",
@@ -656,6 +667,7 @@
"read_only": 1
},
{
+ "depends_on": "total_net_weight",
"fieldname": "total_net_weight",
"fieldtype": "Float",
"label": "Total Net Weight",
@@ -665,6 +677,8 @@
{
"fieldname": "taxes_section",
"fieldtype": "Section Break",
+ "hide_border": 1,
+ "label": "Taxes and Charges",
"oldfieldtype": "Section Break",
"options": "fa fa-money"
},
@@ -688,7 +702,8 @@
},
{
"fieldname": "section_break_51",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "hide_border": 1
},
{
"fieldname": "taxes_and_charges",
@@ -792,7 +807,6 @@
},
{
"collapsible": 1,
- "collapsible_depends_on": "discount_amount",
"fieldname": "section_break_44",
"fieldtype": "Section Break",
"label": "Additional Discount"
@@ -832,7 +846,8 @@
},
{
"fieldname": "section_break_49",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "label": "Totals"
},
{
"fieldname": "base_grand_total",
@@ -1003,8 +1018,6 @@
},
{
"collapsible": 1,
- "collapsible_depends_on": "write_off_amount",
- "depends_on": "grand_total",
"fieldname": "write_off",
"fieldtype": "Section Break",
"label": "Write Off"
@@ -1081,7 +1094,6 @@
"print_hide": 1
},
{
- "collapsible": 1,
"collapsible_depends_on": "eval:(!doc.is_return)",
"fieldname": "payment_schedule_section",
"fieldtype": "Section Break",
@@ -1102,8 +1114,6 @@
"print_hide": 1
},
{
- "collapsible": 1,
- "collapsible_depends_on": "terms",
"fieldname": "terms_section_break",
"fieldtype": "Section Break",
"label": "Terms and Conditions",
@@ -1119,13 +1129,13 @@
{
"fieldname": "terms",
"fieldtype": "Text Editor",
- "label": "Terms and Conditions1"
+ "label": "Terms and Conditions"
},
{
"collapsible": 1,
"fieldname": "printing_settings",
"fieldtype": "Section Break",
- "label": "Printing Settings"
+ "label": "Print Settings"
},
{
"allow_on_submit": 1,
@@ -1166,15 +1176,6 @@
"print_hide": 1,
"read_only": 1
},
- {
- "collapsible": 1,
- "fieldname": "more_info",
- "fieldtype": "Section Break",
- "label": "More Information",
- "oldfieldtype": "Section Break",
- "options": "fa fa-file-text",
- "print_hide": 1
- },
{
"default": "0",
"fetch_from": "supplier.is_internal_supplier",
@@ -1260,7 +1261,7 @@
"collapsible": 1,
"fieldname": "subscription_section",
"fieldtype": "Section Break",
- "label": "Subscription Section",
+ "label": "Subscription",
"print_hide": 1
},
{
@@ -1339,7 +1340,7 @@
},
{
"depends_on": "eval:doc.is_internal_supplier",
- "description": "Unrealized Profit / Loss account for intra-company transfers",
+ "description": "Unrealized Profit/Loss account for intra-company transfers",
"fieldname": "unrealized_profit_loss_account",
"fieldtype": "Link",
"label": "Unrealized Profit / Loss Account",
@@ -1356,7 +1357,6 @@
},
{
"depends_on": "eval:doc.update_stock && doc.is_internal_supplier",
- "description": "Sets 'From Warehouse' in each row of the items table.",
"fieldname": "set_from_warehouse",
"fieldtype": "Link",
"label": "Set From Warehouse",
@@ -1422,6 +1422,7 @@
"read_only": 1
},
{
+ "collapsible_depends_on": "tax_withheld_vouchers",
"fieldname": "tax_withheld_vouchers_section",
"fieldtype": "Section Break",
"label": "Tax Withheld Vouchers"
@@ -1433,13 +1434,92 @@
"no_copy": 1,
"options": "Tax Withheld Vouchers",
"read_only": 1
+ },
+ {
+ "fieldname": "payments_tab",
+ "fieldtype": "Tab Break",
+ "label": "Payments"
+ },
+ {
+ "fieldname": "address_and_contact_tab",
+ "fieldtype": "Tab Break",
+ "label": "Address & Contact"
+ },
+ {
+ "fieldname": "terms_tab",
+ "fieldtype": "Tab Break",
+ "label": "Terms"
+ },
+ {
+ "fieldname": "more_info_tab",
+ "fieldtype": "Tab Break",
+ "label": "More Info"
+ },
+ {
+ "fieldname": "connections_tab",
+ "fieldtype": "Tab Break",
+ "label": "Connections",
+ "show_dashboard": 1
+ },
+ {
+ "fieldname": "column_break_6",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_38",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_50",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_58",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "company_shipping_address_section",
+ "fieldtype": "Section Break",
+ "label": "Company Shipping Address"
+ },
+ {
+ "fieldname": "column_break_126",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "company_billing_address_section",
+ "fieldtype": "Section Break",
+ "label": "Company Billing Address"
+ },
+ {
+ "fieldname": "column_break_130",
+ "fieldtype": "Column Break"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "status_section",
+ "fieldtype": "Section Break",
+ "label": "Status"
+ },
+ {
+ "fieldname": "column_break_177",
+ "fieldtype": "Column Break"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "additional_info_section",
+ "fieldtype": "Section Break",
+ "label": "Additional Info",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-file-text",
+ "print_hide": 1
}
],
"icon": "fa fa-file-text",
"idx": 204,
"is_submittable": 1,
"links": [],
- "modified": "2022-10-07 14:19:14.214157",
+ "modified": "2022-10-11 13:04:44.304389",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 2b633cb8c3..3d74b8f139 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -705,6 +705,10 @@ class PurchaseInvoice(BuyingController):
)
)
+ credit_amount = item.base_net_amount
+ if self.is_internal_supplier and item.valuation_rate:
+ credit_amount = flt(item.valuation_rate * item.stock_qty)
+
# Intentionally passed negative debit amount to avoid incorrect GL Entry validation
gl_entries.append(
self.get_gl_dict(
@@ -714,7 +718,7 @@ class PurchaseInvoice(BuyingController):
"cost_center": item.cost_center,
"project": item.project or self.project,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "debit": -1 * flt(item.base_net_amount, item.precision("base_net_amount")),
+ "debit": -1 * flt(credit_amount, item.precision("base_net_amount")),
},
warehouse_account[item.from_warehouse]["account_currency"],
item=item,
@@ -1411,6 +1415,7 @@ class PurchaseInvoice(BuyingController):
"Stock Ledger Entry",
"Repost Item Valuation",
"Payment Ledger Entry",
+ "Purchase Invoice",
)
self.update_advance_tax_references(cancel=1)
diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
index fca7e3a887..9de9036887 100644
--- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
+++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
@@ -711,6 +711,7 @@
"label": "Valuation Rate",
"no_copy": 1,
"options": "Company:company:default_currency",
+ "precision": "6",
"print_hide": 1,
"read_only": 1
},
@@ -870,7 +871,7 @@
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2022-09-27 10:54:23.980713",
+ "modified": "2022-10-12 03:37:29.032732",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 2da515737a..97e5f4017e 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -12,44 +12,29 @@
"customer",
"customer_name",
"tax_id",
- "pos_profile",
- "is_pos",
- "is_consolidated",
- "is_return",
- "is_debit_note",
- "update_billed_amount_in_sales_order",
- "column_break1",
"company",
"company_tax_id",
+ "column_break1",
"posting_date",
"posting_time",
"set_posting_time",
"due_date",
+ "column_break_14",
+ "is_pos",
+ "pos_profile",
+ "is_consolidated",
+ "is_return",
"return_against",
+ "update_billed_amount_in_sales_order",
+ "is_debit_note",
"amended_from",
"accounting_dimensions_section",
- "project",
- "dimension_col_break",
"cost_center",
- "customer_po_details",
- "po_no",
- "column_break_23",
- "po_date",
- "address_and_contact",
- "customer_address",
- "address_display",
- "contact_person",
- "contact_display",
- "contact_mobile",
- "contact_email",
- "territory",
- "col_break4",
- "shipping_address_name",
- "shipping_address",
- "company_address",
- "company_address_display",
- "dispatch_address_name",
- "dispatch_address",
+ "dimension_col_break",
+ "project",
+ "column_break_27",
+ "campaign",
+ "source",
"currency_and_price_list",
"currency",
"conversion_rate",
@@ -58,60 +43,35 @@
"price_list_currency",
"plc_conversion_rate",
"ignore_pricing_rule",
- "sec_warehouse",
- "set_warehouse",
- "column_break_55",
- "set_target_warehouse",
"items_section",
- "update_stock",
"scan_barcode",
+ "update_stock",
+ "column_break_39",
+ "set_warehouse",
+ "set_target_warehouse",
+ "section_break_42",
"items",
- "pricing_rule_details",
- "pricing_rules",
- "packing_list",
- "packed_items",
- "product_bundle_help",
- "time_sheet_list",
- "timesheets",
- "total_billing_amount",
- "total_billing_hours",
"section_break_30",
"total_qty",
+ "total_net_weight",
+ "column_break_32",
"base_total",
"base_net_total",
- "column_break_32",
- "total_net_weight",
+ "column_break_52",
"total",
"net_total",
"taxes_section",
"taxes_and_charges",
"column_break_38",
"shipping_rule",
+ "column_break_55",
"tax_category",
"section_break_40",
"taxes",
- "sec_tax_breakup",
- "other_charges_calculation",
"section_break_43",
"base_total_taxes_and_charges",
"column_break_47",
"total_taxes_and_charges",
- "loyalty_points_redemption",
- "loyalty_points",
- "loyalty_amount",
- "redeem_loyalty_points",
- "column_break_77",
- "loyalty_program",
- "loyalty_redemption_account",
- "loyalty_redemption_cost_center",
- "section_break_49",
- "apply_discount_on",
- "is_cash_or_non_trade_discount",
- "base_discount_amount",
- "additional_discount_account",
- "column_break_51",
- "additional_discount_percentage",
- "discount_amount",
"totals",
"base_grand_total",
"base_rounding_adjustment",
@@ -125,21 +85,28 @@
"total_advance",
"outstanding_amount",
"disable_rounded_total",
- "column_break4",
- "write_off_amount",
- "base_write_off_amount",
- "write_off_outstanding_amount_automatically",
- "column_break_74",
- "write_off_account",
- "write_off_cost_center",
- "advances_section",
- "allocate_advances_automatically",
- "get_advances",
- "advances",
- "payment_schedule_section",
- "ignore_default_payment_terms_template",
- "payment_terms_template",
- "payment_schedule",
+ "section_break_49",
+ "apply_discount_on",
+ "base_discount_amount",
+ "is_cash_or_non_trade_discount",
+ "additional_discount_account",
+ "column_break_51",
+ "additional_discount_percentage",
+ "discount_amount",
+ "sec_tax_breakup",
+ "other_charges_calculation",
+ "pricing_rule_details",
+ "pricing_rules",
+ "packing_list",
+ "packed_items",
+ "product_bundle_help",
+ "time_sheet_list",
+ "timesheets",
+ "section_break_104",
+ "total_billing_hours",
+ "column_break_106",
+ "total_billing_amount",
+ "payments_tab",
"payments_section",
"cash_bank_account",
"payments",
@@ -152,47 +119,95 @@
"column_break_90",
"change_amount",
"account_for_change_amount",
+ "advances_section",
+ "allocate_advances_automatically",
+ "get_advances",
+ "advances",
+ "write_off_section",
+ "write_off_amount",
+ "base_write_off_amount",
+ "write_off_outstanding_amount_automatically",
+ "column_break_74",
+ "write_off_account",
+ "write_off_cost_center",
+ "loyalty_points_redemption",
+ "redeem_loyalty_points",
+ "loyalty_points",
+ "loyalty_amount",
+ "column_break_77",
+ "loyalty_program",
+ "loyalty_redemption_account",
+ "loyalty_redemption_cost_center",
+ "contact_and_address_tab",
+ "address_and_contact",
+ "customer_address",
+ "address_display",
+ "col_break4",
+ "contact_person",
+ "contact_display",
+ "contact_mobile",
+ "contact_email",
+ "territory",
+ "shipping_address_section",
+ "shipping_address_name",
+ "shipping_address",
+ "shipping_addr_col_break",
+ "dispatch_address_name",
+ "dispatch_address",
+ "company_address_section",
+ "company_address",
+ "company_addr_col_break",
+ "company_address_display",
+ "terms_tab",
+ "payment_schedule_section",
+ "ignore_default_payment_terms_template",
+ "payment_terms_template",
+ "payment_schedule",
"terms_section_break",
"tc_name",
"terms",
- "edit_printing_settings",
- "letter_head",
- "group_same_items",
- "select_print_heading",
- "column_break_84",
- "language",
- "more_information",
- "status",
- "inter_company_invoice_reference",
- "represents_company",
- "customer_group",
- "campaign",
- "col_break23",
- "is_internal_customer",
- "is_discounted",
- "source",
+ "more_info_tab",
+ "customer_po_details",
+ "po_no",
+ "column_break_23",
+ "po_date",
"more_info",
"debit_to",
"party_account_currency",
"is_opening",
"column_break8",
"unrealized_profit_loss_account",
- "remarks",
+ "against_income_account",
"sales_team_section_break",
"sales_partner",
- "column_break10",
"amount_eligible_for_commission",
+ "column_break10",
"commission_rate",
"total_commission",
"section_break2",
"sales_team",
+ "edit_printing_settings",
+ "letter_head",
+ "group_same_items",
+ "column_break_84",
+ "select_print_heading",
+ "language",
"subscription_section",
"from_date",
- "to_date",
- "column_break_140",
"auto_repeat",
+ "column_break_140",
+ "to_date",
"update_auto_repeat_reference",
- "against_income_account"
+ "more_information",
+ "status",
+ "inter_company_invoice_reference",
+ "represents_company",
+ "customer_group",
+ "col_break23",
+ "is_internal_customer",
+ "is_discounted",
+ "remarks",
+ "connections_tab"
],
"fields": [
{
@@ -453,12 +468,11 @@
"label": "Customer's Purchase Order Date"
},
{
- "collapsible": 1,
"fieldname": "address_and_contact",
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Address and Contact"
+ "label": "Billing Address"
},
{
"fieldname": "customer_address",
@@ -560,7 +574,6 @@
{
"fieldname": "company_address_display",
"fieldtype": "Small Text",
- "hidden": 1,
"hide_days": 1,
"hide_seconds": 1,
"label": "Company Address",
@@ -651,13 +664,6 @@
"label": "Ignore Pricing Rule",
"print_hide": 1
},
- {
- "fieldname": "sec_warehouse",
- "fieldtype": "Section Break",
- "hide_days": 1,
- "hide_seconds": 1,
- "label": "Warehouse"
- },
{
"depends_on": "update_stock",
"fieldname": "set_warehouse",
@@ -671,6 +677,7 @@
{
"fieldname": "items_section",
"fieldtype": "Section Break",
+ "hide_border": 1,
"hide_days": 1,
"hide_seconds": 1,
"label": "Items",
@@ -702,7 +709,6 @@
"fieldtype": "Table",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Items",
"oldfieldname": "entries",
"oldfieldtype": "Table",
"options": "Sales Invoice Item",
@@ -755,9 +761,10 @@
{
"collapsible": 1,
"collapsible_depends_on": "eval:doc.total_billing_amount > 0",
- "depends_on": "eval: !doc.is_return",
+ "depends_on": "eval:!doc.is_return",
"fieldname": "time_sheet_list",
"fieldtype": "Section Break",
+ "hide_border": 1,
"hide_days": 1,
"hide_seconds": 1,
"label": "Time Sheet List"
@@ -845,6 +852,7 @@
"read_only": 1
},
{
+ "depends_on": "total_net_weight",
"fieldname": "total_net_weight",
"fieldtype": "Float",
"hide_days": 1,
@@ -856,8 +864,10 @@
{
"fieldname": "taxes_section",
"fieldtype": "Section Break",
+ "hide_border": 1,
"hide_days": 1,
"hide_seconds": 1,
+ "label": "Taxes and Charges",
"oldfieldtype": "Section Break",
"options": "fa fa-money"
},
@@ -900,6 +910,7 @@
{
"fieldname": "section_break_40",
"fieldtype": "Section Break",
+ "hide_border": 1,
"hide_days": 1,
"hide_seconds": 1
},
@@ -908,7 +919,6 @@
"fieldtype": "Table",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Sales Taxes and Charges",
"oldfieldname": "other_charges",
"oldfieldtype": "Table",
"options": "Sales Taxes and Charges"
@@ -1046,7 +1056,6 @@
},
{
"collapsible": 1,
- "collapsible_depends_on": "discount_amount",
"fieldname": "section_break_49",
"fieldtype": "Section Break",
"hide_days": 1,
@@ -1102,6 +1111,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
+ "label": "Totals",
"oldfieldtype": "Section Break",
"options": "fa fa-money",
"print_hide": 1
@@ -1283,8 +1293,6 @@
"print_hide": 1
},
{
- "collapsible": 1,
- "collapsible_depends_on": "eval:(!doc.is_pos && !doc.is_return)",
"fieldname": "payment_schedule_section",
"fieldtype": "Section Break",
"hide_days": 1,
@@ -1314,7 +1322,9 @@
"print_hide": 1
},
{
- "depends_on": "eval:doc.is_pos===1||(doc.advances && doc.advances.length>0)",
+ "collapsible": 1,
+ "collapsible_depends_on": "eval:!doc.is_pos",
+ "depends_on": "eval:doc.is_pos===1",
"fieldname": "payments_section",
"fieldtype": "Section Break",
"hide_days": 1,
@@ -1352,6 +1362,7 @@
"hide_seconds": 1
},
{
+ "depends_on": "eval: doc.is_pos || doc.redeem_loyalty_points",
"fieldname": "base_paid_amount",
"fieldtype": "Currency",
"hide_days": 1,
@@ -1383,10 +1394,13 @@
"read_only": 1
},
{
+ "collapsible": 1,
+ "depends_on": "is_pos",
"fieldname": "section_break_88",
"fieldtype": "Section Break",
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "label": "Changes"
},
{
"depends_on": "is_pos",
@@ -1427,17 +1441,6 @@
"options": "Account",
"print_hide": 1
},
- {
- "collapsible": 1,
- "collapsible_depends_on": "write_off_amount",
- "depends_on": "grand_total",
- "fieldname": "column_break4",
- "fieldtype": "Section Break",
- "hide_days": 1,
- "hide_seconds": 1,
- "label": "Write Off",
- "width": "50%"
- },
{
"fieldname": "write_off_amount",
"fieldtype": "Currency",
@@ -1495,8 +1498,6 @@
"print_hide": 1
},
{
- "collapsible": 1,
- "collapsible_depends_on": "terms",
"fieldname": "terms_section_break",
"fieldtype": "Section Break",
"hide_days": 1,
@@ -1530,7 +1531,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Printing Settings"
+ "label": "Print Settings"
},
{
"allow_on_submit": 1,
@@ -1591,7 +1592,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "More Information"
+ "label": "Additional Info"
},
{
"fieldname": "inter_company_invoice_reference",
@@ -1814,7 +1815,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Subscription Section"
+ "label": "Subscription"
},
{
"allow_on_submit": 1,
@@ -1935,10 +1936,6 @@
"options": "Company",
"read_only": 1
},
- {
- "fieldname": "column_break_55",
- "fieldtype": "Column Break"
- },
{
"depends_on": "eval: doc.is_internal_customer && doc.update_stock",
"fieldname": "set_target_warehouse",
@@ -2009,6 +2006,97 @@
"fieldname": "is_cash_or_non_trade_discount",
"fieldtype": "Check",
"label": "Is Cash or Non Trade Discount"
+ },
+ {
+ "fieldname": "contact_and_address_tab",
+ "fieldtype": "Tab Break",
+ "label": "Contact & Address"
+ },
+ {
+ "fieldname": "payments_tab",
+ "fieldtype": "Tab Break",
+ "label": "Payments"
+ },
+ {
+ "fieldname": "terms_tab",
+ "fieldtype": "Tab Break",
+ "label": "Terms"
+ },
+ {
+ "fieldname": "more_info_tab",
+ "fieldtype": "Tab Break",
+ "label": "More Info"
+ },
+ {
+ "fieldname": "connections_tab",
+ "fieldtype": "Tab Break",
+ "label": "Connections",
+ "show_dashboard": 1
+ },
+ {
+ "fieldname": "column_break_14",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_39",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "section_break_42",
+ "fieldtype": "Section Break",
+ "hide_border": 1,
+ "hide_days": 1,
+ "hide_seconds": 1
+ },
+ {
+ "fieldname": "column_break_55",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "shipping_address_section",
+ "fieldtype": "Section Break",
+ "label": "Shipping Address"
+ },
+ {
+ "fieldname": "company_address_section",
+ "fieldtype": "Section Break",
+ "label": "Company Address"
+ },
+ {
+ "fieldname": "shipping_addr_col_break",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "company_addr_col_break",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_27",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_52",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "eval:(!doc.is_return && doc.total_billing_amount > 0)",
+ "fieldname": "section_break_104",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_106",
+ "fieldtype": "Column Break"
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "write_off_amount",
+ "depends_on": "grand_total",
+ "fieldname": "write_off_section",
+ "fieldtype": "Section Break",
+ "hide_days": 1,
+ "hide_seconds": 1,
+ "label": "Write Off",
+ "width": "50%"
}
],
"icon": "fa fa-file-text",
@@ -2021,7 +2109,7 @@
"link_fieldname": "consolidated_invoice"
}
],
- "modified": "2022-09-16 17:44:22.227332",
+ "modified": "2022-10-11 13:07:36.488095",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index afd5a59df4..0c03c550ba 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -2017,6 +2017,9 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
update_address(
target_doc, "shipping_address", "shipping_address_display", source_doc.customer_address
)
+ update_address(
+ target_doc, "billing_address", "billing_address_display", source_doc.customer_address
+ )
if currency:
target_doc.currency = currency
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index ce44ae304b..1ba782451b 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -32,10 +32,20 @@ from erpnext.stock.doctype.stock_entry.test_stock_entry import (
get_qty_after_transaction,
make_stock_entry,
)
-from erpnext.stock.utils import get_incoming_rate
+from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
+ create_stock_reconciliation,
+)
+from erpnext.stock.utils import get_incoming_rate, get_stock_balance
class TestSalesInvoice(unittest.TestCase):
+ def setUp(self):
+ from erpnext.stock.doctype.stock_ledger_entry.test_stock_ledger_entry import create_items
+
+ create_items(["_Test Internal Transfer Item"], uoms=[{"uom": "Box", "conversion_factor": 10}])
+ create_internal_parties()
+ setup_accounts()
+
def make(self):
w = frappe.copy_doc(test_records[0])
w.is_pos = 0
@@ -1705,7 +1715,7 @@ class TestSalesInvoice(unittest.TestCase):
si.save()
self.assertEqual(si.get("items")[0].rate, flt((price_list_rate * 25) / 100 + price_list_rate))
- def test_outstanding_amount_after_advance_jv_cancelation(self):
+ def test_outstanding_amount_after_advance_jv_cancellation(self):
from erpnext.accounts.doctype.journal_entry.test_journal_entry import (
test_records as jv_test_records,
)
@@ -1749,7 +1759,7 @@ class TestSalesInvoice(unittest.TestCase):
flt(si.rounded_total + si.total_advance, si.precision("outstanding_amount")),
)
- def test_outstanding_amount_after_advance_payment_entry_cancelation(self):
+ def test_outstanding_amount_after_advance_payment_entry_cancellation(self):
pe = frappe.get_doc(
{
"doctype": "Payment Entry",
@@ -2367,29 +2377,6 @@ class TestSalesInvoice(unittest.TestCase):
acc_settings.save()
def test_inter_company_transaction(self):
- from erpnext.selling.doctype.customer.test_customer import create_internal_customer
-
- create_internal_customer(
- customer_name="_Test Internal Customer",
- represents_company="_Test Company 1",
- allowed_to_interact_with="Wind Power LLC",
- )
-
- if not frappe.db.exists("Supplier", "_Test Internal Supplier"):
- supplier = frappe.get_doc(
- {
- "supplier_group": "_Test Supplier Group",
- "supplier_name": "_Test Internal Supplier",
- "doctype": "Supplier",
- "is_internal_supplier": 1,
- "represents_company": "Wind Power LLC",
- }
- )
-
- supplier.append("companies", {"company": "_Test Company 1"})
-
- supplier.insert()
-
si = create_sales_invoice(
company="Wind Power LLC",
customer="_Test Internal Customer",
@@ -2440,38 +2427,6 @@ class TestSalesInvoice(unittest.TestCase):
"Expenses Included In Valuation - _TC1",
)
- if not frappe.db.exists("Customer", "_Test Internal Customer"):
- customer = frappe.get_doc(
- {
- "customer_group": "_Test Customer Group",
- "customer_name": "_Test Internal Customer",
- "customer_type": "Individual",
- "doctype": "Customer",
- "territory": "_Test Territory",
- "is_internal_customer": 1,
- "represents_company": "_Test Company 1",
- }
- )
-
- customer.append("companies", {"company": "Wind Power LLC"})
-
- customer.insert()
-
- if not frappe.db.exists("Supplier", "_Test Internal Supplier"):
- supplier = frappe.get_doc(
- {
- "supplier_group": "_Test Supplier Group",
- "supplier_name": "_Test Internal Supplier",
- "doctype": "Supplier",
- "is_internal_supplier": 1,
- "represents_company": "Wind Power LLC",
- }
- )
-
- supplier.append("companies", {"company": "_Test Company 1"})
-
- supplier.insert()
-
# begin test
si = create_sales_invoice(
company="Wind Power LLC",
@@ -2541,34 +2496,9 @@ class TestSalesInvoice(unittest.TestCase):
se.cancel()
def test_internal_transfer_gl_entry(self):
- ## Create internal transfer account
- from erpnext.selling.doctype.customer.test_customer import create_internal_customer
-
- account = create_account(
- account_name="Unrealized Profit",
- parent_account="Current Liabilities - TCP1",
- company="_Test Company with perpetual inventory",
- )
-
- frappe.db.set_value(
- "Company", "_Test Company with perpetual inventory", "unrealized_profit_loss_account", account
- )
-
- customer = create_internal_customer(
- "_Test Internal Customer 2",
- "_Test Company with perpetual inventory",
- "_Test Company with perpetual inventory",
- )
-
- create_internal_supplier(
- "_Test Internal Supplier 2",
- "_Test Company with perpetual inventory",
- "_Test Company with perpetual inventory",
- )
-
si = create_sales_invoice(
company="_Test Company with perpetual inventory",
- customer=customer,
+ customer="_Test Internal Customer 2",
debit_to="Debtors - TCP1",
warehouse="Stores - TCP1",
income_account="Sales - TCP1",
@@ -2582,7 +2512,7 @@ class TestSalesInvoice(unittest.TestCase):
si.update_stock = 1
si.items[0].target_warehouse = "Work In Progress - TCP1"
- # Add stock to stores for succesful stock transfer
+ # Add stock to stores for successful stock transfer
make_stock_entry(
target="Stores - TCP1", company="_Test Company with perpetual inventory", qty=1, basic_rate=100
)
@@ -2638,6 +2568,77 @@ class TestSalesInvoice(unittest.TestCase):
check_gl_entries(self, target_doc.name, pi_gl_entries, add_days(nowdate(), -1))
+ def test_internal_transfer_gl_precision_issues(self):
+ # Make a stock queue of an item with two valuations
+
+ # Remove all existing stock for this
+ if get_stock_balance("_Test Internal Transfer Item", "Stores - TCP1", "2022-04-10"):
+ create_stock_reconciliation(
+ item_code="_Test Internal Transfer Item",
+ warehouse="Stores - TCP1",
+ qty=0,
+ rate=0,
+ company="_Test Company with perpetual inventory",
+ expense_account="Stock Adjustment - TCP1"
+ if frappe.get_all("Stock Ledger Entry")
+ else "Temporary Opening - TCP1",
+ posting_date="2020-04-10",
+ posting_time="14:00",
+ )
+
+ make_stock_entry(
+ item_code="_Test Internal Transfer Item",
+ target="Stores - TCP1",
+ qty=9000000,
+ basic_rate=52.0,
+ posting_date="2020-04-10",
+ posting_time="14:00",
+ )
+ make_stock_entry(
+ item_code="_Test Internal Transfer Item",
+ target="Stores - TCP1",
+ qty=60000000,
+ basic_rate=52.349777,
+ posting_date="2020-04-10",
+ posting_time="14:00",
+ )
+
+ # Make an internal transfer Sales Invoice Stock in non stock uom to check
+ # for rounding errors while converting to stock uom
+ si = create_sales_invoice(
+ company="_Test Company with perpetual inventory",
+ customer="_Test Internal Customer 2",
+ item_code="_Test Internal Transfer Item",
+ qty=5000000,
+ uom="Box",
+ debit_to="Debtors - TCP1",
+ warehouse="Stores - TCP1",
+ income_account="Sales - TCP1",
+ expense_account="Cost of Goods Sold - TCP1",
+ cost_center="Main - TCP1",
+ currency="INR",
+ do_not_save=1,
+ )
+
+ # Check GL Entries with precision
+ si.update_stock = 1
+ si.items[0].target_warehouse = "Work In Progress - TCP1"
+ si.items[0].conversion_factor = 10
+ si.save()
+ si.submit()
+
+ # Check if adjustment entry is created
+ self.assertTrue(
+ frappe.db.exists(
+ "GL Entry",
+ {
+ "voucher_type": "Sales Invoice",
+ "voucher_no": si.name,
+ "remarks": "Rounding gain/loss Entry for Stock Transfer",
+ },
+ )
+ )
+
def test_item_tax_net_range(self):
item = create_item("T Shirt")
@@ -3077,7 +3078,7 @@ class TestSalesInvoice(unittest.TestCase):
[deferred_account, 2022.47, 0.0, "2019-03-15"],
]
- gl_entries = gl_entries = frappe.db.sql(
+ gl_entries = frappe.db.sql(
"""select account, debit, credit, posting_date
from `tabGL Entry`
where voucher_type='Journal Entry' and voucher_detail_no=%s and posting_date <= %s
@@ -3227,6 +3228,22 @@ class TestSalesInvoice(unittest.TestCase):
self.assertTrue(return_si.docstatus == 1)
+ def test_sales_invoice_with_payable_tax_account(self):
+ si = create_sales_invoice(do_not_submit=True)
+ si.append(
+ "taxes",
+ {
+ "charge_type": "Actual",
+ "account_head": "Creditors - _TC",
+ "description": "Test",
+ "cost_center": "Main - _TC",
+ "tax_amount": 10,
+ "total": 10,
+ "dont_recompute_tax": 0,
+ },
+ )
+ self.assertRaises(frappe.ValidationError, si.submit)
+
def get_sales_invoice_for_e_invoice():
si = make_sales_invoice_for_ewaybill()
@@ -3306,6 +3323,7 @@ def create_sales_invoice(**args):
"item_name": args.item_name or "_Test Item",
"description": args.description or "_Test Item",
"warehouse": args.warehouse or "_Test Warehouse - _TC",
+ "target_warehouse": args.target_warehouse,
"qty": args.qty or 1,
"uom": args.uom or "Nos",
"stock_uom": args.uom or "Nos",
@@ -3318,7 +3336,7 @@ def create_sales_invoice(**args):
"asset": args.asset or None,
"cost_center": args.cost_center or "_Test Cost Center - _TC",
"serial_no": args.serial_no,
- "conversion_factor": 1,
+ "conversion_factor": args.get("conversion_factor", 1),
"incoming_rate": args.incoming_rate or 0,
"batch_no": args.batch_no or None,
},
@@ -3431,6 +3449,34 @@ def get_taxes_and_charges():
]
+def create_internal_parties():
+ from erpnext.selling.doctype.customer.test_customer import create_internal_customer
+
+ create_internal_customer(
+ customer_name="_Test Internal Customer",
+ represents_company="_Test Company 1",
+ allowed_to_interact_with="Wind Power LLC",
+ )
+
+ create_internal_customer(
+ customer_name="_Test Internal Customer 2",
+ represents_company="_Test Company with perpetual inventory",
+ allowed_to_interact_with="_Test Company with perpetual inventory",
+ )
+
+ create_internal_supplier(
+ supplier_name="_Test Internal Supplier",
+ represents_company="Wind Power LLC",
+ allowed_to_interact_with="_Test Company 1",
+ )
+
+ create_internal_supplier(
+ supplier_name="_Test Internal Supplier 2",
+ represents_company="_Test Company with perpetual inventory",
+ allowed_to_interact_with="_Test Company with perpetual inventory",
+ )
+
+
def create_internal_supplier(supplier_name, represents_company, allowed_to_interact_with):
if not frappe.db.exists("Supplier", supplier_name):
supplier = frappe.get_doc(
@@ -3453,6 +3499,19 @@ def create_internal_supplier(supplier_name, represents_company, allowed_to_inter
return supplier_name
+def setup_accounts():
+ ## Create internal transfer account
+ account = create_account(
+ account_name="Unrealized Profit",
+ parent_account="Current Liabilities - TCP1",
+ company="_Test Company with perpetual inventory",
+ )
+
+ frappe.db.set_value(
+ "Company", "_Test Company with perpetual inventory", "unrealized_profit_loss_account", account
+ )
+
+
def add_taxes(doc):
doc.append(
"taxes",
diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
index 4f97b63789..a307a6c17c 100644
--- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
+++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
@@ -820,6 +820,7 @@
"label": "Incoming Rate (Costing)",
"no_copy": 1,
"options": "Company:company:default_currency",
+ "precision": "6",
"print_hide": 1
},
{
@@ -875,7 +876,7 @@
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2022-09-06 14:17:43.394309",
+ "modified": "2022-10-10 20:57:38.340026",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 95ba3d86ce..d7bf991688 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -460,10 +460,6 @@ def reconcile_against_document(args): # nosemgrep
frappe.flags.ignore_party_validation = False
- if entry.voucher_type in ("Payment Entry", "Journal Entry"):
- if hasattr(doc, "update_expense_claim"):
- doc.update_expense_claim()
-
def check_if_advance_entry_modified(args):
"""
@@ -1171,6 +1167,10 @@ def _delete_gl_entries(voucher_type, voucher_no):
where voucher_type=%s and voucher_no=%s""",
(voucher_type, voucher_no),
)
+ ple = qb.DocType("Payment Ledger Entry")
+ qb.from_(ple).delete().where(
+ (ple.voucher_type == voucher_type) & (ple.voucher_no == voucher_no)
+ ).run()
def sort_stock_vouchers_by_posting_date(
@@ -1368,9 +1368,8 @@ def check_and_delete_linked_reports(report):
frappe.delete_doc("Desktop Icon", icon)
-def create_payment_ledger_entry(
- gl_entries, cancel=0, adv_adj=0, update_outstanding="Yes", from_repost=0
-):
+def get_payment_ledger_entries(gl_entries, cancel=0):
+ ple_map = []
if gl_entries:
ple = None
@@ -1410,44 +1409,57 @@ def create_payment_ledger_entry(
dr_or_cr *= -1
dr_or_cr_account_currency *= -1
- ple = frappe.get_doc(
- {
- "doctype": "Payment Ledger Entry",
- "posting_date": gle.posting_date,
- "company": gle.company,
- "account_type": account_type,
- "account": gle.account,
- "party_type": gle.party_type,
- "party": gle.party,
- "cost_center": gle.cost_center,
- "finance_book": gle.finance_book,
- "due_date": gle.due_date,
- "voucher_type": gle.voucher_type,
- "voucher_no": gle.voucher_no,
- "against_voucher_type": gle.against_voucher_type
- if gle.against_voucher_type
- else gle.voucher_type,
- "against_voucher_no": gle.against_voucher if gle.against_voucher else gle.voucher_no,
- "account_currency": gle.account_currency,
- "amount": dr_or_cr,
- "amount_in_account_currency": dr_or_cr_account_currency,
- "delinked": True if cancel else False,
- "remarks": gle.remarks,
- }
+ ple = frappe._dict(
+ doctype="Payment Ledger Entry",
+ posting_date=gle.posting_date,
+ company=gle.company,
+ account_type=account_type,
+ account=gle.account,
+ party_type=gle.party_type,
+ party=gle.party,
+ cost_center=gle.cost_center,
+ finance_book=gle.finance_book,
+ due_date=gle.due_date,
+ voucher_type=gle.voucher_type,
+ voucher_no=gle.voucher_no,
+ against_voucher_type=gle.against_voucher_type
+ if gle.against_voucher_type
+ else gle.voucher_type,
+ against_voucher_no=gle.against_voucher if gle.against_voucher else gle.voucher_no,
+ account_currency=gle.account_currency,
+ amount=dr_or_cr,
+ amount_in_account_currency=dr_or_cr_account_currency,
+ delinked=True if cancel else False,
+ remarks=gle.remarks,
)
dimensions_and_defaults = get_dimensions()
if dimensions_and_defaults:
for dimension in dimensions_and_defaults[0]:
- ple.set(dimension.fieldname, gle.get(dimension.fieldname))
+ ple[dimension.fieldname] = gle.get(dimension.fieldname)
- if cancel:
- delink_original_entry(ple)
- ple.flags.ignore_permissions = 1
- ple.flags.adv_adj = adv_adj
- ple.flags.from_repost = from_repost
- ple.flags.update_outstanding = update_outstanding
- ple.submit()
+ ple_map.append(ple)
+ return ple_map
+
+
+def create_payment_ledger_entry(
+ gl_entries, cancel=0, adv_adj=0, update_outstanding="Yes", from_repost=0
+):
+ if gl_entries:
+ ple_map = get_payment_ledger_entries(gl_entries, cancel=cancel)
+
+ for entry in ple_map:
+
+ ple = frappe.get_doc(entry)
+
+ if cancel:
+ delink_original_entry(ple)
+
+ ple.flags.ignore_permissions = 1
+ ple.flags.adv_adj = adv_adj
+ ple.flags.from_repost = from_repost
+ ple.flags.update_outstanding = update_outstanding
+ ple.submit()
def update_voucher_outstanding(voucher_type, voucher_no, account, party_type, party):
@@ -1467,7 +1479,12 @@ def update_voucher_outstanding(voucher_type, voucher_no, account, party_type, pa
# on cancellation outstanding can be an empty list
voucher_outstanding = ple_query.get_voucher_outstandings(vouchers, common_filter=common_filter)
- if voucher_type in ["Sales Invoice", "Purchase Invoice", "Fees"] and voucher_outstanding:
+ if (
+ voucher_type in ["Sales Invoice", "Purchase Invoice", "Fees"]
+ and party_type
+ and party
+ and voucher_outstanding
+ ):
outstanding = voucher_outstanding[0]
ref_doc = frappe.get_doc(voucher_type, voucher_no)
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index fb8f25a0df..2193985ff2 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -12,43 +12,24 @@
"title",
"naming_series",
"supplier",
- "get_items_from_open_material_requests",
"supplier_name",
+ "order_confirmation_no",
+ "order_confirmation_date",
+ "get_items_from_open_material_requests",
+ "column_break_7",
+ "transaction_date",
+ "schedule_date",
+ "column_break1",
+ "company",
"apply_tds",
"tax_withholding_category",
"is_subcontracted",
"supplier_warehouse",
- "column_break1",
- "company",
- "transaction_date",
- "schedule_date",
- "order_confirmation_no",
- "order_confirmation_date",
"amended_from",
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"project",
- "drop_ship",
- "customer",
- "customer_name",
- "column_break_19",
- "customer_contact_person",
- "customer_contact_display",
- "customer_contact_mobile",
- "customer_contact_email",
- "section_addresses",
- "supplier_address",
- "address_display",
- "contact_person",
- "contact_display",
- "contact_mobile",
- "contact_email",
- "col_break_address",
- "shipping_address",
- "shipping_address_display",
- "billing_address",
- "billing_address_display",
"currency_and_price_list",
"currency",
"conversion_rate",
@@ -57,7 +38,6 @@
"price_list_currency",
"plc_conversion_rate",
"ignore_pricing_rule",
- "section_break_45",
"before_items_section",
"scan_barcode",
"set_from_warehouse",
@@ -67,10 +47,11 @@
"items",
"sb_last_purchase",
"total_qty",
+ "total_net_weight",
+ "column_break_40",
"base_total",
"base_net_total",
"column_break_26",
- "total_net_weight",
"total",
"net_total",
"section_break_48",
@@ -79,14 +60,13 @@
"set_reserve_warehouse",
"supplied_items",
"taxes_section",
+ "taxes_and_charges",
+ "column_break_53",
"tax_category",
"column_break_50",
"shipping_rule",
"section_break_52",
- "taxes_and_charges",
"taxes",
- "sec_tax_breakup",
- "other_charges_calculation",
"totals",
"base_taxes_and_charges_added",
"base_taxes_and_charges_deducted",
@@ -95,12 +75,6 @@
"taxes_and_charges_added",
"taxes_and_charges_deducted",
"total_taxes_and_charges",
- "discount_section",
- "apply_discount_on",
- "base_discount_amount",
- "column_break_45",
- "additional_discount_percentage",
- "discount_amount",
"totals_section",
"base_grand_total",
"base_rounding_adjustment",
@@ -113,37 +87,73 @@
"disable_rounded_total",
"in_words",
"advance_paid",
+ "discount_section",
+ "apply_discount_on",
+ "base_discount_amount",
+ "column_break_45",
+ "additional_discount_percentage",
+ "discount_amount",
+ "sec_tax_breakup",
+ "other_charges_calculation",
+ "address_and_contact_tab",
+ "section_addresses",
+ "supplier_address",
+ "address_display",
+ "col_break_address",
+ "contact_person",
+ "contact_display",
+ "contact_mobile",
+ "contact_email",
+ "company_shipping_address_section",
+ "shipping_address",
+ "column_break_99",
+ "shipping_address_display",
+ "company_billing_address_section",
+ "billing_address",
+ "column_break_103",
+ "billing_address_display",
+ "drop_ship",
+ "customer",
+ "customer_name",
+ "column_break_19",
+ "customer_contact_person",
+ "customer_contact_display",
+ "customer_contact_mobile",
+ "customer_contact_email",
+ "terms_tab",
"payment_schedule_section",
"payment_terms_template",
"payment_schedule",
+ "terms_section_break",
+ "tc_name",
+ "terms",
+ "more_info_tab",
"tracking_section",
"status",
"column_break_75",
"per_billed",
"per_received",
- "terms_section_break",
- "tc_name",
- "terms",
"column_break5",
"letter_head",
- "select_print_heading",
- "column_break_86",
- "language",
"group_same_items",
+ "column_break_86",
+ "select_print_heading",
+ "language",
"subscription_section",
"from_date",
"to_date",
"column_break_97",
"auto_repeat",
"update_auto_repeat_reference",
- "more_info",
+ "additional_info_section",
+ "is_internal_supplier",
+ "represents_company",
"ref_sq",
"column_break_74",
"party_account_currency",
- "is_internal_supplier",
- "represents_company",
"inter_company_order_reference",
- "is_old_subcontracting_flow"
+ "is_old_subcontracting_flow",
+ "dashboard"
],
"fields": [
{
@@ -267,8 +277,9 @@
"read_only": 1
},
{
+ "depends_on": "eval:doc.customer",
"fieldname": "drop_ship",
- "fieldtype": "Section Break",
+ "fieldtype": "Tab Break",
"label": "Drop Ship"
},
{
@@ -299,7 +310,6 @@
{
"fieldname": "customer_contact_display",
"fieldtype": "Small Text",
- "hidden": 1,
"label": "Customer Contact",
"print_hide": 1
},
@@ -319,10 +329,9 @@
"print_hide": 1
},
{
- "collapsible": 1,
"fieldname": "section_addresses",
"fieldtype": "Section Break",
- "label": "Address and Contact"
+ "label": "Supplier Address"
},
{
"fieldname": "supplier_address",
@@ -445,7 +454,6 @@
"print_hide": 1
},
{
- "description": "Sets 'Warehouse' in each row of the Items table.",
"fieldname": "set_warehouse",
"fieldtype": "Link",
"label": "Set Target Warehouse",
@@ -483,7 +491,6 @@
"allow_bulk_edit": 1,
"fieldname": "items",
"fieldtype": "Table",
- "label": "Items",
"oldfieldname": "po_details",
"oldfieldtype": "Table",
"options": "Purchase Order Item",
@@ -570,6 +577,7 @@
"read_only": 1
},
{
+ "depends_on": "total_net_weight",
"fieldname": "total_net_weight",
"fieldtype": "Float",
"label": "Total Net Weight",
@@ -579,6 +587,8 @@
{
"fieldname": "taxes_section",
"fieldtype": "Section Break",
+ "hide_border": 1,
+ "label": "Taxes and Charges",
"oldfieldtype": "Section Break",
"options": "fa fa-money"
},
@@ -633,7 +643,6 @@
{
"fieldname": "totals",
"fieldtype": "Section Break",
- "label": "Taxes and Charges",
"oldfieldtype": "Section Break",
"options": "fa fa-money"
},
@@ -698,7 +707,6 @@
"read_only": 1
},
{
- "depends_on": "total_taxes_and_charges",
"fieldname": "total_taxes_and_charges",
"fieldtype": "Currency",
"label": "Total Taxes and Charges",
@@ -708,7 +716,6 @@
},
{
"collapsible": 1,
- "collapsible_depends_on": "apply_discount_on",
"fieldname": "discount_section",
"fieldtype": "Section Break",
"label": "Additional Discount"
@@ -773,7 +780,6 @@
"read_only": 1
},
{
- "description": "In Words will be visible once you save the Purchase Order.",
"fieldname": "base_in_words",
"fieldtype": "Data",
"label": "In Words (Company Currency)",
@@ -851,7 +857,6 @@
"read_only": 1
},
{
- "collapsible": 1,
"fieldname": "payment_schedule_section",
"fieldtype": "Section Break",
"label": "Payment Terms"
@@ -871,11 +876,10 @@
"print_hide": 1
},
{
- "collapsible": 1,
"collapsible_depends_on": "terms",
"fieldname": "terms_section_break",
"fieldtype": "Section Break",
- "label": "Terms and Conditions",
+ "label": "Terms & Conditions",
"oldfieldtype": "Section Break",
"options": "fa fa-legal"
},
@@ -895,13 +899,6 @@
"oldfieldname": "terms",
"oldfieldtype": "Text Editor"
},
- {
- "collapsible": 1,
- "fieldname": "more_info",
- "fieldtype": "Section Break",
- "label": "More Information",
- "oldfieldtype": "Section Break"
- },
{
"default": "Draft",
"fieldname": "status",
@@ -1023,7 +1020,7 @@
"collapsible": 1,
"fieldname": "subscription_section",
"fieldtype": "Section Break",
- "label": "Subscription Section"
+ "label": "Auto Repeat"
},
{
"allow_on_submit": 1,
@@ -1098,7 +1095,9 @@
},
{
"fieldname": "before_items_section",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "hide_border": 1,
+ "label": "Items"
},
{
"fieldname": "items_col_break",
@@ -1133,10 +1132,6 @@
"label": "Tax Withholding Category",
"options": "Tax Withholding Category"
},
- {
- "fieldname": "section_break_45",
- "fieldtype": "Section Break"
- },
{
"collapsible": 1,
"fieldname": "accounting_dimensions_section",
@@ -1173,13 +1168,71 @@
"fieldtype": "Link",
"label": "Set From Warehouse",
"options": "Warehouse"
+ },
+ {
+ "fieldname": "terms_tab",
+ "fieldtype": "Tab Break",
+ "label": "Terms"
+ },
+ {
+ "fieldname": "more_info_tab",
+ "fieldtype": "Tab Break",
+ "label": "More Info"
+ },
+ {
+ "fieldname": "dashboard",
+ "fieldtype": "Tab Break",
+ "label": "Dashboard",
+ "show_dashboard": 1
+ },
+ {
+ "fieldname": "column_break_7",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_40",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_53",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "address_and_contact_tab",
+ "fieldtype": "Tab Break",
+ "label": "Address & Contact"
+ },
+ {
+ "fieldname": "company_shipping_address_section",
+ "fieldtype": "Section Break",
+ "label": "Company Shipping Address"
+ },
+ {
+ "fieldname": "company_billing_address_section",
+ "fieldtype": "Section Break",
+ "label": "Company Billing Address"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "additional_info_section",
+ "fieldtype": "Section Break",
+ "label": "Additional Info",
+ "oldfieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_99",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_103",
+ "fieldtype": "Column Break"
}
],
"icon": "fa fa-file-text",
"idx": 105,
"is_submittable": 1,
"links": [],
- "modified": "2022-09-16 17:45:04.954055",
+ "modified": "2022-10-11 13:01:41.674352",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index bcedd4d0a1..c224b611e5 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -18,7 +18,7 @@ from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import (
get_party_tax_withholding_details,
)
-from erpnext.accounts.party import get_party_account_currency
+from erpnext.accounts.party import get_party_account, get_party_account_currency
from erpnext.buying.utils import check_on_hold_or_closed_status, validate_for_items
from erpnext.controllers.buying_controller import BuyingController
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
@@ -558,6 +558,7 @@ def get_mapped_purchase_invoice(source_name, target_doc=None, ignore_permissions
target.set_advances()
target.set_payment_schedule()
+ target.credit_to = get_party_account("Supplier", source.supplier, source.company)
def update_item(obj, target, source_parent):
target.amount = flt(obj.amount) - flt(obj.billed_amt)
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
index 8d1939a101..16365618ca 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
@@ -13,19 +13,13 @@
"naming_series",
"supplier",
"supplier_name",
- "column_break1",
"company",
+ "column_break1",
+ "status",
"transaction_date",
"valid_till",
"quotation_number",
"amended_from",
- "address_section",
- "supplier_address",
- "contact_person",
- "address_display",
- "contact_display",
- "contact_mobile",
- "contact_email",
"currency_and_price_list",
"currency",
"conversion_rate",
@@ -36,25 +30,23 @@
"ignore_pricing_rule",
"items_section",
"items",
- "pricing_rule_details",
- "pricing_rules",
"section_break_22",
"total_qty",
+ "total_net_weight",
+ "column_break_26",
"base_total",
"base_net_total",
"column_break_24",
"total",
"net_total",
- "total_net_weight",
"taxes_section",
+ "taxes_and_charges",
+ "column_break_34",
"tax_category",
"column_break_36",
"shipping_rule",
"section_break_38",
- "taxes_and_charges",
"taxes",
- "tax_breakup",
- "other_charges_calculation",
"totals",
"base_taxes_and_charges_added",
"base_taxes_and_charges_deducted",
@@ -80,24 +72,36 @@
"rounded_total",
"in_words",
"disable_rounded_total",
- "terms_section_break",
+ "tax_breakup",
+ "other_charges_calculation",
+ "pricing_rule_details",
+ "pricing_rules",
+ "address_and_contact_tab",
+ "supplier_address",
+ "address_display",
+ "column_break_72",
+ "contact_person",
+ "contact_display",
+ "contact_mobile",
+ "contact_email",
+ "terms_tab",
"tc_name",
"terms",
+ "more_info_tab",
"printing_settings",
- "select_print_heading",
- "group_same_items",
- "column_break_72",
"letter_head",
+ "group_same_items",
+ "column_break_85",
+ "select_print_heading",
"language",
"subscription_section",
"auto_repeat",
"update_auto_repeat_reference",
"more_info",
- "status",
- "column_break_57",
"is_subcontracted",
- "reference",
- "opportunity"
+ "column_break_57",
+ "opportunity",
+ "connections_tab"
],
"fields": [
{
@@ -146,7 +150,7 @@
"fieldname": "supplier_name",
"fieldtype": "Data",
"in_global_search": 1,
- "label": "Name",
+ "label": "Supplier Name",
"read_only": 1
},
{
@@ -193,12 +197,6 @@
"reqd": 1,
"search_index": 1
},
- {
- "collapsible": 1,
- "fieldname": "address_section",
- "fieldtype": "Section Break",
- "label": "Address and Contact"
- },
{
"fieldname": "supplier_address",
"fieldtype": "Link",
@@ -309,6 +307,8 @@
{
"fieldname": "items_section",
"fieldtype": "Section Break",
+ "hide_border": 1,
+ "label": "Items",
"oldfieldtype": "Section Break",
"options": "fa fa-shopping-cart"
},
@@ -316,7 +316,6 @@
"allow_bulk_edit": 1,
"fieldname": "items",
"fieldtype": "Table",
- "label": "Items",
"oldfieldname": "po_details",
"oldfieldtype": "Table",
"options": "Supplier Quotation Item",
@@ -394,6 +393,7 @@
{
"fieldname": "taxes_section",
"fieldtype": "Section Break",
+ "hide_border": 1,
"label": "Taxes and Charges",
"oldfieldtype": "Section Break",
"options": "fa fa-money"
@@ -417,7 +417,8 @@
},
{
"fieldname": "section_break_38",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "hide_border": 1
},
{
"fieldname": "taxes_and_charges",
@@ -523,7 +524,6 @@
},
{
"collapsible": 1,
- "collapsible_depends_on": "discount_amount",
"fieldname": "section_break_41",
"fieldtype": "Section Break",
"label": "Additional Discount"
@@ -563,7 +563,8 @@
},
{
"fieldname": "section_break_46",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "label": "Totals"
},
{
"fieldname": "base_grand_total",
@@ -654,19 +655,10 @@
"fieldtype": "Check",
"label": "Disable Rounded Total"
},
- {
- "collapsible": 1,
- "collapsible_depends_on": "terms",
- "fieldname": "terms_section_break",
- "fieldtype": "Section Break",
- "label": "Terms and Conditions",
- "oldfieldtype": "Section Break",
- "options": "fa fa-legal"
- },
{
"fieldname": "tc_name",
"fieldtype": "Link",
- "label": "Terms",
+ "label": "Terms Template",
"oldfieldname": "tc_name",
"oldfieldtype": "Link",
"options": "Terms and Conditions",
@@ -729,7 +721,7 @@
{
"fieldname": "subscription_section",
"fieldtype": "Section Break",
- "label": "Auto Repeat Section"
+ "label": "Auto Repeat"
},
{
"fieldname": "auto_repeat",
@@ -751,7 +743,7 @@
"collapsible": 1,
"fieldname": "more_info",
"fieldtype": "Section Break",
- "label": "More Information",
+ "label": "Additional Info",
"oldfieldtype": "Section Break",
"options": "fa fa-file-text"
},
@@ -779,11 +771,6 @@
"label": "Is Subcontracted",
"print_hide": 1
},
- {
- "fieldname": "reference",
- "fieldtype": "Section Break",
- "label": "Reference"
- },
{
"fieldname": "opportunity",
"fieldtype": "Link",
@@ -803,6 +790,39 @@
"fieldname": "quotation_number",
"fieldtype": "Data",
"label": "Quotation Number"
+ },
+ {
+ "fieldname": "address_and_contact_tab",
+ "fieldtype": "Tab Break",
+ "label": "Address & Contact"
+ },
+ {
+ "fieldname": "terms_tab",
+ "fieldtype": "Tab Break",
+ "label": "Terms"
+ },
+ {
+ "fieldname": "more_info_tab",
+ "fieldtype": "Tab Break",
+ "label": "More Info"
+ },
+ {
+ "fieldname": "connections_tab",
+ "fieldtype": "Tab Break",
+ "label": "Connections",
+ "show_dashboard": 1
+ },
+ {
+ "fieldname": "column_break_26",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_34",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_85",
+ "fieldtype": "Column Break"
}
],
"icon": "fa fa-shopping-cart",
@@ -810,7 +830,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2022-03-14 16:13:20.284572",
+ "modified": "2022-09-27 18:20:09.462037",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Quotation",
diff --git a/erpnext/buying/report/procurement_tracker/procurement_tracker.py b/erpnext/buying/report/procurement_tracker/procurement_tracker.py
index d70ac46ce3..71019e8037 100644
--- a/erpnext/buying/report/procurement_tracker/procurement_tracker.py
+++ b/erpnext/buying/report/procurement_tracker/procurement_tracker.py
@@ -127,32 +127,27 @@ def get_columns(filters):
return columns
-def get_conditions(filters):
- conditions = ""
-
+def apply_filters_on_query(filters, parent, child, query):
if filters.get("company"):
- conditions += " AND parent.company=%s" % frappe.db.escape(filters.get("company"))
+ query = query.where(parent.company == filters.get("company"))
if filters.get("cost_center") or filters.get("project"):
- conditions += """
- AND (child.`cost_center`=%s OR child.`project`=%s)
- """ % (
- frappe.db.escape(filters.get("cost_center")),
- frappe.db.escape(filters.get("project")),
+ query = query.where(
+ (child.cost_center == filters.get("cost_center")) | (child.project == filters.get("project"))
)
if filters.get("from_date"):
- conditions += " AND parent.transaction_date>='%s'" % filters.get("from_date")
+ query = query.where(parent.transaction_date >= filters.get("from_date"))
if filters.get("to_date"):
- conditions += " AND parent.transaction_date<='%s'" % filters.get("to_date")
- return conditions
+ query = query.where(parent.transaction_date <= filters.get("to_date"))
+
+ return query
def get_data(filters):
- conditions = get_conditions(filters)
- purchase_order_entry = get_po_entries(conditions)
- mr_records, procurement_record_against_mr = get_mapped_mr_details(conditions)
+ purchase_order_entry = get_po_entries(filters)
+ mr_records, procurement_record_against_mr = get_mapped_mr_details(filters)
pr_records = get_mapped_pr_records()
pi_records = get_mapped_pi_records()
@@ -187,11 +182,15 @@ def get_data(filters):
return procurement_record
-def get_mapped_mr_details(conditions):
+def get_mapped_mr_details(filters):
mr_records = {}
- mr_details = frappe.db.sql(
- """
- SELECT
+ parent = frappe.qb.DocType("Material Request")
+ child = frappe.qb.DocType("Material Request Item")
+
+ query = (
+ frappe.qb.from_(parent)
+ .from_(child)
+ .select(
parent.transaction_date,
parent.per_ordered,
parent.owner,
@@ -203,18 +202,13 @@ def get_mapped_mr_details(conditions):
child.uom,
parent.status,
child.project,
- child.cost_center
- FROM `tabMaterial Request` parent, `tabMaterial Request Item` child
- WHERE
- parent.per_ordered>=0
- AND parent.name=child.parent
- AND parent.docstatus=1
- {conditions}
- """.format(
- conditions=conditions
- ),
- as_dict=1,
- ) # nosec
+ child.cost_center,
+ )
+ .where((parent.per_ordered >= 0) & (parent.name == child.parent) & (parent.docstatus == 1))
+ )
+ query = apply_filters_on_query(filters, parent, child, query)
+
+ mr_details = query.run(as_dict=True)
procurement_record_against_mr = []
for record in mr_details:
@@ -241,46 +235,49 @@ def get_mapped_mr_details(conditions):
def get_mapped_pi_records():
- return frappe._dict(
- frappe.db.sql(
- """
- SELECT
- pi_item.po_detail,
- pi_item.base_amount
- FROM `tabPurchase Invoice Item` as pi_item
- INNER JOIN `tabPurchase Order` as po
- ON pi_item.`purchase_order` = po.`name`
- WHERE
- pi_item.docstatus = 1
- AND po.status not in ('Closed','Completed','Cancelled')
- AND pi_item.po_detail IS NOT NULL
- """
+ po = frappe.qb.DocType("Purchase Order")
+ pi_item = frappe.qb.DocType("Purchase Invoice Item")
+ pi_records = (
+ frappe.qb.from_(pi_item)
+ .inner_join(po)
+ .on(pi_item.purchase_order == po.name)
+ .select(pi_item.po_detail, pi_item.base_amount)
+ .where(
+ (pi_item.docstatus == 1)
+ & (po.status.notin(("Closed", "Completed", "Cancelled")))
+ & (pi_item.po_detail.isnotnull())
)
- )
+ ).run()
+
+ return frappe._dict(pi_records)
def get_mapped_pr_records():
- return frappe._dict(
- frappe.db.sql(
- """
- SELECT
- pr_item.purchase_order_item,
- pr.posting_date
- FROM `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pr_item
- WHERE
- pr.docstatus=1
- AND pr.name=pr_item.parent
- AND pr_item.purchase_order_item IS NOT NULL
- AND pr.status not in ('Closed','Completed','Cancelled')
- """
+ pr = frappe.qb.DocType("Purchase Receipt")
+ pr_item = frappe.qb.DocType("Purchase Receipt Item")
+ pr_records = (
+ frappe.qb.from_(pr)
+ .from_(pr_item)
+ .select(pr_item.purchase_order_item, pr.posting_date)
+ .where(
+ (pr.docstatus == 1)
+ & (pr.name == pr_item.parent)
+ & (pr_item.purchase_order_item.isnotnull())
+ & (pr.status.notin(("Closed", "Completed", "Cancelled")))
)
- )
+ ).run()
+
+ return frappe._dict(pr_records)
-def get_po_entries(conditions):
- return frappe.db.sql(
- """
- SELECT
+def get_po_entries(filters):
+ parent = frappe.qb.DocType("Purchase Order")
+ child = frappe.qb.DocType("Purchase Order Item")
+
+ query = (
+ frappe.qb.from_(parent)
+ .from_(child)
+ .select(
child.name,
child.parent,
child.cost_center,
@@ -297,17 +294,15 @@ def get_po_entries(conditions):
parent.transaction_date,
parent.supplier,
parent.status,
- parent.owner
- FROM `tabPurchase Order` parent, `tabPurchase Order Item` child
- WHERE
- parent.docstatus = 1
- AND parent.name = child.parent
- AND parent.status not in ('Closed','Completed','Cancelled')
- {conditions}
- GROUP BY
- parent.name, child.item_code
- """.format(
- conditions=conditions
- ),
- as_dict=1,
- ) # nosec
+ parent.owner,
+ )
+ .where(
+ (parent.docstatus == 1)
+ & (parent.name == child.parent)
+ & (parent.status.notin(("Closed", "Completed", "Cancelled")))
+ )
+ .groupby(parent.name, child.item_code)
+ )
+ query = apply_filters_on_query(filters, parent, child, query)
+
+ return query.run(as_dict=True)
diff --git a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py
index a5c464910d..e10c0e2fcc 100644
--- a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py
+++ b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py
@@ -6,6 +6,7 @@ import copy
import frappe
from frappe import _
+from frappe.query_builder.functions import IfNull
from frappe.utils import date_diff, flt, getdate
@@ -16,9 +17,7 @@ def execute(filters=None):
validate_filters(filters)
columns = get_columns(filters)
- conditions = get_conditions(filters)
-
- data = get_data(conditions, filters)
+ data = get_data(filters)
if not data:
return [], [], None, []
@@ -37,60 +36,61 @@ def validate_filters(filters):
frappe.throw(_("To Date cannot be before From Date."))
-def get_conditions(filters):
- conditions = ""
- if filters.get("from_date") and filters.get("to_date"):
- conditions += " and po.transaction_date between %(from_date)s and %(to_date)s"
+def get_data(filters):
+ po = frappe.qb.DocType("Purchase Order")
+ po_item = frappe.qb.DocType("Purchase Order Item")
+ pi_item = frappe.qb.DocType("Purchase Invoice Item")
- for field in ["company", "name"]:
+ query = (
+ frappe.qb.from_(po)
+ .from_(po_item)
+ .left_join(pi_item)
+ .on(pi_item.po_detail == po_item.name)
+ .select(
+ po.transaction_date.as_("date"),
+ po_item.schedule_date.as_("required_date"),
+ po_item.project,
+ po.name.as_("purchase_order"),
+ po.status,
+ po.supplier,
+ po_item.item_code,
+ po_item.qty,
+ po_item.received_qty,
+ (po_item.qty - po_item.received_qty).as_("pending_qty"),
+ IfNull(pi_item.qty, 0).as_("billed_qty"),
+ po_item.base_amount.as_("amount"),
+ (po_item.received_qty * po_item.base_rate).as_("received_qty_amount"),
+ (po_item.billed_amt * IfNull(po.conversion_rate, 1)).as_("billed_amount"),
+ (po_item.base_amount - (po_item.billed_amt * IfNull(po.conversion_rate, 1))).as_(
+ "pending_amount"
+ ),
+ po.set_warehouse.as_("warehouse"),
+ po.company,
+ po_item.name,
+ )
+ .where(
+ (po_item.parent == po.name) & (po.status.notin(("Stopped", "Closed"))) & (po.docstatus == 1)
+ )
+ .groupby(po_item.name)
+ .orderby(po.transaction_date)
+ )
+
+ for field in ("company", "name"):
if filters.get(field):
- conditions += f" and po.{field} = %({field})s"
+ query = query.where(po[field] == filters.get(field))
+
+ if filters.get("from_date") and filters.get("to_date"):
+ query = query.where(
+ po.transaction_date.between(filters.get("from_date"), filters.get("to_date"))
+ )
if filters.get("status"):
- conditions += " and po.status in %(status)s"
+ query = query.where(po.status.isin(filters.get("status")))
if filters.get("project"):
- conditions += " and poi.project = %(project)s"
+ query = query.where(po_item.project == filters.get("project"))
- return conditions
-
-
-def get_data(conditions, filters):
- data = frappe.db.sql(
- """
- SELECT
- po.transaction_date as date,
- poi.schedule_date as required_date,
- poi.project,
- po.name as purchase_order,
- po.status, po.supplier, poi.item_code,
- poi.qty, poi.received_qty,
- (poi.qty - poi.received_qty) AS pending_qty,
- IFNULL(pii.qty, 0) as billed_qty,
- poi.base_amount as amount,
- (poi.received_qty * poi.base_rate) as received_qty_amount,
- (poi.billed_amt * IFNULL(po.conversion_rate, 1)) as billed_amount,
- (poi.base_amount - (poi.billed_amt * IFNULL(po.conversion_rate, 1))) as pending_amount,
- po.set_warehouse as warehouse,
- po.company, poi.name
- FROM
- `tabPurchase Order` po,
- `tabPurchase Order Item` poi
- LEFT JOIN `tabPurchase Invoice Item` pii
- ON pii.po_detail = poi.name
- WHERE
- poi.parent = po.name
- and po.status not in ('Stopped', 'Closed')
- and po.docstatus = 1
- {0}
- GROUP BY poi.name
- ORDER BY po.transaction_date ASC
- """.format(
- conditions
- ),
- filters,
- as_dict=1,
- )
+ data = query.run(as_dict=True)
return data
diff --git a/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py
index 3013b6d160..a728290961 100644
--- a/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py
+++ b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py
@@ -16,8 +16,7 @@ def execute(filters=None):
return [], []
columns = get_columns(filters)
- conditions = get_conditions(filters)
- supplier_quotation_data = get_data(filters, conditions)
+ supplier_quotation_data = get_data(filters)
data, chart_data = prepare_data(supplier_quotation_data, filters)
message = get_message()
@@ -25,50 +24,51 @@ def execute(filters=None):
return columns, data, message, chart_data
-def get_conditions(filters):
- conditions = ""
+def get_data(filters):
+ sq = frappe.qb.DocType("Supplier Quotation")
+ sq_item = frappe.qb.DocType("Supplier Quotation Item")
+
+ query = (
+ frappe.qb.from_(sq_item)
+ .from_(sq)
+ .select(
+ sq_item.parent,
+ sq_item.item_code,
+ sq_item.qty,
+ sq_item.stock_qty,
+ sq_item.amount,
+ sq_item.uom,
+ sq_item.stock_uom,
+ sq_item.request_for_quotation,
+ sq_item.lead_time_days,
+ sq.supplier.as_("supplier_name"),
+ sq.valid_till,
+ )
+ .where(
+ (sq_item.parent == sq.name)
+ & (sq_item.docstatus < 2)
+ & (sq.company == filters.get("company"))
+ & (sq.transaction_date.between(filters.get("from_date"), filters.get("to_date")))
+ )
+ .orderby(sq.transaction_date, sq_item.item_code)
+ )
+
if filters.get("item_code"):
- conditions += " AND sqi.item_code = %(item_code)s"
+ query = query.where(sq_item.item_code == filters.get("item_code"))
if filters.get("supplier_quotation"):
- conditions += " AND sqi.parent in %(supplier_quotation)s"
+ query = query.where(sq_item.parent.isin(filters.get("supplier_quotation")))
if filters.get("request_for_quotation"):
- conditions += " AND sqi.request_for_quotation = %(request_for_quotation)s"
+ query = query.where(sq_item.request_for_quotation == filters.get("request_for_quotation"))
if filters.get("supplier"):
- conditions += " AND sq.supplier in %(supplier)s"
+ query = query.where(sq.supplier.isin(filters.get("supplier")))
if not filters.get("include_expired"):
- conditions += " AND sq.status != 'Expired'"
+ query = query.where(sq.status != "Expired")
- return conditions
-
-
-def get_data(filters, conditions):
- supplier_quotation_data = frappe.db.sql(
- """
- SELECT
- sqi.parent, sqi.item_code,
- sqi.qty, sqi.stock_qty, sqi.amount,
- sqi.uom, sqi.stock_uom,
- sqi.request_for_quotation,
- sqi.lead_time_days, sq.supplier as supplier_name, sq.valid_till
- FROM
- `tabSupplier Quotation Item` sqi,
- `tabSupplier Quotation` sq
- WHERE
- sqi.parent = sq.name
- AND sqi.docstatus < 2
- AND sq.company = %(company)s
- AND sq.transaction_date between %(from_date)s and %(to_date)s
- {0}
- order by sq.transaction_date, sqi.item_code""".format(
- conditions
- ),
- filters,
- as_dict=1,
- )
+ supplier_quotation_data = query.run(as_dict=True)
return supplier_quotation_data
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 5e9c069b1d..e8e9076975 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -442,11 +442,17 @@ class SellingController(StockController):
# For internal transfers use incoming rate as the valuation rate
if self.is_internal_transfer():
if d.doctype == "Packed Item":
- incoming_rate = flt(d.incoming_rate * d.conversion_factor, d.precision("incoming_rate"))
+ incoming_rate = flt(
+ flt(d.incoming_rate, d.precision("incoming_rate")) * d.conversion_factor,
+ d.precision("incoming_rate"),
+ )
if d.incoming_rate != incoming_rate:
d.incoming_rate = incoming_rate
else:
- rate = flt(d.incoming_rate * d.conversion_factor, d.precision("rate"))
+ rate = flt(
+ flt(d.incoming_rate, d.precision("incoming_rate")) * d.conversion_factor,
+ d.precision("rate"),
+ )
if d.rate != rate:
d.rate = rate
frappe.msgprint(
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 9149b4d857..98dc58677b 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -142,13 +142,15 @@ class StockController(AccountsController):
warehouse_with_no_account = []
precision = self.get_debit_field_precision()
for item_row in voucher_details:
-
sle_list = sle_map.get(item_row.name)
+ sle_rounding_diff = 0.0
if sle_list:
for sle in sle_list:
if warehouse_account.get(sle.warehouse):
# from warehouse account
+ sle_rounding_diff += flt(sle.stock_value_difference)
+
self.check_expense_account(item_row)
# expense account/ target_warehouse / source_warehouse
@@ -191,6 +193,46 @@ class StockController(AccountsController):
elif sle.warehouse not in warehouse_with_no_account:
warehouse_with_no_account.append(sle.warehouse)
+ if abs(sle_rounding_diff) > (1.0 / (10**precision)) and self.is_internal_transfer():
+ warehouse_asset_account = ""
+ if self.get("is_internal_customer"):
+ warehouse_asset_account = warehouse_account[item_row.get("target_warehouse")]["account"]
+ elif self.get("is_internal_supplier"):
+ warehouse_asset_account = warehouse_account[item_row.get("warehouse")]["account"]
+
+ expense_account = frappe.db.get_value("Company", self.company, "default_expense_account")
+
+ gl_list.append(
+ self.get_gl_dict(
+ {
+ "account": expense_account,
+ "against": warehouse_asset_account,
+ "cost_center": item_row.cost_center,
+ "project": item_row.project or self.get("project"),
+ "remarks": _("Rounding gain/loss Entry for Stock Transfer"),
+ "debit": sle_rounding_diff,
+ "is_opening": item_row.get("is_opening") or self.get("is_opening") or "No",
+ },
+ warehouse_account[sle.warehouse]["account_currency"],
+ item=item_row,
+ )
+ )
+
+ gl_list.append(
+ self.get_gl_dict(
+ {
+ "account": warehouse_asset_account,
+ "against": expense_account,
+ "cost_center": item_row.cost_center,
+ "remarks": _("Rounding gain/loss Entry for Stock Transfer"),
+ "credit": sle_rounding_diff,
+ "project": item_row.get("project") or self.get("project"),
+ "is_opening": item_row.get("is_opening") or self.get("is_opening") or "No",
+ },
+ item=item_row,
+ )
+ )
+
if warehouse_with_no_account:
for wh in warehouse_with_no_account:
if frappe.db.get_value("Warehouse", wh, "company"):
diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json
index 99c00ad6e6..8f8a086d99 100644
--- a/erpnext/crm/doctype/lead/lead.json
+++ b/erpnext/crm/doctype/lead/lead.json
@@ -375,7 +375,7 @@
"depends_on": "eval:!doc.__islocal",
"fieldname": "notes_tab",
"fieldtype": "Tab Break",
- "label": "Notes"
+ "label": "Comments"
},
{
"collapsible": 1,
@@ -506,7 +506,7 @@
{
"fieldname": "dashboard_tab",
"fieldtype": "Tab Break",
- "label": "Dashboard",
+ "label": "Connections",
"show_dashboard": 1
}
],
@@ -514,7 +514,7 @@
"idx": 5,
"image_field": "image",
"links": [],
- "modified": "2022-08-09 18:26:17.101521",
+ "modified": "2022-10-13 12:42:04.277879",
"modified_by": "Administrator",
"module": "CRM",
"name": "Lead",
diff --git a/erpnext/crm/doctype/opportunity/opportunity.json b/erpnext/crm/doctype/opportunity/opportunity.json
index fed0c7c79a..07641d20c3 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.json
+++ b/erpnext/crm/doctype/opportunity/opportunity.json
@@ -544,14 +544,14 @@
"depends_on": "eval:!doc.__islocal",
"fieldname": "dashboard_tab",
"fieldtype": "Tab Break",
- "label": "Dashboard",
+ "label": "Connections",
"show_dashboard": 1
},
{
"depends_on": "eval:!doc.__islocal",
"fieldname": "notes_tab",
"fieldtype": "Tab Break",
- "label": "Notes"
+ "label": "Comments"
},
{
"fieldname": "notes_html",
@@ -622,7 +622,7 @@
"icon": "fa fa-info-sign",
"idx": 195,
"links": [],
- "modified": "2022-08-09 18:26:37.235964",
+ "modified": "2022-10-13 12:42:21.545636",
"modified_by": "Administrator",
"module": "CRM",
"name": "Opportunity",
diff --git a/erpnext/crm/doctype/prospect/prospect.json b/erpnext/crm/doctype/prospect/prospect.json
index 820a6c72ea..d32311bc4e 100644
--- a/erpnext/crm/doctype/prospect/prospect.json
+++ b/erpnext/crm/doctype/prospect/prospect.json
@@ -128,7 +128,7 @@
"depends_on": "eval:!doc.__islocal",
"fieldname": "notes_section",
"fieldtype": "Tab Break",
- "label": "Notes"
+ "label": "Comments"
},
{
"depends_on": "eval: !doc.__islocal",
@@ -218,7 +218,7 @@
],
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2022-08-09 18:26:56.950185",
+ "modified": "2022-10-13 12:29:33.674561",
"modified_by": "Administrator",
"module": "CRM",
"name": "Prospect",
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index b8f51f839c..6bc17a3675 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -274,8 +274,6 @@ has_website_permission = {
"Timesheet": "erpnext.controllers.website_list_for_contact.has_website_permission",
}
-dump_report_map = "erpnext.startup.report_data_map.data_map"
-
before_tests = "erpnext.setup.utils.before_tests"
standard_queries = {
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index ed45106634..fb94e8aa99 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -133,7 +133,7 @@ class JobCard(Document):
(%(from_time)s <= jctl.from_time and %(to_time)s >= jctl.to_time) {0}
)
and jctl.name != %(name)s and jc.name != %(parent)s and jc.docstatus < 2 {1}
- order by jctl.to_time desc limit 1""".format(
+ order by jctl.to_time desc""".format(
extra_cond, validate_overlap_for
),
{
diff --git a/erpnext/manufacturing/doctype/job_card/test_job_card.py b/erpnext/manufacturing/doctype/job_card/test_job_card.py
index ac7114138c..4d2dab73e3 100644
--- a/erpnext/manufacturing/doctype/job_card/test_job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/test_job_card.py
@@ -136,6 +136,45 @@ class TestJobCard(FrappeTestCase):
)
self.assertRaises(OverlapError, jc2.save)
+ def test_job_card_overlap_with_capacity(self):
+ wo2 = make_wo_order_test_record(item="_Test FG Item 2", qty=2)
+
+ workstation = make_workstation(workstation_name=random_string(5)).name
+ frappe.db.set_value("Workstation", workstation, "production_capacity", 1)
+
+ jc1 = frappe.get_last_doc("Job Card", {"work_order": self.work_order.name})
+ jc2 = frappe.get_last_doc("Job Card", {"work_order": wo2.name})
+
+ jc1.workstation = workstation
+ jc1.append(
+ "time_logs",
+ {"from_time": "2021-01-01 00:00:00", "to_time": "2021-01-01 08:00:00", "completed_qty": 1},
+ )
+ jc1.save()
+
+ jc2.workstation = workstation
+
+ # add a new entry in same time slice
+ jc2.append(
+ "time_logs",
+ {"from_time": "2021-01-01 00:01:00", "to_time": "2021-01-01 06:00:00", "completed_qty": 1},
+ )
+ self.assertRaises(OverlapError, jc2.save)
+
+ frappe.db.set_value("Workstation", workstation, "production_capacity", 2)
+ jc2.load_from_db()
+
+ jc2.workstation = workstation
+
+ # add a new entry in same time slice
+ jc2.append(
+ "time_logs",
+ {"from_time": "2021-01-01 00:01:00", "to_time": "2021-01-01 06:00:00", "completed_qty": 1},
+ )
+
+ jc2.save()
+ self.assertTrue(jc2.name)
+
def test_job_card_multiple_materials_transfer(self):
"Test transferring RMs separately against Job Card with multiple RMs."
self.transfer_material_against = "Job Card"
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 4bb4dcc648..000ee07f2c 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -27,6 +27,7 @@ from erpnext.manufacturing.doctype.bom.bom import get_children as get_bom_childr
from erpnext.manufacturing.doctype.bom.bom import validate_bom_no
from erpnext.manufacturing.doctype.work_order.work_order import get_item_details
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
+from erpnext.stock.get_item_details import get_conversion_factor
from erpnext.utilities.transaction_base import validate_uom_is_integer
@@ -648,13 +649,23 @@ class ProductionPlan(Document):
else:
material_request = material_request_map[key]
+ conversion_factor = 1.0
+ if (
+ material_request_type == "Purchase"
+ and item_doc.purchase_uom
+ and item_doc.purchase_uom != item_doc.stock_uom
+ ):
+ conversion_factor = (
+ get_conversion_factor(item_doc.name, item_doc.purchase_uom).get("conversion_factor") or 1.0
+ )
+
# add item
material_request.append(
"items",
{
"item_code": item.item_code,
"from_warehouse": item.from_warehouse,
- "qty": item.quantity,
+ "qty": item.quantity / conversion_factor,
"schedule_date": schedule_date,
"warehouse": item.warehouse,
"sales_order": item.sales_order,
diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
index 60e6398072..c4ab0f886f 100644
--- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
@@ -806,6 +806,35 @@ class TestProductionPlan(FrappeTestCase):
self.assertEqual(pln.status, "Completed")
self.assertEqual(pln.po_items[0].produced_qty, 5)
+ def test_material_request_item_for_purchase_uom(self):
+ from erpnext.stock.doctype.item.test_item import make_item
+
+ fg_item = make_item(properties={"is_stock_item": 1, "stock_uom": "_Test UOM 1"}).name
+ bom_item = make_item(
+ properties={"is_stock_item": 1, "stock_uom": "_Test UOM 1", "purchase_uom": "Nos"}
+ ).name
+
+ if not frappe.db.exists("UOM Conversion Detail", {"parent": bom_item, "uom": "Nos"}):
+ doc = frappe.get_doc("Item", bom_item)
+ doc.append("uoms", {"uom": "Nos", "conversion_factor": 10})
+ doc.save()
+
+ make_bom(item=fg_item, raw_materials=[bom_item], source_warehouse="_Test Warehouse - _TC")
+
+ pln = create_production_plan(
+ item_code=fg_item, planned_qty=10, ignore_existing_ordered_qty=1, stock_uom="_Test UOM 1"
+ )
+
+ pln.make_material_request()
+ for row in frappe.get_all(
+ "Material Request Item",
+ filters={"production_plan": pln.name},
+ fields=["item_code", "uom", "qty"],
+ ):
+ self.assertEqual(row.item_code, bom_item)
+ self.assertEqual(row.uom, "Nos")
+ self.assertEqual(row.qty, 1)
+
def create_production_plan(**args):
"""
diff --git a/erpnext/projects/workspace/projects/projects.json b/erpnext/projects/workspace/projects/projects.json
index 1253649e49..4bdb1db387 100644
--- a/erpnext/projects/workspace/projects/projects.json
+++ b/erpnext/projects/workspace/projects/projects.json
@@ -5,7 +5,7 @@
"label": "Open Projects"
}
],
- "content": "[{\"type\":\"chart\",\"data\":{\"chart_name\":\"Open Projects\",\"col\":12}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"Your Shortcuts\",\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Task\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Project\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Timesheet\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Project Billing Summary\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"Reports & Masters\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Projects\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Time Tracking\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}}]",
+ "content": "[{\"type\":\"chart\",\"data\":{\"chart_name\":\"Open Projects\",\"col\":12}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"Your Shortcuts\",\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Task\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Project\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Timesheet\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Project Billing Summary\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"Reports & Masters\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Projects\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Time Tracking\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}}]",
"creation": "2020-03-02 15:46:04.874669",
"docstatus": 0,
"doctype": "Workspace",
@@ -170,9 +170,27 @@
"link_type": "Report",
"onboard": 0,
"type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Settings",
+ "link_count": 1,
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Projects Settings",
+ "link_count": 0,
+ "link_to": "Projects Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
}
],
- "modified": "2022-06-28 12:31:30.167740",
+ "modified": "2022-10-11 22:39:10.436311",
"modified_by": "Administrator",
"module": "Projects",
"name": "Projects",
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index c17610b58a..7fecb18fad 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -426,6 +426,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
if(!this.validate_company_and_party()) {
this.frm.fields_dict["items"].grid.grid_rows[item.idx - 1].remove();
} else {
+ item.pricing_rules = ''
return this.frm.call({
method: "erpnext.stock.get_item_details.get_item_details",
child: item,
@@ -1045,6 +1046,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
uom(doc, cdt, cdn) {
var me = this;
var item = frappe.get_doc(cdt, cdn);
+ item.pricing_rules = ''
if(item.item_code && item.uom) {
return this.frm.call({
method: "erpnext.stock.get_item_details.get_conversion_factor",
@@ -1121,6 +1123,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
qty(doc, cdt, cdn) {
let item = frappe.get_doc(cdt, cdn);
+ item.pricing_rules = ''
this.conversion_factor(doc, cdt, cdn, true);
this.calculate_stock_uom_rate(doc, cdt, cdn);
this.apply_pricing_rule(item, true);
diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js
index 1a309ba015..b0082bdb28 100644
--- a/erpnext/public/js/financial_statements.js
+++ b/erpnext/public/js/financial_statements.js
@@ -28,7 +28,7 @@ erpnext.financial_statements = {
},
"open_general_ledger": function(data) {
if (!data.account) return;
- var project = $.grep(frappe.query_report.filters, function(e){ return e.df.fieldname == 'project'; })
+ let project = $.grep(frappe.query_report.filters, function(e){ return e.df.fieldname == 'project'; });
frappe.route_options = {
"account": data.account,
@@ -37,7 +37,16 @@ erpnext.financial_statements = {
"to_date": data.to_date || data.year_end_date,
"project": (project && project.length > 0) ? project[0].$input.val() : ""
};
- frappe.set_route("query-report", "General Ledger");
+
+ let report = "General Ledger";
+
+ if (["Payable", "Receivable"].includes(data.account_type)) {
+ report = data.account_type == "Payable" ? "Accounts Payable" : "Accounts Receivable";
+ frappe.route_options["party_account"] = data.account;
+ frappe.route_options["report_date"] = data.year_end_date;
+ }
+
+ frappe.set_route("query-report", report);
},
"tree": true,
"name_field": "account",
diff --git a/erpnext/regional/united_arab_emirates/setup.py b/erpnext/regional/united_arab_emirates/setup.py
index be621bcdd1..36a079546e 100644
--- a/erpnext/regional/united_arab_emirates/setup.py
+++ b/erpnext/regional/united_arab_emirates/setup.py
@@ -37,7 +37,7 @@ def make_custom_fields():
fieldname="vat_section",
label="VAT Details",
fieldtype="Section Break",
- insert_after="group_same_items",
+ insert_after="language",
print_hide=1,
collapsible=1,
),
diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js
index 70ae085051..6b42e4daea 100644
--- a/erpnext/selling/doctype/quotation/quotation.js
+++ b/erpnext/selling/doctype/quotation/quotation.js
@@ -84,11 +84,12 @@ erpnext.selling.QuotationController = class QuotationController extends erpnext.
}
}
- if(doc.docstatus == 1 && !(['Lost', 'Ordered']).includes(doc.status)) {
- if(!doc.valid_till || frappe.datetime.get_diff(doc.valid_till, frappe.datetime.get_today()) >= 0) {
- cur_frm.add_custom_button(__('Sales Order'),
- cur_frm.cscript['Make Sales Order'], __('Create'));
- }
+ if (doc.docstatus == 1 && !["Lost", "Ordered"].includes(doc.status)) {
+ this.frm.add_custom_button(
+ __("Sales Order"),
+ this.frm.cscript["Make Sales Order"],
+ __("Create")
+ );
if(doc.status!=="Ordered") {
this.frm.add_custom_button(__('Set as Lost'), () => {
diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json
index c58a46ba51..fa64b1625b 100644
--- a/erpnext/selling/doctype/quotation/quotation.json
+++ b/erpnext/selling/doctype/quotation/quotation.json
@@ -15,26 +15,13 @@
"quotation_to",
"party_name",
"customer_name",
- "column_break1",
- "amended_from",
- "company",
+ "column_break_7",
"transaction_date",
"valid_till",
+ "column_break1",
"order_type",
- "contact_section",
- "customer_address",
- "address_display",
- "contact_person",
- "contact_display",
- "contact_mobile",
- "contact_email",
- "col_break98",
- "shipping_address_name",
- "shipping_address",
- "company_address",
- "company_address_display",
- "customer_group",
- "territory",
+ "company",
+ "amended_from",
"currency_and_price_list",
"currency",
"conversion_rate",
@@ -43,79 +30,105 @@
"price_list_currency",
"plc_conversion_rate",
"ignore_pricing_rule",
- "section_break_33",
- "scan_barcode",
"items_section",
+ "scan_barcode",
"items",
- "bundle_items_section",
- "packed_items",
- "pricing_rule_details",
- "pricing_rules",
"sec_break23",
"total_qty",
+ "total_net_weight",
+ "column_break_28",
"base_total",
"base_net_total",
- "column_break_28",
+ "column_break_31",
"total",
"net_total",
- "total_net_weight",
"taxes_section",
+ "taxes_and_charges",
+ "column_break_36",
"tax_category",
"column_break_34",
"shipping_rule",
"section_break_36",
- "taxes_and_charges",
"taxes",
- "sec_tax_breakup",
- "other_charges_calculation",
"section_break_39",
"base_total_taxes_and_charges",
"column_break_42",
"total_taxes_and_charges",
- "section_break_44",
- "coupon_code",
- "referral_sales_partner",
- "apply_discount_on",
- "base_discount_amount",
- "column_break_46",
- "additional_discount_percentage",
- "discount_amount",
"totals",
"base_grand_total",
"base_rounding_adjustment",
- "base_in_words",
"base_rounded_total",
+ "base_in_words",
"column_break3",
"grand_total",
"rounding_adjustment",
"rounded_total",
"in_words",
+ "section_break_44",
+ "apply_discount_on",
+ "base_discount_amount",
+ "coupon_code",
+ "column_break_46",
+ "additional_discount_percentage",
+ "discount_amount",
+ "referral_sales_partner",
+ "sec_tax_breakup",
+ "other_charges_calculation",
+ "bundle_items_section",
+ "packed_items",
+ "pricing_rule_details",
+ "pricing_rules",
+ "address_and_contact_tab",
+ "billing_address_section",
+ "customer_address",
+ "address_display",
+ "col_break98",
+ "contact_person",
+ "contact_display",
+ "contact_mobile",
+ "contact_email",
+ "shipping_address_section",
+ "shipping_address_name",
+ "column_break_81",
+ "shipping_address",
+ "company_address_section",
+ "company_address",
+ "column_break_87",
+ "company_address_display",
+ "terms_tab",
"payment_schedule_section",
"payment_terms_template",
"payment_schedule",
"terms_section_break",
"tc_name",
"terms",
+ "more_info_tab",
+ "subscription_section",
+ "auto_repeat",
+ "update_auto_repeat_reference",
"print_settings",
"letter_head",
"group_same_items",
"column_break_73",
"select_print_heading",
"language",
- "subscription_section",
- "auto_repeat",
- "update_auto_repeat_reference",
- "more_info",
+ "lost_reasons_section",
+ "lost_reasons",
+ "competitors",
+ "column_break_117",
+ "order_lost_reason",
+ "additional_info_section",
+ "status",
+ "customer_group",
+ "territory",
+ "column_break_108",
"campaign",
"source",
- "order_lost_reason",
"column_break4",
- "status",
- "enq_det",
- "supplier_quotation",
"opportunity",
- "lost_reasons",
- "competitors"
+ "supplier_quotation",
+ "enq_det",
+ "connections_tab"
],
"fields": [
{
@@ -241,14 +254,6 @@
"print_hide": 1,
"reqd": 1
},
- {
- "collapsible": 1,
- "depends_on": "party_name",
- "fieldname": "contact_section",
- "fieldtype": "Section Break",
- "label": "Address and Contact",
- "options": "fa fa-bullhorn"
- },
{
"fieldname": "customer_address",
"fieldtype": "Link",
@@ -296,7 +301,7 @@
"read_only": 1
},
{
- "depends_on": "eval:doc.quotation_to=='Customer' && doc.party_name",
+ "depends_on": "eval:(doc.quotation_to=='Customer' && doc.party_name)",
"fieldname": "col_break98",
"fieldtype": "Column Break",
"width": "50%"
@@ -316,7 +321,7 @@
"read_only": 1
},
{
- "depends_on": "eval:doc.quotation_to=='Customer' && doc.party_name",
+ "depends_on": "eval:(doc.quotation_to=='Customer' && doc.party_name)",
"fieldname": "customer_group",
"fieldtype": "Link",
"hidden": 1,
@@ -408,6 +413,8 @@
{
"fieldname": "items_section",
"fieldtype": "Section Break",
+ "hide_border": 1,
+ "label": "Items",
"oldfieldtype": "Section Break",
"options": "fa fa-shopping-cart"
},
@@ -415,7 +422,6 @@
"allow_bulk_edit": 1,
"fieldname": "items",
"fieldtype": "Table",
- "label": "Items",
"oldfieldname": "quotation_details",
"oldfieldtype": "Table",
"options": "Quotation Item",
@@ -423,6 +429,7 @@
"width": "40px"
},
{
+ "collapsible": 1,
"fieldname": "pricing_rule_details",
"fieldtype": "Section Break",
"label": "Pricing Rules"
@@ -483,6 +490,7 @@
"read_only": 1
},
{
+ "depends_on": "total_net_weight",
"fieldname": "total_net_weight",
"fieldtype": "Float",
"label": "Total Net Weight",
@@ -492,6 +500,7 @@
{
"fieldname": "taxes_section",
"fieldtype": "Section Break",
+ "hide_border": 1,
"label": "Taxes and Charges",
"oldfieldtype": "Section Break",
"options": "fa fa-money"
@@ -517,7 +526,8 @@
},
{
"fieldname": "section_break_36",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "hide_border": 1
},
{
"fieldname": "taxes_and_charges",
@@ -579,10 +589,9 @@
},
{
"collapsible": 1,
- "collapsible_depends_on": "discount_amount",
"fieldname": "section_break_44",
"fieldtype": "Section Break",
- "label": "Additional Discount and Coupon Code"
+ "label": "Additional Discount"
},
{
"fieldname": "coupon_code",
@@ -632,6 +641,7 @@
{
"fieldname": "totals",
"fieldtype": "Section Break",
+ "label": "Totals",
"oldfieldtype": "Section Break",
"options": "fa fa-money",
"print_hide": 1
@@ -657,7 +667,6 @@
"read_only": 1
},
{
- "description": "In Words will be visible once you save the Quotation.",
"fieldname": "base_in_words",
"fieldtype": "Data",
"label": "In Words (Company Currency)",
@@ -665,8 +674,7 @@
"oldfieldname": "in_words",
"oldfieldtype": "Data",
"print_hide": 1,
- "read_only": 1,
- "width": "200px"
+ "read_only": 1
},
{
"fieldname": "base_rounded_total",
@@ -749,7 +757,6 @@
"print_hide": 1
},
{
- "collapsible": 1,
"collapsible_depends_on": "terms",
"fieldname": "terms_section_break",
"fieldtype": "Section Break",
@@ -824,7 +831,7 @@
{
"fieldname": "subscription_section",
"fieldtype": "Section Break",
- "label": "Auto Repeat Section"
+ "label": "Auto Repeat"
},
{
"fieldname": "auto_repeat",
@@ -837,20 +844,11 @@
},
{
"allow_on_submit": 1,
- "depends_on": "eval: doc.auto_repeat",
+ "depends_on": "eval:doc.auto_repeat",
"fieldname": "update_auto_repeat_reference",
"fieldtype": "Button",
"label": "Update Auto Repeat Reference"
},
- {
- "collapsible": 1,
- "fieldname": "more_info",
- "fieldtype": "Section Break",
- "label": "More Information",
- "oldfieldtype": "Section Break",
- "options": "fa fa-file-text",
- "print_hide": 1
- },
{
"fieldname": "campaign",
"fieldtype": "Link",
@@ -871,7 +869,7 @@
},
{
"allow_on_submit": 1,
- "depends_on": "eval:doc.status===\"Lost\"",
+ "depends_on": "eval:doc.status=='Lost'",
"fieldname": "order_lost_reason",
"fieldtype": "Small Text",
"label": "Detailed Reason",
@@ -934,7 +932,6 @@
"read_only": 1
},
{
- "depends_on": "packed_items",
"fieldname": "packed_items",
"fieldtype": "Table",
"label": "Bundle Items",
@@ -943,7 +940,6 @@
},
{
"collapsible": 1,
- "collapsible_depends_on": "packed_items",
"depends_on": "packed_items",
"fieldname": "bundle_items_section",
"fieldtype": "Section Break",
@@ -970,22 +966,99 @@
"label": "Company Address",
"read_only": 1
},
- {
- "fieldname": "section_break_33",
- "fieldtype": "Section Break"
- },
{
"fieldname": "scan_barcode",
"fieldtype": "Data",
"label": "Scan Barcode",
"options": "Barcode"
+ },
+ {
+ "fieldname": "address_and_contact_tab",
+ "fieldtype": "Tab Break",
+ "label": "Address & Contact"
+ },
+ {
+ "fieldname": "terms_tab",
+ "fieldtype": "Tab Break",
+ "label": "Terms"
+ },
+ {
+ "fieldname": "more_info_tab",
+ "fieldtype": "Tab Break",
+ "label": "More Info"
+ },
+ {
+ "fieldname": "connections_tab",
+ "fieldtype": "Tab Break",
+ "label": "Connections",
+ "show_dashboard": 1
+ },
+ {
+ "fieldname": "column_break_7",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_31",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_36",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "billing_address_section",
+ "fieldtype": "Section Break",
+ "label": "Billing Address",
+ "options": "fa fa-bullhorn"
+ },
+ {
+ "fieldname": "shipping_address_section",
+ "fieldtype": "Section Break",
+ "label": "Shipping Address"
+ },
+ {
+ "fieldname": "column_break_81",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "company_address_section",
+ "fieldtype": "Section Break",
+ "label": "Company Address"
+ },
+ {
+ "fieldname": "column_break_87",
+ "fieldtype": "Column Break"
+ },
+ {
+ "collapsible": 1,
+ "depends_on": "eval:(doc.lost_reasons || doc.order_lost_reason)",
+ "fieldname": "lost_reasons_section",
+ "fieldtype": "Section Break",
+ "label": "Lost Reasons"
+ },
+ {
+ "fieldname": "column_break_117",
+ "fieldtype": "Column Break"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "additional_info_section",
+ "fieldtype": "Section Break",
+ "label": "Additional Info",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-file-text",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "column_break_108",
+ "fieldtype": "Column Break"
}
],
"icon": "fa fa-shopping-cart",
"idx": 82,
"is_submittable": 1,
"links": [],
- "modified": "2022-09-16 17:44:43.221804",
+ "modified": "2022-10-11 13:06:33.479650",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation",
@@ -1083,4 +1156,4 @@
"states": [],
"timeline_field": "party_name",
"title_field": "title"
-}
+}
\ No newline at end of file
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index ff269d0e68..e6ff39d8d4 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -15,37 +15,25 @@
"naming_series",
"customer",
"customer_name",
+ "tax_id",
"order_type",
- "skip_delivery_note",
- "column_break1",
- "amended_from",
- "company",
+ "column_break_7",
"transaction_date",
"delivery_date",
+ "column_break1",
"po_no",
"po_date",
- "tax_id",
+ "company",
+ "skip_delivery_note",
+ "amended_from",
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"project",
- "contact_info",
- "customer_address",
- "address_display",
- "contact_person",
- "contact_display",
- "contact_phone",
- "contact_mobile",
- "contact_email",
- "company_address",
- "company_address_display",
- "col_break46",
- "shipping_address_name",
- "shipping_address",
- "dispatch_address_name",
- "dispatch_address",
- "customer_group",
- "territory",
+ "column_break_77",
+ "source",
+ "campaign",
+ "custom_dimensions_section",
"currency_and_price_list",
"currency",
"conversion_rate",
@@ -55,46 +43,32 @@
"plc_conversion_rate",
"ignore_pricing_rule",
"sec_warehouse",
+ "scan_barcode",
+ "column_break_28",
"set_warehouse",
"items_section",
- "scan_barcode",
"items",
- "packing_list",
- "packed_items",
- "pricing_rule_details",
- "pricing_rules",
"section_break_31",
- "column_break_33a",
"total_qty",
+ "total_net_weight",
+ "column_break_33",
"base_total",
"base_net_total",
- "column_break_33",
- "total_net_weight",
+ "column_break_33a",
"total",
"net_total",
"taxes_section",
- "tax_category",
+ "taxes_and_charges",
"column_break_38",
+ "tax_category",
+ "column_break_49",
"shipping_rule",
"section_break_40",
- "taxes_and_charges",
"taxes",
- "sec_tax_breakup",
- "other_charges_calculation",
"section_break_43",
"base_total_taxes_and_charges",
"column_break_46",
"total_taxes_and_charges",
- "loyalty_points_redemption",
- "loyalty_points",
- "loyalty_amount",
- "section_break_48",
- "coupon_code",
- "apply_discount_on",
- "base_discount_amount",
- "column_break_50",
- "additional_discount_percentage",
- "discount_amount",
"totals",
"base_grand_total",
"base_rounding_adjustment",
@@ -107,26 +81,49 @@
"in_words",
"advance_paid",
"disable_rounded_total",
+ "section_break_48",
+ "apply_discount_on",
+ "base_discount_amount",
+ "coupon_code",
+ "column_break_50",
+ "additional_discount_percentage",
+ "discount_amount",
+ "sec_tax_breakup",
+ "other_charges_calculation",
+ "packing_list",
+ "packed_items",
+ "pricing_rule_details",
+ "pricing_rules",
+ "contact_info",
+ "billing_address_column",
+ "customer_address",
+ "address_display",
+ "customer_group",
+ "territory",
+ "column_break_84",
+ "contact_person",
+ "contact_display",
+ "contact_phone",
+ "contact_mobile",
+ "contact_email",
+ "shipping_address_column",
+ "shipping_address_name",
+ "shipping_address",
+ "column_break_93",
+ "dispatch_address_name",
+ "dispatch_address",
+ "col_break46",
+ "company_address",
+ "column_break_92",
+ "company_address_display",
"payment_schedule_section",
+ "payment_terms_section",
"payment_terms_template",
"payment_schedule",
"terms_section_break",
"tc_name",
"terms",
"more_info",
- "is_internal_customer",
- "represents_company",
- "inter_company_order_reference",
- "party_account_currency",
- "column_break_77",
- "source",
- "campaign",
- "printing_details",
- "language",
- "letter_head",
- "column_break4",
- "select_print_heading",
- "group_same_items",
"section_break_78",
"status",
"delivery_status",
@@ -143,12 +140,29 @@
"total_commission",
"section_break1",
"sales_team",
+ "loyalty_points_redemption",
+ "loyalty_points",
+ "column_break_116",
+ "loyalty_amount",
"subscription_section",
"from_date",
"to_date",
"column_break_108",
"auto_repeat",
- "update_auto_repeat_reference"
+ "update_auto_repeat_reference",
+ "printing_details",
+ "letter_head",
+ "group_same_items",
+ "column_break4",
+ "select_print_heading",
+ "language",
+ "additional_info_section",
+ "is_internal_customer",
+ "represents_company",
+ "column_break_152",
+ "inter_company_order_reference",
+ "party_account_currency",
+ "connections_tab"
],
"fields": [
{
@@ -334,10 +348,10 @@
"collapsible": 1,
"depends_on": "customer",
"fieldname": "contact_info",
- "fieldtype": "Section Break",
+ "fieldtype": "Tab Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Address and Contact",
+ "label": "Address & Contact",
"options": "fa fa-bullhorn"
},
{
@@ -414,9 +428,10 @@
},
{
"fieldname": "col_break46",
- "fieldtype": "Column Break",
+ "fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
+ "label": "Company Address",
"width": "50%"
},
{
@@ -550,8 +565,10 @@
{
"fieldname": "sec_warehouse",
"fieldtype": "Section Break",
+ "hide_border": 1,
"hide_days": 1,
- "hide_seconds": 1
+ "hide_seconds": 1,
+ "label": "Items"
},
{
"fieldname": "set_warehouse",
@@ -565,6 +582,7 @@
{
"fieldname": "items_section",
"fieldtype": "Section Break",
+ "hide_border": 1,
"hide_days": 1,
"hide_seconds": 1,
"oldfieldtype": "Section Break",
@@ -675,6 +693,7 @@
"read_only": 1
},
{
+ "depends_on": "total_net_weight",
"fieldname": "total_net_weight",
"fieldtype": "Float",
"hide_days": 1,
@@ -688,7 +707,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Taxes and Charges",
+ "label": "Taxes",
"oldfieldtype": "Section Break",
"options": "fa fa-money"
},
@@ -720,6 +739,7 @@
{
"fieldname": "section_break_40",
"fieldtype": "Section Break",
+ "hide_border": 1,
"hide_days": 1,
"hide_seconds": 1
},
@@ -804,7 +824,7 @@
"hidden": 1,
"hide_days": 1,
"hide_seconds": 1,
- "label": "Loyalty Points Redemption",
+ "label": "Loyalty Points",
"print_hide": 1
},
{
@@ -828,12 +848,11 @@
},
{
"collapsible": 1,
- "collapsible_depends_on": "discount_amount",
"fieldname": "section_break_48",
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Additional Discount and Coupon Code"
+ "label": "Additional Discount"
},
{
"fieldname": "coupon_code",
@@ -891,6 +910,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
+ "label": "Totals",
"oldfieldtype": "Section Break",
"options": "fa fa-money",
"print_hide": 1
@@ -1045,10 +1065,10 @@
},
{
"fieldname": "payment_schedule_section",
- "fieldtype": "Section Break",
+ "fieldtype": "Tab Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Payment Terms"
+ "label": "Terms"
},
{
"fieldname": "payment_terms_template",
@@ -1070,13 +1090,12 @@
"print_hide": 1
},
{
- "collapsible": 1,
"collapsible_depends_on": "terms",
"fieldname": "terms_section_break",
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Terms and Conditions",
+ "label": "Terms & Conditions",
"oldfieldtype": "Section Break",
"options": "fa fa-legal"
},
@@ -1104,10 +1123,10 @@
"collapsible": 1,
"collapsible_depends_on": "project",
"fieldname": "more_info",
- "fieldtype": "Section Break",
+ "fieldtype": "Tab Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "More Information",
+ "label": "More Info",
"oldfieldtype": "Section Break",
"options": "fa fa-file-text",
"print_hide": 1
@@ -1122,7 +1141,6 @@
"read_only": 1
},
{
- "description": "Track this Sales Order against any Project",
"fieldname": "project",
"fieldtype": "Link",
"hide_days": 1,
@@ -1240,7 +1258,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Billing and Delivery Status",
+ "label": "Status",
"oldfieldtype": "Column Break",
"print_hide": 1,
"width": "50%"
@@ -1410,7 +1428,7 @@
"fieldtype": "Section Break",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Auto Repeat Section",
+ "label": "Auto Repeat",
"no_copy": 1,
"print_hide": 1,
"read_only": 1
@@ -1542,13 +1560,76 @@
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_7",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_28",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_49",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "connections_tab",
+ "fieldtype": "Tab Break",
+ "label": "Connections",
+ "show_dashboard": 1
+ },
+ {
+ "fieldname": "payment_terms_section",
+ "fieldtype": "Section Break",
+ "label": "Payment Terms"
+ },
+ {
+ "fieldname": "column_break_116",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "billing_address_column",
+ "fieldtype": "Section Break",
+ "label": "Billing Address"
+ },
+ {
+ "fieldname": "shipping_address_column",
+ "fieldtype": "Section Break",
+ "label": "Shipping Address"
+ },
+ {
+ "fieldname": "column_break_93",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_84",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_92",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "custom_dimensions_section",
+ "fieldtype": "Section Break"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "additional_info_section",
+ "fieldtype": "Section Break",
+ "label": "Additional Info"
+ },
+ {
+ "fieldname": "column_break_152",
+ "fieldtype": "Column Break"
}
],
"icon": "fa fa-file-text",
"idx": 105,
"is_submittable": 1,
"links": [],
- "modified": "2022-09-16 17:43:57.007441",
+ "modified": "2022-10-11 13:06:10.469796",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order",
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 25806d6ed8..f0e9e4b7d9 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -18,6 +18,7 @@ from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
update_linked_doc,
validate_inter_company_party,
)
+from erpnext.accounts.party import get_party_account
from erpnext.controllers.selling_controller import SellingController
from erpnext.manufacturing.doctype.production_plan.production_plan import (
get_items_for_material_requests,
@@ -727,6 +728,8 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
if source.loyalty_points and source.order_type == "Shopping Cart":
target.redeem_loyalty_points = 1
+ target.debit_to = get_party_account("Customer", source.customer, source.company)
+
def update_item(source, target, source_parent):
target.amount = flt(source.amount) - flt(source.billed_amt)
target.base_amount = target.amount * flt(source_parent.conversion_rate)
diff --git a/erpnext/setup/doctype/brand/brand.js b/erpnext/setup/doctype/brand/brand.js
index 3680906057..0abb71a362 100644
--- a/erpnext/setup/doctype/brand/brand.js
+++ b/erpnext/setup/doctype/brand/brand.js
@@ -1,13 +1,71 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
+frappe.ui.form.on('Brand', {
+ setup: (frm) => {
+ frm.fields_dict["brand_defaults"].grid.get_field("default_warehouse").get_query = function(doc, cdt, cdn) {
+ const row = locals[cdt][cdn];
+ return {
+ filters: { company: row.company }
+ }
+ }
+ frm.fields_dict["brand_defaults"].grid.get_field("default_discount_account").get_query = function(doc, cdt, cdn) {
+ const row = locals[cdt][cdn];
+ return {
+ filters: {
+ 'report_type': 'Profit and Loss',
+ 'company': row.company,
+ "is_group": 0
+ }
+ };
+ }
-//--------- ONLOAD -------------
-cur_frm.cscript.onload = function(doc, cdt, cdn) {
+ frm.fields_dict["brand_defaults"].grid.get_field("buying_cost_center").get_query = function(doc, cdt, cdn) {
+ const row = locals[cdt][cdn];
+ return {
+ filters: {
+ "is_group": 0,
+ "company": row.company
+ }
+ }
+ }
-}
+ frm.fields_dict["brand_defaults"].grid.get_field("expense_account").get_query = function(doc, cdt, cdn) {
+ const row = locals[cdt][cdn];
+ return {
+ query: "erpnext.controllers.queries.get_expense_account",
+ filters: { company: row.company }
+ }
+ }
-cur_frm.cscript.refresh = function(doc, cdt, cdn) {
+ frm.fields_dict["brand_defaults"].grid.get_field("default_provisional_account").get_query = function(doc, cdt, cdn) {
+ const row = locals[cdt][cdn];
+ return {
+ filters: {
+ "company": row.company,
+ "root_type": ["in", ["Liability", "Asset"]],
+ "is_group": 0
+ }
+ };
+ }
-}
+ frm.fields_dict["brand_defaults"].grid.get_field("selling_cost_center").get_query = function(doc, cdt, cdn) {
+ const row = locals[cdt][cdn];
+ return {
+ filters: {
+ "is_group": 0,
+ "company": row.company
+ }
+ }
+ }
+
+ frm.fields_dict["brand_defaults"].grid.get_field("income_account").get_query = function(doc, cdt, cdn) {
+ const row = locals[cdt][cdn];
+ return {
+ query: "erpnext.controllers.queries.get_income_account",
+ filters: { company: row.company }
+ }
+ }
+ }
+});
\ No newline at end of file
diff --git a/erpnext/startup/report_data_map.py b/erpnext/startup/report_data_map.py
deleted file mode 100644
index f8c1b6cca0..0000000000
--- a/erpnext/startup/report_data_map.py
+++ /dev/null
@@ -1,327 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-
-# mappings for table dumps
-# "remember to add indexes!"
-
-data_map = {
- "Company": {"columns": ["name"], "conditions": ["docstatus < 2"]},
- "Fiscal Year": {
- "columns": ["name", "year_start_date", "year_end_date"],
- "conditions": ["docstatus < 2"],
- },
- # Accounts
- "Account": {
- "columns": ["name", "parent_account", "lft", "rgt", "report_type", "company", "is_group"],
- "conditions": ["docstatus < 2"],
- "order_by": "lft",
- "links": {
- "company": ["Company", "name"],
- },
- },
- "Cost Center": {
- "columns": ["name", "lft", "rgt"],
- "conditions": ["docstatus < 2"],
- "order_by": "lft",
- },
- "GL Entry": {
- "columns": [
- "name",
- "account",
- "posting_date",
- "cost_center",
- "debit",
- "credit",
- "is_opening",
- "company",
- "voucher_type",
- "voucher_no",
- "remarks",
- ],
- "order_by": "posting_date, account",
- "links": {
- "account": ["Account", "name"],
- "company": ["Company", "name"],
- "cost_center": ["Cost Center", "name"],
- },
- },
- # Stock
- "Item": {
- "columns": [
- "name",
- "if(item_name=name, '', item_name) as item_name",
- "description",
- "item_group as parent_item_group",
- "stock_uom",
- "brand",
- "valuation_method",
- ],
- # "conditions": ["docstatus < 2"],
- "order_by": "name",
- "links": {"parent_item_group": ["Item Group", "name"], "brand": ["Brand", "name"]},
- },
- "Item Group": {
- "columns": ["name", "parent_item_group"],
- # "conditions": ["docstatus < 2"],
- "order_by": "lft",
- },
- "Brand": {"columns": ["name"], "conditions": ["docstatus < 2"], "order_by": "name"},
- "Project": {"columns": ["name"], "conditions": ["docstatus < 2"], "order_by": "name"},
- "Warehouse": {"columns": ["name"], "conditions": ["docstatus < 2"], "order_by": "name"},
- "Stock Ledger Entry": {
- "columns": [
- "name",
- "posting_date",
- "posting_time",
- "item_code",
- "warehouse",
- "actual_qty as qty",
- "voucher_type",
- "voucher_no",
- "project",
- "incoming_rate as incoming_rate",
- "stock_uom",
- "serial_no",
- "qty_after_transaction",
- "valuation_rate",
- ],
- "order_by": "posting_date, posting_time, creation",
- "links": {
- "item_code": ["Item", "name"],
- "warehouse": ["Warehouse", "name"],
- "project": ["Project", "name"],
- },
- "force_index": "posting_sort_index",
- },
- "Serial No": {
- "columns": ["name", "purchase_rate as incoming_rate"],
- "conditions": ["docstatus < 2"],
- "order_by": "name",
- },
- "Stock Entry": {
- "columns": ["name", "purpose"],
- "conditions": ["docstatus=1"],
- "order_by": "posting_date, posting_time, name",
- },
- "Material Request Item": {
- "columns": ["item.name as name", "item_code", "warehouse", "(qty - ordered_qty) as qty"],
- "from": "`tabMaterial Request Item` item, `tabMaterial Request` main",
- "conditions": [
- "item.parent = main.name",
- "main.docstatus=1",
- "main.status != 'Stopped'",
- "ifnull(warehouse, '')!=''",
- "qty > ordered_qty",
- ],
- "links": {"item_code": ["Item", "name"], "warehouse": ["Warehouse", "name"]},
- },
- "Purchase Order Item": {
- "columns": [
- "item.name as name",
- "item_code",
- "warehouse",
- "(qty - received_qty)*conversion_factor as qty",
- ],
- "from": "`tabPurchase Order Item` item, `tabPurchase Order` main",
- "conditions": [
- "item.parent = main.name",
- "main.docstatus=1",
- "main.status != 'Stopped'",
- "ifnull(warehouse, '')!=''",
- "qty > received_qty",
- ],
- "links": {"item_code": ["Item", "name"], "warehouse": ["Warehouse", "name"]},
- },
- "Sales Order Item": {
- "columns": [
- "item.name as name",
- "item_code",
- "(qty - delivered_qty)*conversion_factor as qty",
- "warehouse",
- ],
- "from": "`tabSales Order Item` item, `tabSales Order` main",
- "conditions": [
- "item.parent = main.name",
- "main.docstatus=1",
- "main.status != 'Stopped'",
- "ifnull(warehouse, '')!=''",
- "qty > delivered_qty",
- ],
- "links": {"item_code": ["Item", "name"], "warehouse": ["Warehouse", "name"]},
- },
- # Sales
- "Customer": {
- "columns": [
- "name",
- "if(customer_name=name, '', customer_name) as customer_name",
- "customer_group as parent_customer_group",
- "territory as parent_territory",
- ],
- "conditions": ["docstatus < 2"],
- "order_by": "name",
- "links": {
- "parent_customer_group": ["Customer Group", "name"],
- "parent_territory": ["Territory", "name"],
- },
- },
- "Customer Group": {
- "columns": ["name", "parent_customer_group"],
- "conditions": ["docstatus < 2"],
- "order_by": "lft",
- },
- "Territory": {
- "columns": ["name", "parent_territory"],
- "conditions": ["docstatus < 2"],
- "order_by": "lft",
- },
- "Sales Invoice": {
- "columns": ["name", "customer", "posting_date", "company"],
- "conditions": ["docstatus=1"],
- "order_by": "posting_date",
- "links": {"customer": ["Customer", "name"], "company": ["Company", "name"]},
- },
- "Sales Invoice Item": {
- "columns": ["name", "parent", "item_code", "stock_qty as qty", "base_net_amount"],
- "conditions": ["docstatus=1", "ifnull(parent, '')!=''"],
- "order_by": "parent",
- "links": {"parent": ["Sales Invoice", "name"], "item_code": ["Item", "name"]},
- },
- "Sales Order": {
- "columns": ["name", "customer", "transaction_date as posting_date", "company"],
- "conditions": ["docstatus=1"],
- "order_by": "transaction_date",
- "links": {"customer": ["Customer", "name"], "company": ["Company", "name"]},
- },
- "Sales Order Item[Sales Analytics]": {
- "columns": ["name", "parent", "item_code", "stock_qty as qty", "base_net_amount"],
- "conditions": ["docstatus=1", "ifnull(parent, '')!=''"],
- "order_by": "parent",
- "links": {"parent": ["Sales Order", "name"], "item_code": ["Item", "name"]},
- },
- "Delivery Note": {
- "columns": ["name", "customer", "posting_date", "company"],
- "conditions": ["docstatus=1"],
- "order_by": "posting_date",
- "links": {"customer": ["Customer", "name"], "company": ["Company", "name"]},
- },
- "Delivery Note Item[Sales Analytics]": {
- "columns": ["name", "parent", "item_code", "stock_qty as qty", "base_net_amount"],
- "conditions": ["docstatus=1", "ifnull(parent, '')!=''"],
- "order_by": "parent",
- "links": {"parent": ["Delivery Note", "name"], "item_code": ["Item", "name"]},
- },
- "Supplier": {
- "columns": [
- "name",
- "if(supplier_name=name, '', supplier_name) as supplier_name",
- "supplier_group as parent_supplier_group",
- ],
- "conditions": ["docstatus < 2"],
- "order_by": "name",
- "links": {
- "parent_supplier_group": ["Supplier Group", "name"],
- },
- },
- "Supplier Group": {
- "columns": ["name", "parent_supplier_group"],
- "conditions": ["docstatus < 2"],
- "order_by": "name",
- },
- "Purchase Invoice": {
- "columns": ["name", "supplier", "posting_date", "company"],
- "conditions": ["docstatus=1"],
- "order_by": "posting_date",
- "links": {"supplier": ["Supplier", "name"], "company": ["Company", "name"]},
- },
- "Purchase Invoice Item": {
- "columns": ["name", "parent", "item_code", "stock_qty as qty", "base_net_amount"],
- "conditions": ["docstatus=1", "ifnull(parent, '')!=''"],
- "order_by": "parent",
- "links": {"parent": ["Purchase Invoice", "name"], "item_code": ["Item", "name"]},
- },
- "Purchase Order": {
- "columns": ["name", "supplier", "transaction_date as posting_date", "company"],
- "conditions": ["docstatus=1"],
- "order_by": "posting_date",
- "links": {"supplier": ["Supplier", "name"], "company": ["Company", "name"]},
- },
- "Purchase Order Item[Purchase Analytics]": {
- "columns": ["name", "parent", "item_code", "stock_qty as qty", "base_net_amount"],
- "conditions": ["docstatus=1", "ifnull(parent, '')!=''"],
- "order_by": "parent",
- "links": {"parent": ["Purchase Order", "name"], "item_code": ["Item", "name"]},
- },
- "Purchase Receipt": {
- "columns": ["name", "supplier", "posting_date", "company"],
- "conditions": ["docstatus=1"],
- "order_by": "posting_date",
- "links": {"supplier": ["Supplier", "name"], "company": ["Company", "name"]},
- },
- "Purchase Receipt Item[Purchase Analytics]": {
- "columns": ["name", "parent", "item_code", "stock_qty as qty", "base_net_amount"],
- "conditions": ["docstatus=1", "ifnull(parent, '')!=''"],
- "order_by": "parent",
- "links": {"parent": ["Purchase Receipt", "name"], "item_code": ["Item", "name"]},
- },
- # Support
- "Issue": {
- "columns": ["name", "status", "creation", "resolution_date", "first_responded_on"],
- "conditions": ["docstatus < 2"],
- "order_by": "creation",
- },
- # Manufacturing
- "Work Order": {
- "columns": [
- "name",
- "status",
- "creation",
- "planned_start_date",
- "planned_end_date",
- "status",
- "actual_start_date",
- "actual_end_date",
- "modified",
- ],
- "conditions": ["docstatus = 1"],
- "order_by": "creation",
- },
- # Medical
- "Patient": {
- "columns": [
- "name",
- "creation",
- "owner",
- "if(patient_name=name, '', patient_name) as patient_name",
- ],
- "conditions": ["docstatus < 2"],
- "order_by": "name",
- "links": {"owner": ["User", "name"]},
- },
- "Patient Appointment": {
- "columns": [
- "name",
- "appointment_type",
- "patient",
- "practitioner",
- "appointment_date",
- "department",
- "status",
- "company",
- ],
- "order_by": "name",
- "links": {
- "practitioner": ["Healthcare Practitioner", "name"],
- "appointment_type": ["Appointment Type", "name"],
- },
- },
- "Healthcare Practitioner": {
- "columns": ["name", "department"],
- "order_by": "name",
- "links": {
- "department": ["Department", "name"],
- },
- },
- "Appointment Type": {"columns": ["name"], "order_by": "name"},
- "Medical Department": {"columns": ["name"], "order_by": "name"},
-}
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json
index a8f907ed71..0ca3e69f76 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.json
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.json
@@ -8,46 +8,29 @@
"document_type": "Document",
"engine": "InnoDB",
"field_order": [
- "delivery_to_section",
- "column_break0",
"title",
"naming_series",
"customer",
+ "tax_id",
"customer_name",
"column_break1",
- "amended_from",
- "company",
"posting_date",
"posting_time",
"set_posting_time",
+ "column_break_10",
+ "company",
+ "amended_from",
"is_return",
"issue_credit_note",
"return_against",
"accounting_dimensions_section",
"cost_center",
- "dimension_col_break",
+ "column_break_18",
"project",
- "customer_po_details",
- "po_no",
- "column_break_17",
- "po_date",
- "section_break_18",
- "pick_list",
- "contact_info",
- "shipping_address_name",
- "shipping_address",
- "dispatch_address_name",
- "dispatch_address",
- "contact_person",
- "contact_display",
- "contact_mobile",
- "contact_email",
- "col_break21",
- "customer_address",
- "tax_id",
- "address_display",
- "company_address",
- "company_address_display",
+ "dimension_col_break",
+ "campaign",
+ "source",
+ "custom_dimensions_section",
"currency_and_price_list",
"currency",
"conversion_rate",
@@ -56,45 +39,35 @@
"price_list_currency",
"plc_conversion_rate",
"ignore_pricing_rule",
- "sec_warehouse",
- "set_warehouse",
- "col_break_warehouse",
- "set_target_warehouse",
"items_section",
"scan_barcode",
+ "pick_list",
+ "col_break_warehouse",
+ "set_warehouse",
+ "set_target_warehouse",
+ "section_break_30",
"items",
- "pricing_rule_details",
- "pricing_rules",
- "packing_list",
- "packed_items",
- "product_bundle_help",
"section_break_31",
"total_qty",
+ "total_net_weight",
+ "column_break_35",
"base_total",
"base_net_total",
"column_break_33",
- "total_net_weight",
"total",
"net_total",
"taxes_section",
+ "taxes_and_charges",
+ "column_break_43",
"tax_category",
"column_break_39",
"shipping_rule",
"section_break_41",
- "taxes_and_charges",
"taxes",
- "sec_tax_breakup",
- "other_charges_calculation",
"section_break_44",
"base_total_taxes_and_charges",
"column_break_47",
"total_taxes_and_charges",
- "section_break_49",
- "apply_discount_on",
- "base_discount_amount",
- "column_break_51",
- "additional_discount_percentage",
- "discount_amount",
"totals",
"base_grand_total",
"base_rounding_adjustment",
@@ -106,9 +79,50 @@
"rounded_total",
"in_words",
"disable_rounded_total",
- "terms_section_break",
+ "section_break_49",
+ "apply_discount_on",
+ "base_discount_amount",
+ "column_break_51",
+ "additional_discount_percentage",
+ "discount_amount",
+ "sec_tax_breakup",
+ "other_charges_calculation",
+ "packing_list",
+ "packed_items",
+ "product_bundle_help",
+ "pricing_rule_details",
+ "pricing_rules",
+ "address_and_contact_tab",
+ "contact_info",
+ "customer_address",
+ "address_display",
+ "col_break21",
+ "contact_person",
+ "contact_display",
+ "contact_mobile",
+ "contact_email",
+ "shipping_address_section",
+ "shipping_address_name",
+ "shipping_address",
+ "column_break_95",
+ "dispatch_address_name",
+ "dispatch_address",
+ "company_address_section",
+ "company_address",
+ "column_break_101",
+ "company_address_display",
+ "terms_tab",
"tc_name",
"terms",
+ "more_info_tab",
+ "section_break_83",
+ "per_billed",
+ "status",
+ "column_break_112",
+ "per_installed",
+ "installation_status",
+ "column_break_89",
+ "per_returned",
"transporter_info",
"transporter",
"driver",
@@ -118,56 +132,40 @@
"transporter_name",
"driver_name",
"lr_date",
- "more_info",
- "campaign",
- "source",
- "column_break5",
- "is_internal_customer",
- "represents_company",
- "inter_company_reference",
- "per_billed",
- "customer_group",
- "territory",
- "printing_details",
- "letter_head",
- "select_print_heading",
- "language",
- "column_break_88",
- "print_without_amount",
- "group_same_items",
- "section_break_83",
- "status",
- "per_installed",
- "installation_status",
- "column_break_89",
- "per_returned",
- "excise_page",
- "instructions",
- "subscription_section",
- "auto_repeat",
+ "customer_po_details",
+ "po_no",
+ "column_break_17",
+ "po_date",
"sales_team_section_break",
"sales_partner",
- "column_break7",
"amount_eligible_for_commission",
+ "column_break7",
"commission_rate",
"total_commission",
"section_break1",
- "sales_team"
+ "sales_team",
+ "subscription_section",
+ "auto_repeat",
+ "printing_details",
+ "letter_head",
+ "print_without_amount",
+ "group_same_items",
+ "column_break_88",
+ "select_print_heading",
+ "language",
+ "more_info",
+ "is_internal_customer",
+ "represents_company",
+ "inter_company_reference",
+ "customer_group",
+ "territory",
+ "column_break5",
+ "excise_page",
+ "instructions",
+ "connections_tab",
+ "column_break_25"
],
"fields": [
- {
- "fieldname": "delivery_to_section",
- "fieldtype": "Section Break",
- "label": "Delivery To",
- "options": "fa fa-user"
- },
- {
- "fieldname": "column_break0",
- "fieldtype": "Column Break",
- "oldfieldtype": "Column Break",
- "print_width": "50%",
- "width": "50%"
- },
{
"allow_on_submit": 1,
"default": "{customer_name}",
@@ -337,11 +335,10 @@
"width": "100px"
},
{
- "collapsible": 1,
"depends_on": "customer",
"fieldname": "contact_info",
"fieldtype": "Section Break",
- "label": "Address and Contact",
+ "label": "Billing Address",
"options": "fa fa-bullhorn"
},
{
@@ -493,10 +490,6 @@
"permlevel": 1,
"print_hide": 1
},
- {
- "fieldname": "sec_warehouse",
- "fieldtype": "Section Break"
- },
{
"fieldname": "set_warehouse",
"fieldtype": "Link",
@@ -511,6 +504,8 @@
{
"fieldname": "items_section",
"fieldtype": "Section Break",
+ "hide_border": 1,
+ "label": "Items",
"oldfieldtype": "Section Break",
"options": "fa fa-shopping-cart"
},
@@ -524,7 +519,6 @@
"allow_bulk_edit": 1,
"fieldname": "items",
"fieldtype": "Table",
- "label": "Items",
"oldfieldname": "delivery_note_details",
"oldfieldtype": "Table",
"options": "Delivery Note Item",
@@ -619,6 +613,7 @@
"read_only": 1
},
{
+ "depends_on": "total_net_weight",
"fieldname": "total_net_weight",
"fieldtype": "Float",
"label": "Total Net Weight",
@@ -628,6 +623,7 @@
{
"fieldname": "taxes_section",
"fieldtype": "Section Break",
+ "hide_border": 1,
"label": "Taxes and Charges",
"oldfieldtype": "Section Break",
"options": "fa fa-money"
@@ -653,10 +649,10 @@
},
{
"fieldname": "section_break_41",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "hide_border": 1
},
{
- "description": "If you have created a standard template in Sales Taxes and Charges Template, select one and click on the button below.",
"fieldname": "taxes_and_charges",
"fieldtype": "Link",
"label": "Sales Taxes and Charges Template",
@@ -668,7 +664,6 @@
{
"fieldname": "taxes",
"fieldtype": "Table",
- "label": "Sales Taxes and Charges",
"oldfieldname": "other_charges",
"oldfieldtype": "Table",
"options": "Sales Taxes and Charges"
@@ -718,7 +713,6 @@
},
{
"collapsible": 1,
- "collapsible_depends_on": "discount_amount",
"fieldname": "section_break_49",
"fieldtype": "Section Break",
"label": "Additional Discount"
@@ -759,6 +753,7 @@
{
"fieldname": "totals",
"fieldtype": "Section Break",
+ "label": "Totals",
"oldfieldtype": "Section Break",
"options": "fa fa-money"
},
@@ -863,15 +858,6 @@
"read_only": 1,
"width": "150px"
},
- {
- "collapsible": 1,
- "collapsible_depends_on": "terms",
- "fieldname": "terms_section_break",
- "fieldtype": "Section Break",
- "label": "Terms and Conditions",
- "oldfieldtype": "Section Break",
- "options": "fa fa-legal"
- },
{
"fieldname": "tc_name",
"fieldtype": "Link",
@@ -965,13 +951,12 @@
"collapsible": 1,
"fieldname": "more_info",
"fieldtype": "Section Break",
- "label": "More Information",
+ "label": "Additional Info",
"oldfieldtype": "Section Break",
"options": "fa fa-file-text",
"print_hide": 1
},
{
- "description": "Track this Delivery Note against any Project",
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
@@ -1110,7 +1095,6 @@
},
{
"depends_on": "eval:!doc.__islocal",
- "description": "% of materials delivered against this Delivery Note",
"fieldname": "per_installed",
"fieldtype": "Percent",
"in_list_view": 1,
@@ -1237,10 +1221,6 @@
"options": "Pick List",
"read_only": 1
},
- {
- "fieldname": "section_break_18",
- "fieldtype": "Section Break"
- },
{
"default": "0",
"fetch_from": "customer.is_internal_customer",
@@ -1329,13 +1309,85 @@
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "address_and_contact_tab",
+ "fieldtype": "Tab Break",
+ "label": "Address & Contact"
+ },
+ {
+ "fieldname": "terms_tab",
+ "fieldtype": "Tab Break",
+ "label": "Terms"
+ },
+ {
+ "fieldname": "more_info_tab",
+ "fieldtype": "Tab Break",
+ "label": "More Info"
+ },
+ {
+ "fieldname": "connections_tab",
+ "fieldtype": "Tab Break",
+ "label": "Connections",
+ "show_dashboard": 1
+ },
+ {
+ "fieldname": "column_break_10",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_25",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "section_break_30",
+ "fieldtype": "Section Break",
+ "hide_border": 1
+ },
+ {
+ "fieldname": "column_break_35",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_43",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "custom_dimensions_section",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "shipping_address_section",
+ "fieldtype": "Section Break",
+ "label": "Shipping Address"
+ },
+ {
+ "fieldname": "column_break_95",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "company_address_section",
+ "fieldtype": "Section Break",
+ "label": "Company Address"
+ },
+ {
+ "fieldname": "column_break_101",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_112",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_18",
+ "fieldtype": "Column Break"
}
],
"icon": "fa fa-truck",
"idx": 146,
"is_submittable": 1,
"links": [],
- "modified": "2022-09-16 17:46:17.701904",
+ "modified": "2022-10-11 13:06:58.655635",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note",
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index 36d5a6ce0e..9dd28dc60b 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -842,6 +842,9 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
update_address(
target_doc, "shipping_address", "shipping_address_display", source_doc.customer_address
)
+ update_address(
+ target_doc, "billing_address", "billing_address_display", source_doc.customer_address
+ )
update_taxes(
target_doc,
diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
index 0911cdb476..0a5cbabab0 100644
--- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
+++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
@@ -753,6 +753,7 @@
"fieldtype": "Currency",
"label": "Incoming Rate",
"no_copy": 1,
+ "precision": "6",
"print_hide": 1,
"read_only": 1
},
@@ -813,7 +814,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2022-09-06 14:19:42.876357",
+ "modified": "2022-10-12 03:36:05.344847",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note Item",
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index c8bb1b960e..20bc9d9b2c 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -232,10 +232,10 @@ class Item(Document):
def clear_retain_sample(self):
if not self.has_batch_no:
- self.retain_sample = None
+ self.retain_sample = False
if not self.retain_sample:
- self.sample_quantity = None
+ self.sample_quantity = 0
def add_default_uom_in_conversion_factor_table(self):
if not self.is_new() and self.has_value_changed("stock_uom"):
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index e35c8bf335..e1ee9389de 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -32,7 +32,7 @@ test_ignore = ["BOM"]
test_dependencies = ["Warehouse", "Item Group", "Item Tax Template", "Brand", "Item Attribute"]
-def make_item(item_code=None, properties=None):
+def make_item(item_code=None, properties=None, uoms=None):
if not item_code:
item_code = frappe.generate_hash(length=16)
@@ -56,6 +56,11 @@ def make_item(item_code=None, properties=None):
for item_default in [doc for doc in item.get("item_defaults") if not doc.default_warehouse]:
item_default.default_warehouse = "_Test Warehouse - _TC"
item_default.company = "_Test Company"
+
+ if uoms:
+ for uom in uoms:
+ item.append("uoms", uom)
+
item.insert()
return item
@@ -717,8 +722,8 @@ class TestItem(FrappeTestCase):
item.has_batch_no = None
item.save()
- self.assertEqual(item.retain_sample, None)
- self.assertEqual(item.sample_quantity, None)
+ self.assertEqual(item.retain_sample, False)
+ self.assertEqual(item.sample_quantity, 0)
item.delete()
def consume_item_code_with_differet_stock_transactions(
diff --git a/erpnext/stock/doctype/material_request/material_request.json b/erpnext/stock/doctype/material_request/material_request.json
index 35931307af..413c373e0e 100644
--- a/erpnext/stock/doctype/material_request/material_request.json
+++ b/erpnext/stock/doctype/material_request/material_request.json
@@ -11,34 +11,40 @@
"naming_series",
"title",
"material_request_type",
- "transfer_status",
"customer",
- "status",
+ "company",
"column_break_2",
"transaction_date",
"schedule_date",
- "company",
"amended_from",
"warehouse_section",
+ "scan_barcode",
+ "column_break_13",
"set_from_warehouse",
"column_break5",
"set_warehouse",
"items_section",
- "scan_barcode",
"items",
- "more_info",
- "per_ordered",
- "column_break2",
- "per_received",
- "printing_details",
- "letter_head",
- "select_print_heading",
+ "terms_tab",
"terms_section_break",
"tc_name",
"terms",
+ "more_info_tab",
+ "status_section",
+ "status",
+ "per_ordered",
+ "column_break2",
+ "transfer_status",
+ "per_received",
+ "printing_details",
+ "letter_head",
+ "column_break_31",
+ "select_print_heading",
"reference",
"job_card",
- "work_order"
+ "column_break_35",
+ "work_order",
+ "connections_tab"
],
"fields": [
{
@@ -147,14 +153,6 @@
"options": "Material Request Item",
"reqd": 1
},
- {
- "collapsible": 1,
- "fieldname": "more_info",
- "fieldtype": "Section Break",
- "label": "More Information",
- "oldfieldtype": "Section Break",
- "options": "fa fa-file-text"
- },
{
"default": "Today",
"fieldname": "transaction_date",
@@ -239,7 +237,6 @@
"collapsible_depends_on": "terms",
"fieldname": "terms_section_break",
"fieldtype": "Section Break",
- "label": "Terms and Conditions",
"oldfieldtype": "Section Break",
"options": "fa fa-legal"
},
@@ -277,10 +274,10 @@
{
"fieldname": "warehouse_section",
"fieldtype": "Section Break",
- "label": "Warehouse"
+ "hide_border": 1,
+ "label": "Items"
},
{
- "description": "Sets 'Target Warehouse' in each row of the Items table.",
"fieldname": "set_warehouse",
"fieldtype": "Link",
"in_list_view": 1,
@@ -296,7 +293,6 @@
},
{
"depends_on": "eval:doc.material_request_type == 'Material Transfer'",
- "description": "Sets 'Source Warehouse' in each row of the Items table.",
"fieldname": "set_from_warehouse",
"fieldtype": "Link",
"label": "Set Source Warehouse",
@@ -317,13 +313,49 @@
"label": "Work Order",
"options": "Work Order",
"read_only": 1
+ },
+ {
+ "fieldname": "terms_tab",
+ "fieldtype": "Tab Break",
+ "label": "Terms"
+ },
+ {
+ "fieldname": "more_info_tab",
+ "fieldtype": "Tab Break",
+ "label": "More Info"
+ },
+ {
+ "fieldname": "connections_tab",
+ "fieldtype": "Tab Break",
+ "label": "Connections",
+ "show_dashboard": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "status_section",
+ "fieldtype": "Section Break",
+ "label": "Status",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-file-text"
+ },
+ {
+ "fieldname": "column_break_31",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_35",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_13",
+ "fieldtype": "Column Break"
}
],
"icon": "fa fa-ticket",
"idx": 70,
"is_submittable": 1,
"links": [],
- "modified": "2022-08-25 11:49:28.155048",
+ "modified": "2022-09-27 17:58:26.366469",
"modified_by": "Administrator",
"module": "Stock",
"name": "Material Request",
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
index acaac920c9..3141212ee5 100755
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
@@ -17,10 +17,11 @@
"supplier_name",
"supplier_delivery_note",
"column_break1",
- "company",
"posting_date",
"posting_time",
"set_posting_time",
+ "column_break_12",
+ "company",
"apply_putaway_rule",
"is_return",
"return_against",
@@ -28,18 +29,6 @@
"cost_center",
"dimension_col_break",
"project",
- "section_addresses",
- "supplier_address",
- "contact_person",
- "address_display",
- "contact_display",
- "contact_mobile",
- "contact_email",
- "col_break_address",
- "shipping_address",
- "shipping_address_display",
- "billing_address",
- "billing_address_display",
"currency_and_price_list",
"currency",
"conversion_rate",
@@ -49,37 +38,33 @@
"plc_conversion_rate",
"ignore_pricing_rule",
"sec_warehouse",
+ "scan_barcode",
+ "column_break_31",
"set_warehouse",
- "rejected_warehouse",
- "col_break_warehouse",
"set_from_warehouse",
+ "col_break_warehouse",
+ "rejected_warehouse",
"is_subcontracted",
"supplier_warehouse",
"items_section",
- "scan_barcode",
"items",
"section_break0",
"total_qty",
+ "total_net_weight",
+ "column_break_43",
"base_total",
"base_net_total",
"column_break_27",
- "total_net_weight",
"total",
"net_total",
- "pricing_rule_details",
- "pricing_rules",
- "raw_material_details",
- "get_current_stock",
- "supplied_items",
"taxes_charges_section",
- "tax_category",
+ "taxes_and_charges",
"shipping_col",
+ "tax_category",
+ "column_break_53",
"shipping_rule",
"taxes_section",
- "taxes_and_charges",
"taxes",
- "sec_tax_breakup",
- "other_charges_calculation",
"totals",
"base_taxes_and_charges_added",
"base_taxes_and_charges_deducted",
@@ -88,53 +73,81 @@
"taxes_and_charges_added",
"taxes_and_charges_deducted",
"total_taxes_and_charges",
- "section_break_42",
- "apply_discount_on",
- "base_discount_amount",
- "column_break_44",
- "additional_discount_percentage",
- "discount_amount",
"section_break_46",
"base_grand_total",
"base_rounding_adjustment",
- "base_in_words",
"base_rounded_total",
+ "base_in_words",
"column_break_50",
"grand_total",
"rounding_adjustment",
"rounded_total",
"in_words",
"disable_rounded_total",
- "terms_section_break",
+ "section_break_42",
+ "apply_discount_on",
+ "base_discount_amount",
+ "column_break_44",
+ "additional_discount_percentage",
+ "discount_amount",
+ "sec_tax_breakup",
+ "other_charges_calculation",
+ "pricing_rule_details",
+ "pricing_rules",
+ "raw_material_details",
+ "get_current_stock",
+ "supplied_items",
+ "address_and_contact_tab",
+ "section_addresses",
+ "supplier_address",
+ "address_display",
+ "col_break_address",
+ "contact_person",
+ "contact_display",
+ "contact_mobile",
+ "contact_email",
+ "section_break_98",
+ "shipping_address",
+ "column_break_100",
+ "shipping_address_display",
+ "billing_address_section",
+ "billing_address",
+ "column_break_104",
+ "billing_address_display",
+ "terms_tab",
"tc_name",
"terms",
- "more_info",
+ "more_info_tab",
+ "status_section",
"status",
- "amended_from",
- "range",
"column_break4",
"per_billed",
"per_returned",
- "is_internal_supplier",
- "inter_company_reference",
- "represents_company",
"subscription_detail",
"auto_repeat",
"printing_settings",
"letter_head",
- "language",
- "instructions",
+ "group_same_items",
"column_break_97",
"select_print_heading",
- "other_details",
- "remarks",
- "group_same_items",
+ "language",
"transporter_info",
"transporter_name",
"column_break5",
"lr_no",
"lr_date",
- "is_old_subcontracting_flow"
+ "additional_info_section",
+ "instructions",
+ "is_internal_supplier",
+ "represents_company",
+ "inter_company_reference",
+ "column_break_131",
+ "remarks",
+ "range",
+ "amended_from",
+ "is_old_subcontracting_flow",
+ "other_details",
+ "connections_tab"
],
"fields": [
{
@@ -223,7 +236,6 @@
"width": "100px"
},
{
- "description": "Time at which materials were received",
"fieldname": "posting_time",
"fieldtype": "Time",
"label": "Posting Time",
@@ -277,15 +289,14 @@
"read_only": 1
},
{
- "collapsible": 1,
"fieldname": "section_addresses",
"fieldtype": "Section Break",
- "label": "Address and Contact"
+ "label": "Supplier Address"
},
{
"fieldname": "supplier_address",
"fieldtype": "Link",
- "label": "Select Supplier Address",
+ "label": "Supplier Address",
"options": "Address",
"print_hide": 1
},
@@ -330,7 +341,7 @@
{
"fieldname": "shipping_address",
"fieldtype": "Link",
- "label": "Select Shipping Address",
+ "label": "Shipping Address Template",
"options": "Address",
"print_hide": 1
},
@@ -410,10 +421,11 @@
},
{
"fieldname": "sec_warehouse",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "hide_border": 1,
+ "label": "Items"
},
{
- "description": "Sets 'Accepted Warehouse' in each row of the items table.",
"fieldname": "set_warehouse",
"fieldtype": "Link",
"label": "Accepted Warehouse",
@@ -421,7 +433,6 @@
"print_hide": 1
},
{
- "description": "Sets 'Rejected Warehouse' in each row of the items table.",
"fieldname": "rejected_warehouse",
"fieldtype": "Link",
"label": "Rejected Warehouse",
@@ -461,6 +472,7 @@
{
"fieldname": "items_section",
"fieldtype": "Section Break",
+ "hide_border": 1,
"oldfieldtype": "Section Break",
"options": "fa fa-shopping-cart"
},
@@ -571,6 +583,7 @@
"read_only": 1
},
{
+ "depends_on": "total_net_weight",
"fieldname": "total_net_weight",
"fieldtype": "Float",
"label": "Total Net Weight",
@@ -578,11 +591,11 @@
"read_only": 1
},
{
- "description": "Add / Edit Taxes and Charges",
"fieldname": "taxes_charges_section",
"fieldtype": "Section Break",
- "oldfieldtype": "Section Break",
- "options": "fa fa-money"
+ "hide_border": 1,
+ "label": "Taxes and Charges",
+ "oldfieldtype": "Section Break"
},
{
"fieldname": "tax_category",
@@ -603,7 +616,8 @@
},
{
"fieldname": "taxes_section",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "hide_border": 1
},
{
"fieldname": "taxes_and_charges",
@@ -709,7 +723,6 @@
},
{
"collapsible": 1,
- "collapsible_depends_on": "discount_amount",
"fieldname": "section_break_42",
"fieldtype": "Section Break",
"label": "Additional Discount"
@@ -749,7 +762,8 @@
},
{
"fieldname": "section_break_46",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "label": "Totals"
},
{
"fieldname": "base_grand_total",
@@ -841,15 +855,6 @@
"fieldtype": "Check",
"label": "Disable Rounded Total"
},
- {
- "collapsible": 1,
- "collapsible_depends_on": "terms",
- "fieldname": "terms_section_break",
- "fieldtype": "Section Break",
- "label": "Terms and Conditions",
- "oldfieldtype": "Section Break",
- "options": "fa fa-legal"
- },
{
"fieldname": "tc_name",
"fieldtype": "Link",
@@ -866,14 +871,6 @@
"oldfieldname": "terms",
"oldfieldtype": "Text Editor"
},
- {
- "collapsible": 1,
- "fieldname": "more_info",
- "fieldtype": "Section Break",
- "label": "More Information",
- "oldfieldtype": "Section Break",
- "options": "fa fa-file-text"
- },
{
"default": "Draft",
"fieldname": "status",
@@ -924,7 +921,6 @@
"width": "50%"
},
{
- "description": "Track this Purchase Receipt against any Project",
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
@@ -941,7 +937,7 @@
{
"fieldname": "subscription_detail",
"fieldtype": "Section Break",
- "label": "Auto Repeat Detail"
+ "label": "Auto Repeat"
},
{
"fieldname": "auto_repeat",
@@ -1025,7 +1021,7 @@
"collapsible_depends_on": "transporter_name",
"fieldname": "transporter_info",
"fieldtype": "Section Break",
- "label": "Transporter Details",
+ "label": "Transporter",
"options": "fa fa-truck"
},
{
@@ -1087,7 +1083,7 @@
{
"fieldname": "billing_address",
"fieldtype": "Link",
- "label": "Select Billing Address",
+ "label": "Billing Address",
"options": "Address"
},
{
@@ -1113,7 +1109,6 @@
},
{
"depends_on": "eval: doc.is_internal_supplier",
- "description": "Sets 'From Warehouse' in each row of the items table.",
"fieldname": "set_from_warehouse",
"fieldtype": "Link",
"label": "Set From Warehouse",
@@ -1151,13 +1146,85 @@
"hidden": 1,
"label": "Is Old Subcontracting Flow",
"read_only": 1
+ },
+ {
+ "fieldname": "address_and_contact_tab",
+ "fieldtype": "Tab Break",
+ "label": "Address & Contact"
+ },
+ {
+ "fieldname": "terms_tab",
+ "fieldtype": "Tab Break",
+ "label": "Terms"
+ },
+ {
+ "fieldname": "more_info_tab",
+ "fieldtype": "Tab Break",
+ "label": "More Info"
+ },
+ {
+ "fieldname": "connections_tab",
+ "fieldtype": "Tab Break",
+ "label": "Connections",
+ "show_dashboard": 1
+ },
+ {
+ "fieldname": "column_break_12",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_31",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_43",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_53",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "section_break_98",
+ "fieldtype": "Section Break",
+ "label": "Company Shipping Address"
+ },
+ {
+ "fieldname": "billing_address_section",
+ "fieldtype": "Section Break",
+ "label": "Company Billing Address"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "status_section",
+ "fieldtype": "Section Break",
+ "label": "Status",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-file-text"
+ },
+ {
+ "fieldname": "additional_info_section",
+ "fieldtype": "Section Break",
+ "label": "Additional Info"
+ },
+ {
+ "fieldname": "column_break_131",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_100",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_104",
+ "fieldtype": "Column Break"
}
],
"icon": "fa fa-truck",
"idx": 261,
"is_submittable": 1,
"links": [],
- "modified": "2022-09-16 17:45:58.430132",
+ "modified": "2022-10-11 13:02:31.776256",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt",
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 62697244ba..dc9f2b2117 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -1,7 +1,6 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
-
import frappe
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import add_days, cint, cstr, flt, today
@@ -1199,6 +1198,8 @@ class TestPurchaseReceipt(FrappeTestCase):
self.assertEqual(pr1.items[0].rate, 100)
pr1.submit()
+ self.assertEqual(pr1.is_internal_supplier, 1)
+
# Backdated purchase receipt entry, the valuation rate should be updated for DN1 and PR1
make_purchase_receipt(
item_code=item_doc.name,
@@ -1241,6 +1242,234 @@ class TestPurchaseReceipt(FrappeTestCase):
self.assertEqual(query[0].value, 0)
+ def test_backdated_transaction_for_internal_transfer_in_trasit_warehouse_for_purchase_receipt(
+ self,
+ ):
+ from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_purchase_receipt
+ from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
+
+ prepare_data_for_internal_transfer()
+ customer = "_Test Internal Customer 2"
+ company = "_Test Company with perpetual inventory"
+
+ from_warehouse = create_warehouse("_Test Internal From Warehouse New", company=company)
+ to_warehouse = create_warehouse("_Test Internal To Warehouse New", company=company)
+ item_doc = create_item("Test Internal Transfer Item")
+
+ target_warehouse = create_warehouse("_Test Internal GIT Warehouse New", company=company)
+
+ make_purchase_receipt(
+ item_code=item_doc.name,
+ company=company,
+ posting_date=add_days(today(), -1),
+ warehouse=from_warehouse,
+ qty=1,
+ rate=100,
+ )
+
+ # Keep stock in advance and make sure that systen won't pick this stock while reposting backdated transaction
+ for i in range(1, 4):
+ make_purchase_receipt(
+ item_code=item_doc.name,
+ company=company,
+ posting_date=add_days(today(), -1 * i),
+ warehouse=target_warehouse,
+ qty=1,
+ rate=320 * i,
+ )
+
+ dn1 = create_delivery_note(
+ item_code=item_doc.name,
+ company=company,
+ customer=customer,
+ cost_center="Main - TCP1",
+ expense_account="Cost of Goods Sold - TCP1",
+ qty=1,
+ rate=500,
+ warehouse=from_warehouse,
+ target_warehouse=target_warehouse,
+ )
+
+ self.assertEqual(dn1.items[0].rate, 100)
+
+ pr1 = make_inter_company_purchase_receipt(dn1.name)
+ pr1.items[0].warehouse = to_warehouse
+ self.assertEqual(pr1.items[0].rate, 100)
+ pr1.submit()
+
+ stk_ledger = frappe.db.get_value(
+ "Stock Ledger Entry",
+ {"voucher_type": "Purchase Receipt", "voucher_no": pr1.name, "warehouse": target_warehouse},
+ ["stock_value_difference", "outgoing_rate"],
+ as_dict=True,
+ )
+
+ self.assertEqual(abs(stk_ledger.stock_value_difference), 100)
+ self.assertEqual(stk_ledger.outgoing_rate, 100)
+
+ # Backdated purchase receipt entry, the valuation rate should be updated for DN1 and PR1
+ make_purchase_receipt(
+ item_code=item_doc.name,
+ company=company,
+ posting_date=add_days(today(), -2),
+ warehouse=from_warehouse,
+ qty=1,
+ rate=200,
+ )
+
+ dn_value = frappe.db.get_value(
+ "Stock Ledger Entry",
+ {"voucher_type": "Delivery Note", "voucher_no": dn1.name, "warehouse": target_warehouse},
+ "stock_value_difference",
+ )
+
+ self.assertEqual(abs(dn_value), 200.00)
+
+ pr_value = frappe.db.get_value(
+ "Stock Ledger Entry",
+ {"voucher_type": "Purchase Receipt", "voucher_no": pr1.name, "warehouse": to_warehouse},
+ "stock_value_difference",
+ )
+
+ self.assertEqual(abs(pr_value), 200.00)
+ pr1.load_from_db()
+
+ self.assertEqual(pr1.items[0].valuation_rate, 200)
+ self.assertEqual(pr1.items[0].rate, 100)
+
+ Gl = frappe.qb.DocType("GL Entry")
+
+ query = (
+ frappe.qb.from_(Gl)
+ .select(
+ (fn.Sum(Gl.debit) - fn.Sum(Gl.credit)).as_("value"),
+ )
+ .where((Gl.voucher_type == pr1.doctype) & (Gl.voucher_no == pr1.name))
+ ).run(as_dict=True)
+
+ self.assertEqual(query[0].value, 0)
+
+ def test_backdated_transaction_for_internal_transfer_in_trasit_warehouse_for_purchase_invoice(
+ self,
+ ):
+ from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import (
+ make_purchase_invoice as make_purchase_invoice_for_si,
+ )
+ from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
+ make_inter_company_purchase_invoice,
+ )
+ from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+
+ prepare_data_for_internal_transfer()
+ customer = "_Test Internal Customer 2"
+ company = "_Test Company with perpetual inventory"
+
+ from_warehouse = create_warehouse("_Test Internal From Warehouse New", company=company)
+ to_warehouse = create_warehouse("_Test Internal To Warehouse New", company=company)
+ item_doc = create_item("Test Internal Transfer Item")
+
+ target_warehouse = create_warehouse("_Test Internal GIT Warehouse New", company=company)
+
+ make_purchase_invoice_for_si(
+ item_code=item_doc.name,
+ company=company,
+ posting_date=add_days(today(), -1),
+ warehouse=from_warehouse,
+ qty=1,
+ update_stock=1,
+ expense_account="Cost of Goods Sold - TCP1",
+ cost_center="Main - TCP1",
+ rate=100,
+ )
+
+ # Keep stock in advance and make sure that systen won't pick this stock while reposting backdated transaction
+ for i in range(1, 4):
+ make_purchase_invoice_for_si(
+ item_code=item_doc.name,
+ company=company,
+ posting_date=add_days(today(), -1 * i),
+ warehouse=target_warehouse,
+ update_stock=1,
+ qty=1,
+ expense_account="Cost of Goods Sold - TCP1",
+ cost_center="Main - TCP1",
+ rate=320 * i,
+ )
+
+ si1 = create_sales_invoice(
+ item_code=item_doc.name,
+ company=company,
+ customer=customer,
+ cost_center="Main - TCP1",
+ income_account="Sales - TCP1",
+ qty=1,
+ rate=500,
+ update_stock=1,
+ warehouse=from_warehouse,
+ target_warehouse=target_warehouse,
+ )
+
+ self.assertEqual(si1.items[0].rate, 100)
+
+ pi1 = make_inter_company_purchase_invoice(si1.name)
+ pi1.items[0].warehouse = to_warehouse
+ self.assertEqual(pi1.items[0].rate, 100)
+ pi1.update_stock = 1
+ pi1.save()
+ pi1.submit()
+
+ stk_ledger = frappe.db.get_value(
+ "Stock Ledger Entry",
+ {"voucher_type": pi1.doctype, "voucher_no": pi1.name, "warehouse": target_warehouse},
+ ["stock_value_difference", "outgoing_rate"],
+ as_dict=True,
+ )
+
+ self.assertEqual(abs(stk_ledger.stock_value_difference), 100)
+ self.assertEqual(stk_ledger.outgoing_rate, 100)
+
+ # Backdated purchase receipt entry, the valuation rate should be updated for si1 and pi1
+ make_purchase_receipt(
+ item_code=item_doc.name,
+ company=company,
+ posting_date=add_days(today(), -2),
+ warehouse=from_warehouse,
+ qty=1,
+ rate=200,
+ )
+
+ si_value = frappe.db.get_value(
+ "Stock Ledger Entry",
+ {"voucher_type": si1.doctype, "voucher_no": si1.name, "warehouse": target_warehouse},
+ "stock_value_difference",
+ )
+
+ self.assertEqual(abs(si_value), 200.00)
+
+ pi_value = frappe.db.get_value(
+ "Stock Ledger Entry",
+ {"voucher_type": pi1.doctype, "voucher_no": pi1.name, "warehouse": to_warehouse},
+ "stock_value_difference",
+ )
+
+ self.assertEqual(abs(pi_value), 200.00)
+ pi1.load_from_db()
+
+ self.assertEqual(pi1.items[0].valuation_rate, 200)
+ self.assertEqual(pi1.items[0].rate, 100)
+
+ Gl = frappe.qb.DocType("GL Entry")
+
+ query = (
+ frappe.qb.from_(Gl)
+ .select(
+ (fn.Sum(Gl.debit) - fn.Sum(Gl.credit)).as_("value"),
+ )
+ .where((Gl.voucher_type == pi1.doctype) & (Gl.voucher_no == pi1.name))
+ ).run(as_dict=True)
+
+ self.assertEqual(query[0].value, 0)
+
def test_batch_expiry_for_purchase_receipt(self):
from erpnext.controllers.sales_and_purchase_return import make_return_doc
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
index 39833b5e91..772736e0ad 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -744,6 +744,7 @@
"oldfieldname": "valuation_rate",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
+ "precision": "6",
"print_hide": 1,
"print_width": "80px",
"read_only": 1,
@@ -999,7 +1000,7 @@
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2022-07-28 19:27:54.880781",
+ "modified": "2022-10-12 03:37:59.516609",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt Item",
diff --git a/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py
index edd2553d5d..e0f2479710 100644
--- a/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py
@@ -9,6 +9,7 @@ from frappe.tests.utils import FrappeTestCase
from frappe.utils import nowdate
from frappe.utils.data import add_to_date, today
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.accounts.utils import repost_gle_for_stock_vouchers
from erpnext.controllers.stock_controller import create_item_wise_repost_entries
from erpnext.stock.doctype.item.test_item import make_item
@@ -272,3 +273,57 @@ class TestRepostItemValuation(FrappeTestCase, StockTestMixin):
[{"credit": 50, "debit": 0}],
gle_filters={"account": "Stock In Hand - TCP1"},
)
+
+ def test_duplicate_ple_on_repost(self):
+ from erpnext.accounts import utils
+
+ # lower numbers to simplify test
+ orig_chunk_size = utils.GL_REPOSTING_CHUNK
+ utils.GL_REPOSTING_CHUNK = 2
+ self.addCleanup(setattr, utils, "GL_REPOSTING_CHUNK", orig_chunk_size)
+
+ rate = 100
+ item = self.make_item()
+ item.valuation_rate = 90
+ item.allow_negative_stock = 1
+ item.save()
+
+ company = "_Test Company with perpetual inventory"
+
+ # consume non-existing stock
+ sinv = create_sales_invoice(
+ company=company,
+ posting_date=today(),
+ debit_to="Debtors - TCP1",
+ income_account="Sales - TCP1",
+ expense_account="Cost of Goods Sold - TCP1",
+ warehouse="Stores - TCP1",
+ update_stock=1,
+ currency="INR",
+ item_code=item.name,
+ cost_center="Main - TCP1",
+ qty=1,
+ rate=rate,
+ )
+
+ # backdated receipt triggers repost
+ make_stock_entry(
+ item=item.name,
+ company=company,
+ qty=5,
+ rate=rate,
+ target="Stores - TCP1",
+ posting_date=add_to_date(today(), days=-1),
+ )
+
+ ple_entries = frappe.db.get_list(
+ "Payment Ledger Entry",
+ filters={"voucher_type": sinv.doctype, "voucher_no": sinv.name, "delinked": 0},
+ )
+
+ # assert successful deduplication on PLE
+ self.assertEqual(len(ple_entries), 1)
+
+ # outstanding should not be affected
+ sinv.reload()
+ self.assertEqual(sinv.outstanding_amount, 100)
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index 6042ed4ac5..a2748d0d09 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -846,16 +846,15 @@ def get_pos_reserved_serial_nos(filters):
pos_transacted_sr_nos = query.run(as_dict=True)
- reserved_sr_nos = []
- returned_sr_nos = []
+ reserved_sr_nos = set()
+ returned_sr_nos = set()
for d in pos_transacted_sr_nos:
if d.is_return == 0:
- reserved_sr_nos += get_serial_nos(d.serial_no)
+ [reserved_sr_nos.add(x) for x in get_serial_nos(d.serial_no)]
elif d.is_return == 1:
- returned_sr_nos += get_serial_nos(d.serial_no)
+ [returned_sr_nos.add(x) for x in get_serial_nos(d.serial_no)]
- for sr_no in returned_sr_nos:
- reserved_sr_nos.remove(sr_no)
+ reserved_sr_nos = list(reserved_sr_nos - returned_sr_nos)
return reserved_sr_nos
diff --git a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
index 1410da56a3..6c341d9e9e 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
@@ -1323,13 +1323,15 @@ def create_product_bundle_item(new_item_code, packed_items):
item.save()
-def create_items():
- items = [
- "_Test Item for Reposting",
- "_Test Finished Item for Reposting",
- "_Test Subcontracted Item for Reposting",
- "_Test Bundled Item for Reposting",
- ]
+def create_items(items=None, uoms=None):
+ if not items:
+ items = [
+ "_Test Item for Reposting",
+ "_Test Finished Item for Reposting",
+ "_Test Subcontracted Item for Reposting",
+ "_Test Bundled Item for Reposting",
+ ]
+
for d in items:
properties = {"valuation_method": "FIFO"}
if d == "_Test Bundled Item for Reposting":
@@ -1337,7 +1339,7 @@ def create_items():
elif d == "_Test Subcontracted Item for Reposting":
properties.update({"is_sub_contracted_item": 1})
- make_item(d, properties=properties)
+ make_item(d, properties=properties, uoms=uoms)
return items
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 23e0f1efaf..d92d0f1686 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -132,7 +132,9 @@ class StockReconciliation(StockController):
key.append(row.get(field))
if key in item_warehouse_combinations:
- self.validation_messages.append(_get_msg(row_num, _("Duplicate entry")))
+ self.validation_messages.append(
+ _get_msg(row_num, _("Same item and warehouse combination already entered."))
+ )
else:
item_warehouse_combinations.append(key)
diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py
index ab784ca107..6e06d23617 100644
--- a/erpnext/stock/doctype/warehouse/warehouse.py
+++ b/erpnext/stock/doctype/warehouse/warehouse.py
@@ -9,6 +9,7 @@ from frappe import _, throw
from frappe.contacts.address_and_contact import load_address_and_contact
from frappe.utils import cint, flt
from frappe.utils.nestedset import NestedSet
+from pypika.terms import ExistsCriterion
from erpnext.stock import get_warehouse_account
@@ -266,3 +267,23 @@ def get_warehouses_based_on_account(account, company=None):
frappe.throw(_("Warehouse not found against the account {0}").format(account))
return warehouses
+
+
+# Will be use for frappe.qb
+def apply_warehouse_filter(query, sle, filters):
+ if warehouse := filters.get("warehouse"):
+ warehouse_table = frappe.qb.DocType("Warehouse")
+
+ lft, rgt = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"])
+ chilren_subquery = (
+ frappe.qb.from_(warehouse_table)
+ .select(warehouse_table.name)
+ .where(
+ (warehouse_table.lft >= lft)
+ & (warehouse_table.rgt <= rgt)
+ & (warehouse_table.name == sle.warehouse)
+ )
+ )
+ query = query.where(ExistsCriterion(chilren_subquery))
+
+ return query
diff --git a/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.py b/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.py
index 3d9b046197..ef7d6e6816 100644
--- a/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.py
+++ b/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.py
@@ -4,6 +4,7 @@
import frappe
from frappe import _
+from frappe.query_builder.functions import IfNull
from frappe.utils import cint, getdate
@@ -54,31 +55,28 @@ def get_columns(filters):
return columns
-def get_conditions(filters):
- conditions = ""
+def get_stock_ledger_entries(filters):
if not filters.get("from_date"):
frappe.throw(_("'From Date' is required"))
- if filters.get("to_date"):
- conditions += " and posting_date <= '%s'" % filters["to_date"]
- else:
+ if not filters.get("to_date"):
frappe.throw(_("'To Date' is required"))
- return conditions
-
-
-def get_stock_ledger_entries(filters):
- conditions = get_conditions(filters)
- return frappe.db.sql(
- """select item_code, batch_no, warehouse,
- posting_date, actual_qty
- from `tabStock Ledger Entry`
- where is_cancelled = 0
- and docstatus < 2 and ifnull(batch_no, '') != '' %s order by item_code, warehouse"""
- % conditions,
- as_dict=1,
+ sle = frappe.qb.DocType("Stock Ledger Entry")
+ query = (
+ frappe.qb.from_(sle)
+ .select(sle.item_code, sle.batch_no, sle.warehouse, sle.posting_date, sle.actual_qty)
+ .where(
+ (sle.is_cancelled == 0)
+ & (sle.docstatus < 2)
+ & (IfNull(sle.batch_no, "") != "")
+ & (sle.posting_date <= filters["to_date"])
+ )
+ .orderby(sle.item_code, sle.warehouse)
)
+ return query.run(as_dict=True)
+
def get_item_warehouse_batch_map(filters, float_precision):
sle = get_stock_ledger_entries(filters)
@@ -112,7 +110,7 @@ def get_item_warehouse_batch_map(filters, float_precision):
def get_item_details(filters):
item_map = {}
- for d in frappe.db.sql("select name, item_name, description from tabItem", as_dict=1):
+ for d in (frappe.qb.from_("Item").select("name", "item_name", "description")).run(as_dict=True):
item_map.setdefault(d.name, d)
return item_map
diff --git a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
index 8a13300dc8..0d57938e31 100644
--- a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
+++ b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
@@ -5,6 +5,9 @@
import frappe
from frappe import _
from frappe.utils import cint, flt, getdate
+from pypika import functions as fn
+
+from erpnext.stock.doctype.warehouse.warehouse import apply_warehouse_filter
def execute(filters=None):
@@ -64,37 +67,40 @@ def get_columns(filters):
return columns
-def get_conditions(filters):
- conditions = ""
- if not filters.get("from_date"):
- frappe.throw(_("'From Date' is required"))
-
- if filters.get("to_date"):
- conditions += " and posting_date <= '%s'" % filters["to_date"]
- else:
- frappe.throw(_("'To Date' is required"))
-
- for field in ["item_code", "warehouse", "batch_no", "company"]:
- if filters.get(field):
- conditions += " and {0} = {1}".format(field, frappe.db.escape(filters.get(field)))
-
- return conditions
-
-
# get all details
def get_stock_ledger_entries(filters):
- conditions = get_conditions(filters)
- return frappe.db.sql(
- """
- select item_code, batch_no, warehouse, posting_date, sum(actual_qty) as actual_qty
- from `tabStock Ledger Entry`
- where is_cancelled = 0 and docstatus < 2 and ifnull(batch_no, '') != '' %s
- group by voucher_no, batch_no, item_code, warehouse
- order by item_code, warehouse"""
- % conditions,
- as_dict=1,
+ if not filters.get("from_date"):
+ frappe.throw(_("'From Date' is required"))
+ if not filters.get("to_date"):
+ frappe.throw(_("'To Date' is required"))
+
+ sle = frappe.qb.DocType("Stock Ledger Entry")
+ query = (
+ frappe.qb.from_(sle)
+ .select(
+ sle.item_code,
+ sle.warehouse,
+ sle.batch_no,
+ sle.posting_date,
+ fn.Sum(sle.actual_qty).as_("actual_qty"),
+ )
+ .where(
+ (sle.docstatus < 2)
+ & (sle.is_cancelled == 0)
+ & (fn.IfNull(sle.batch_no, "") != "")
+ & (sle.posting_date <= filters["to_date"])
+ )
+ .groupby(sle.voucher_no, sle.batch_no, sle.item_code, sle.warehouse)
+ .orderby(sle.item_code, sle.warehouse)
)
+ query = apply_warehouse_filter(query, sle, filters)
+ for field in ["item_code", "batch_no", "company"]:
+ if filters.get(field):
+ query = query.where(sle[field] == filters.get(field))
+
+ return query.run(as_dict=True)
+
def get_item_warehouse_batch_map(filters, float_precision):
sle = get_stock_ledger_entries(filters)
@@ -127,7 +133,9 @@ def get_item_warehouse_batch_map(filters, float_precision):
def get_item_details(filters):
item_map = {}
- for d in frappe.db.sql("select name, item_name, description, stock_uom from tabItem", as_dict=1):
+ for d in (frappe.qb.from_("Item").select("name", "item_name", "description", "stock_uom")).run(
+ as_dict=1
+ ):
item_map.setdefault(d.name, d)
return item_map
diff --git a/erpnext/stock/report/delayed_item_report/delayed_item_report.py b/erpnext/stock/report/delayed_item_report/delayed_item_report.py
index 9df24d6559..546a834da8 100644
--- a/erpnext/stock/report/delayed_item_report/delayed_item_report.py
+++ b/erpnext/stock/report/delayed_item_report/delayed_item_report.py
@@ -21,56 +21,54 @@ class DelayedItemReport(object):
return self.get_columns(), self.get_data() or []
def get_data(self, consolidated=False):
- conditions = ""
-
doctype = self.filters.get("based_on")
- child_doc = "%s Item" % doctype
+ sales_order_field = "sales_order" if doctype == "Sales Invoice" else "against_sales_order"
+
+ parent = frappe.qb.DocType(doctype)
+ child = frappe.qb.DocType(f"{doctype} Item")
+
+ query = (
+ frappe.qb.from_(child)
+ .from_(parent)
+ .select(
+ child.item_code,
+ child.item_name,
+ child.item_group,
+ child.qty,
+ child.rate,
+ child.amount,
+ child.so_detail,
+ child[sales_order_field].as_("sales_order"),
+ parent.shipping_address_name,
+ parent.po_no,
+ parent.customer,
+ parent.posting_date,
+ parent.name,
+ parent.grand_total,
+ )
+ .where(
+ (child.parent == parent.name)
+ & (parent.docstatus == 1)
+ & (parent.posting_date.between(self.filters.get("from_date"), self.filters.get("to_date")))
+ & (child[sales_order_field].notnull())
+ & (child[sales_order_field] != "")
+ )
+ )
if doctype == "Sales Invoice":
- conditions = " and `tabSales Invoice`.update_stock = 1 and `tabSales Invoice`.is_pos = 0"
+ query = query.where((parent.update_stock == 1) & (parent.is_pos == 0))
if self.filters.get("item_group"):
- conditions += " and `tab%s`.item_group = %s" % (
- child_doc,
- frappe.db.escape(self.filters.get("item_group")),
- )
-
- for field in ["customer", "customer_group", "company"]:
- if self.filters.get(field):
- conditions += " and `tab%s`.%s = %s" % (
- doctype,
- field,
- frappe.db.escape(self.filters.get(field)),
- )
-
- sales_order_field = "against_sales_order"
- if doctype == "Sales Invoice":
- sales_order_field = "sales_order"
+ query = query.where(child.item_group == self.filters.get("item_group"))
if self.filters.get("sales_order"):
- conditions = " and `tab%s`.%s = '%s'" % (
- child_doc,
- sales_order_field,
- self.filters.get("sales_order"),
- )
+ query = query.where(child[sales_order_field] == self.filters.get("sales_order"))
- self.transactions = frappe.db.sql(
- """ SELECT `tab{child_doc}`.item_code, `tab{child_doc}`.item_name,
- `tab{child_doc}`.item_group, `tab{child_doc}`.qty, `tab{child_doc}`.rate, `tab{child_doc}`.amount,
- `tab{child_doc}`.so_detail, `tab{child_doc}`.{so_field} as sales_order,
- `tab{doctype}`.shipping_address_name, `tab{doctype}`.po_no, `tab{doctype}`.customer,
- `tab{doctype}`.posting_date, `tab{doctype}`.name, `tab{doctype}`.grand_total
- FROM `tab{child_doc}`, `tab{doctype}`
- WHERE
- `tab{child_doc}`.parent = `tab{doctype}`.name and `tab{doctype}`.docstatus = 1 and
- `tab{doctype}`.posting_date between %(from_date)s and %(to_date)s and
- `tab{child_doc}`.{so_field} is not null and `tab{child_doc}`.{so_field} != '' {cond}
- """.format(
- cond=conditions, doctype=doctype, child_doc=child_doc, so_field=sales_order_field
- ),
- {"from_date": self.filters.get("from_date"), "to_date": self.filters.get("to_date")},
- as_dict=1,
- )
+ for field in ("customer", "customer_group", "company"):
+ if self.filters.get(field):
+ query = query.where(parent[field] == self.filters.get(field))
+
+ self.transactions = query.run(as_dict=True)
if self.transactions:
self.filter_transactions_data(consolidated)
diff --git a/erpnext/stock/report/item_prices/item_prices.py b/erpnext/stock/report/item_prices/item_prices.py
index 87f1a42e2b..ab47b4a8b9 100644
--- a/erpnext/stock/report/item_prices/item_prices.py
+++ b/erpnext/stock/report/item_prices/item_prices.py
@@ -4,6 +4,7 @@
import frappe
from frappe import _
+from frappe.query_builder.functions import IfNull, Sum
from frappe.utils import flt
@@ -12,8 +13,7 @@ def execute(filters=None):
filters = {}
columns = get_columns(filters)
- conditions = get_condition(filters)
- item_map = get_item_details(conditions)
+ item_map = get_item_details(filters)
pl = get_price_list()
last_purchase_rate = get_last_purchase_rate()
bom_rate = get_item_bom_rate()
@@ -63,18 +63,24 @@ def get_columns(filters):
return columns
-def get_item_details(conditions):
+def get_item_details(filters):
"""returns all items details"""
item_map = {}
- for i in frappe.db.sql(
- """select name, item_group, item_name, description,
- brand, stock_uom from tabItem %s
- order by item_code, item_group"""
- % (conditions),
- as_dict=1,
- ):
+ item = frappe.qb.DocType("Item")
+ query = (
+ frappe.qb.from_(item)
+ .select(item.name, item.item_group, item.item_name, item.description, item.brand, item.stock_uom)
+ .orderby(item.item_code, item.item_group)
+ )
+
+ if filters.get("items") == "Enabled Items only":
+ query = query.where(item.disabled == 0)
+ elif filters.get("items") == "Disabled Items only":
+ query = query.where(item.disabled == 1)
+
+ for i in query.run(as_dict=True):
item_map.setdefault(i.name, i)
return item_map
@@ -85,19 +91,38 @@ def get_price_list():
rate = {}
- price_list = frappe.db.sql(
- """select ip.item_code, ip.buying, ip.selling,
- concat(ifnull(cu.symbol,ip.currency), " ", round(ip.price_list_rate,2), " - ", ip.price_list) as price
- from `tabItem Price` ip, `tabPrice List` pl, `tabCurrency` cu
- where ip.price_list=pl.name and pl.currency=cu.name and pl.enabled=1""",
- as_dict=1,
- )
+ ip = frappe.qb.DocType("Item Price")
+ pl = frappe.qb.DocType("Price List")
+ cu = frappe.qb.DocType("Currency")
- for j in price_list:
- if j.price:
- rate.setdefault(j.item_code, {}).setdefault("Buying" if j.buying else "Selling", []).append(
- j.price
+ price_list = (
+ frappe.qb.from_(ip)
+ .from_(pl)
+ .from_(cu)
+ .select(
+ ip.item_code,
+ ip.buying,
+ ip.selling,
+ (IfNull(cu.symbol, ip.currency)).as_("currency"),
+ ip.price_list_rate,
+ ip.price_list,
+ )
+ .where((ip.price_list == pl.name) & (pl.currency == cu.name) & (pl.enabled == 1))
+ ).run(as_dict=True)
+
+ for d in price_list:
+ d.update(
+ {"price": "{0} {1} - {2}".format(d.currency, round(d.price_list_rate, 2), d.price_list)}
+ )
+ d.pop("currency")
+ d.pop("price_list_rate")
+ d.pop("price_list")
+
+ if d.price:
+ rate.setdefault(d.item_code, {}).setdefault("Buying" if d.buying else "Selling", []).append(
+ d.price
)
+
item_rate_map = {}
for item in rate:
@@ -112,30 +137,39 @@ def get_price_list():
def get_last_purchase_rate():
item_last_purchase_rate_map = {}
- query = """select * from (
- (select
- po_item.item_code,
- po.transaction_date as posting_date,
- po_item.base_rate
- from `tabPurchase Order` po, `tabPurchase Order Item` po_item
- where po.name = po_item.parent and po.docstatus = 1)
- union
- (select
- pr_item.item_code,
- pr.posting_date,
- pr_item.base_rate
- from `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pr_item
- where pr.name = pr_item.parent and pr.docstatus = 1)
- union
- (select
- pi_item.item_code,
- pi.posting_date,
- pi_item.base_rate
- from `tabPurchase Invoice` pi, `tabPurchase Invoice Item` pi_item
- where pi.name = pi_item.parent and pi.docstatus = 1 and pi.update_stock = 1)
- ) result order by result.item_code asc, result.posting_date asc"""
+ po = frappe.qb.DocType("Purchase Order")
+ pr = frappe.qb.DocType("Purchase Receipt")
+ pi = frappe.qb.DocType("Purchase Invoice")
+ po_item = frappe.qb.DocType("Purchase Order Item")
+ pr_item = frappe.qb.DocType("Purchase Receipt Item")
+ pi_item = frappe.qb.DocType("Purchase Invoice Item")
- for d in frappe.db.sql(query, as_dict=1):
+ query = (
+ frappe.qb.from_(
+ (
+ frappe.qb.from_(po)
+ .from_(po_item)
+ .select(po_item.item_code, po.transaction_date.as_("posting_date"), po_item.base_rate)
+ .where((po.name == po_item.parent) & (po.docstatus == 1))
+ )
+ + (
+ frappe.qb.from_(pr)
+ .from_(pr_item)
+ .select(pr_item.item_code, pr.posting_date, pr_item.base_rate)
+ .where((pr.name == pr_item.parent) & (pr.docstatus == 1))
+ )
+ + (
+ frappe.qb.from_(pi)
+ .from_(pi_item)
+ .select(pi_item.item_code, pi.posting_date, pi_item.base_rate)
+ .where((pi.name == pi_item.parent) & (pi.docstatus == 1) & (pi.update_stock == 1))
+ )
+ )
+ .select("*")
+ .orderby("item_code", "posting_date")
+ )
+
+ for d in query.run(as_dict=True):
item_last_purchase_rate_map[d.item_code] = d.base_rate
return item_last_purchase_rate_map
@@ -146,12 +180,15 @@ def get_item_bom_rate():
item_bom_map = {}
- for b in frappe.db.sql(
- """select item, (total_cost/quantity) as bom_rate
- from `tabBOM` where is_active=1 and is_default=1""",
- as_dict=1,
- ):
- item_bom_map.setdefault(b.item, flt(b.bom_rate))
+ bom = frappe.qb.DocType("BOM")
+ bom_data = (
+ frappe.qb.from_(bom)
+ .select(bom.item, (bom.total_cost / bom.quantity).as_("bom_rate"))
+ .where((bom.is_active == 1) & (bom.is_default == 1))
+ ).run(as_dict=True)
+
+ for d in bom_data:
+ item_bom_map.setdefault(d.item, flt(d.bom_rate))
return item_bom_map
@@ -161,25 +198,17 @@ def get_valuation_rate():
item_val_rate_map = {}
- for d in frappe.db.sql(
- """select item_code,
- sum(actual_qty*valuation_rate)/sum(actual_qty) as val_rate
- from tabBin where actual_qty > 0 group by item_code""",
- as_dict=1,
- ):
+ bin = frappe.qb.DocType("Bin")
+ bin_data = (
+ frappe.qb.from_(bin)
+ .select(
+ bin.item_code, Sum(bin.actual_qty * bin.valuation_rate) / Sum(bin.actual_qty).as_("val_rate")
+ )
+ .where(bin.actual_qty > 0)
+ .groupby(bin.item_code)
+ ).run(as_dict=True)
+
+ for d in bin_data:
item_val_rate_map.setdefault(d.item_code, d.val_rate)
return item_val_rate_map
-
-
-def get_condition(filters):
- """Get Filter Items"""
-
- if filters.get("items") == "Enabled Items only":
- conditions = " where disabled=0 "
- elif filters.get("items") == "Disabled Items only":
- conditions = " where disabled=1 "
- else:
- conditions = ""
-
- return conditions
diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py
index 679d234c9f..0fc642ef20 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.py
+++ b/erpnext/stock/report/stock_balance/stock_balance.py
@@ -10,10 +10,10 @@ from frappe import _
from frappe.query_builder.functions import CombineDatetime
from frappe.utils import cint, date_diff, flt, getdate
from frappe.utils.nestedset import get_descendants_of
-from pypika.terms import ExistsCriterion
import erpnext
from erpnext.stock.doctype.inventory_dimension.inventory_dimension import get_inventory_dimensions
+from erpnext.stock.doctype.warehouse.warehouse import apply_warehouse_filter
from erpnext.stock.report.stock_ageing.stock_ageing import FIFOSlots, get_average_age
from erpnext.stock.utils import add_additional_uom_columns, is_reposting_item_valuation_in_progress
@@ -270,18 +270,8 @@ def apply_conditions(query, filters):
if company := filters.get("company"):
query = query.where(sle.company == company)
- if warehouse := filters.get("warehouse"):
- lft, rgt = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"])
- chilren_subquery = (
- frappe.qb.from_(warehouse_table)
- .select(warehouse_table.name)
- .where(
- (warehouse_table.lft >= lft)
- & (warehouse_table.rgt <= rgt)
- & (warehouse_table.name == sle.warehouse)
- )
- )
- query = query.where(ExistsCriterion(chilren_subquery))
+ if filters.get("warehouse"):
+ query = apply_warehouse_filter(query, sle, filters)
elif warehouse_type := filters.get("warehouse_type"):
query = (
query.join(warehouse_table)
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py
index e18d4c7522..a95119736a 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.py
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.py
@@ -6,11 +6,11 @@ import frappe
from frappe import _
from frappe.query_builder.functions import CombineDatetime
from frappe.utils import cint, flt
-from pypika.terms import ExistsCriterion
from erpnext.stock.doctype.inventory_dimension.inventory_dimension import get_inventory_dimensions
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import get_stock_balance_for
+from erpnext.stock.doctype.warehouse.warehouse import apply_warehouse_filter
from erpnext.stock.utils import (
is_reposting_item_valuation_in_progress,
update_included_uom_in_report,
@@ -295,20 +295,7 @@ def get_stock_ledger_entries(filters, items):
if filters.get(field):
query = query.where(sle[field] == filters.get(field))
- if warehouse := filters.get("warehouse"):
- lft, rgt = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"])
-
- warehouse_table = frappe.qb.DocType("Warehouse")
- chilren_subquery = (
- frappe.qb.from_(warehouse_table)
- .select(warehouse_table.name)
- .where(
- (warehouse_table.lft >= lft)
- & (warehouse_table.rgt <= rgt)
- & (warehouse_table.name == sle.warehouse)
- )
- )
- query = query.where(ExistsCriterion(chilren_subquery))
+ query = apply_warehouse_filter(query, sle, filters)
return query.run(as_dict=True)
diff --git a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
index 49e797d6a3..f477d8f08f 100644
--- a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
+++ b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py
@@ -5,6 +5,7 @@
import frappe
from frappe import _
from frappe.utils import flt, today
+from pypika.terms import ExistsCriterion
from erpnext.accounts.doctype.pos_invoice.pos_invoice import get_pos_reserved_qty
from erpnext.stock.utils import (
@@ -218,10 +219,26 @@ def get_columns():
def get_bin_list(filters):
- conditions = []
+ bin = frappe.qb.DocType("Bin")
+ query = (
+ frappe.qb.from_(bin)
+ .select(
+ bin.item_code,
+ bin.warehouse,
+ bin.actual_qty,
+ bin.planned_qty,
+ bin.indented_qty,
+ bin.ordered_qty,
+ bin.reserved_qty,
+ bin.reserved_qty_for_production,
+ bin.reserved_qty_for_sub_contract,
+ bin.projected_qty,
+ )
+ .orderby(bin.item_code, bin.warehouse)
+ )
if filters.item_code:
- conditions.append("item_code = '%s' " % filters.item_code)
+ query = query.where(bin.item_code == filters.item_code)
if filters.warehouse:
warehouse_details = frappe.db.get_value(
@@ -229,21 +246,20 @@ def get_bin_list(filters):
)
if warehouse_details:
- conditions.append(
- " exists (select name from `tabWarehouse` wh \
- where wh.lft >= %s and wh.rgt <= %s and bin.warehouse = wh.name)"
- % (warehouse_details.lft, warehouse_details.rgt)
+ wh = frappe.qb.DocType("Warehouse")
+ query = query.where(
+ ExistsCriterion(
+ frappe.qb.from_(wh)
+ .select(wh.name)
+ .where(
+ (wh.lft >= warehouse_details.lft)
+ & (wh.rgt <= warehouse_details.rgt)
+ & (bin.warehouse == wh.name)
+ )
+ )
)
- bin_list = frappe.db.sql(
- """select item_code, warehouse, actual_qty, planned_qty, indented_qty,
- ordered_qty, reserved_qty, reserved_qty_for_production, reserved_qty_for_sub_contract, projected_qty
- from tabBin bin {conditions} order by item_code, warehouse
- """.format(
- conditions=" where " + " and ".join(conditions) if conditions else ""
- ),
- as_dict=1,
- )
+ bin_list = query.run(as_dict=True)
return bin_list
@@ -251,45 +267,43 @@ def get_bin_list(filters):
def get_item_map(item_code, include_uom):
"""Optimization: get only the item doc and re_order_levels table"""
- condition = ""
- if item_code:
- condition = "and item_code = {0}".format(frappe.db.escape(item_code, percent=False))
+ bin = frappe.qb.DocType("Bin")
+ item = frappe.qb.DocType("Item")
- cf_field = cf_join = ""
- if include_uom:
- cf_field = ", ucd.conversion_factor"
- cf_join = (
- "left join `tabUOM Conversion Detail` ucd on ucd.parent=item.name and ucd.uom=%(include_uom)s"
+ query = (
+ frappe.qb.from_(item)
+ .select(item.name, item.item_name, item.description, item.item_group, item.brand, item.stock_uom)
+ .where(
+ (item.is_stock_item == 1)
+ & (item.disabled == 0)
+ & (
+ (item.end_of_life > today()) | (item.end_of_life.isnull()) | (item.end_of_life == "0000-00-00")
+ )
+ & (ExistsCriterion(frappe.qb.from_(bin).select(bin.name).where(bin.item_code == item.name)))
)
-
- items = frappe.db.sql(
- """
- select item.name, item.item_name, item.description, item.item_group, item.brand, item.stock_uom{cf_field}
- from `tabItem` item
- {cf_join}
- where item.is_stock_item = 1
- and item.disabled=0
- {condition}
- and (item.end_of_life > %(today)s or item.end_of_life is null or item.end_of_life='0000-00-00')
- and exists (select name from `tabBin` bin where bin.item_code=item.name)""".format(
- cf_field=cf_field, cf_join=cf_join, condition=condition
- ),
- {"today": today(), "include_uom": include_uom},
- as_dict=True,
)
- condition = ""
if item_code:
- condition = "where parent={0}".format(frappe.db.escape(item_code, percent=False))
+ query = query.where(item.item_code == item_code)
+
+ if include_uom:
+ ucd = frappe.qb.DocType("UOM Conversion Detail")
+ query = query.left_join(ucd).on((ucd.parent == item.name) & (ucd.uom == include_uom))
+
+ items = query.run(as_dict=True)
+
+ ir = frappe.qb.DocType("Item Reorder")
+ query = frappe.qb.from_(ir).select("*")
+
+ if item_code:
+ query = query.where(ir.parent == item_code)
reorder_levels = frappe._dict()
- for ir in frappe.db.sql(
- """select * from `tabItem Reorder` {condition}""".format(condition=condition), as_dict=1
- ):
- if ir.parent not in reorder_levels:
- reorder_levels[ir.parent] = []
+ for d in query.run(as_dict=True):
+ if d.parent not in reorder_levels:
+ reorder_levels[d.parent] = []
- reorder_levels[ir.parent].append(ir)
+ reorder_levels[d.parent].append(d)
item_map = frappe._dict()
for item in items:
diff --git a/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py b/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py
index 5430fe6969..8c76908cc3 100644
--- a/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py
+++ b/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py
@@ -4,6 +4,7 @@
import frappe
from frappe import _
+from frappe.query_builder.functions import IfNull
from frappe.utils import flt
@@ -70,31 +71,33 @@ def get_columns(filters):
return columns
-def get_conditions(filters):
- conditions = ""
- values = []
+def get_consumed_details(filters):
+ item = frappe.qb.DocType("Item")
+ sle = frappe.qb.DocType("Stock Ledger Entry")
+
+ query = (
+ frappe.qb.from_(sle)
+ .from_(item)
+ .select(
+ sle.item_code,
+ item.item_name,
+ item.description,
+ item.stock_uom,
+ sle.actual_qty,
+ sle.stock_value_difference,
+ sle.voucher_no,
+ sle.voucher_type,
+ )
+ .where((sle.is_cancelled == 0) & (sle.item_code == item.name) & (sle.actual_qty < 0))
+ )
if filters.get("from_date") and filters.get("to_date"):
- conditions = "and sle.posting_date>=%s and sle.posting_date<=%s"
- values = [filters.get("from_date"), filters.get("to_date")]
+ query = query.where(
+ (sle.posting_date >= filters.get("from_date")) & (sle.posting_date <= filters.get("to_date"))
+ )
- return conditions, values
-
-
-def get_consumed_details(filters):
- conditions, values = get_conditions(filters)
consumed_details = {}
-
- for d in frappe.db.sql(
- """select sle.item_code, i.item_name, i.description,
- i.stock_uom, sle.actual_qty, sle.stock_value_difference,
- sle.voucher_no, sle.voucher_type
- from `tabStock Ledger Entry` sle, `tabItem` i
- where sle.is_cancelled = 0 and sle.item_code=i.name and sle.actual_qty < 0 %s"""
- % conditions,
- values,
- as_dict=1,
- ):
+ for d in query.run(as_dict=True):
consumed_details.setdefault(d.item_code, []).append(d)
return consumed_details
@@ -104,24 +107,54 @@ def get_suppliers_details(filters):
item_supplier_map = {}
supplier = filters.get("supplier")
- for d in frappe.db.sql(
- """select pr.supplier, pri.item_code from
- `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pri
- where pr.name=pri.parent and pr.docstatus=1 and
- pri.item_code=(select name from `tabItem` where
- is_stock_item=1 and name=pri.item_code)""",
- as_dict=1,
- ):
+ item = frappe.qb.DocType("Item")
+ pr = frappe.qb.DocType("Purchase Receipt")
+ pr_item = frappe.qb.DocType("Purchase Receipt Item")
+
+ query = (
+ frappe.qb.from_(pr)
+ .from_(pr_item)
+ .select(pr.supplier, pr_item.item_code)
+ .where(
+ (pr.name == pr_item.parent)
+ & (pr.docstatus == 1)
+ & (
+ pr_item.item_code
+ == (
+ frappe.qb.from_(item)
+ .select(item.name)
+ .where((item.is_stock_item == 1) & (item.name == pr_item.item_code))
+ )
+ )
+ )
+ )
+
+ for d in query.run(as_dict=True):
item_supplier_map.setdefault(d.item_code, []).append(d.supplier)
- for d in frappe.db.sql(
- """select pr.supplier, pri.item_code from
- `tabPurchase Invoice` pr, `tabPurchase Invoice Item` pri
- where pr.name=pri.parent and pr.docstatus=1 and
- ifnull(pr.update_stock, 0) = 1 and pri.item_code=(select name from `tabItem`
- where is_stock_item=1 and name=pri.item_code)""",
- as_dict=1,
- ):
+ pi = frappe.qb.DocType("Purchase Invoice")
+ pi_item = frappe.qb.DocType("Purchase Invoice Item")
+
+ query = (
+ frappe.qb.from_(pi)
+ .from_(pi_item)
+ .select(pi.supplier, pi_item.item_code)
+ .where(
+ (pi.name == pi_item.parent)
+ & (pi.docstatus == 1)
+ & (IfNull(pi.update_stock, 0) == 1)
+ & (
+ pi_item.item_code
+ == (
+ frappe.qb.from_(item)
+ .select(item.name)
+ .where((item.is_stock_item == 1) & (item.name == pi_item.item_code))
+ )
+ )
+ )
+ )
+
+ for d in query.run(as_dict=True):
if d.item_code not in item_supplier_map:
item_supplier_map.setdefault(d.item_code, []).append(d.supplier)
@@ -138,7 +171,11 @@ def get_suppliers_details(filters):
def get_material_transfer_vouchers():
- return frappe.db.sql_list(
- """select name from `tabStock Entry` where
- purpose='Material Transfer' and docstatus=1"""
+ se = frappe.qb.DocType("Stock Entry")
+ query = (
+ frappe.qb.from_(se)
+ .select(se.name)
+ .where((se.purpose == "Material Transfer") & (se.docstatus == 1))
)
+
+ return [r[0] for r in query.run()]
diff --git a/erpnext/stock/report/total_stock_summary/total_stock_summary.py b/erpnext/stock/report/total_stock_summary/total_stock_summary.py
index 21529da2a1..c3155bd1a5 100644
--- a/erpnext/stock/report/total_stock_summary/total_stock_summary.py
+++ b/erpnext/stock/report/total_stock_summary/total_stock_summary.py
@@ -4,60 +4,58 @@
import frappe
from frappe import _
+from frappe.query_builder.functions import Sum
def execute(filters=None):
if not filters:
filters = {}
- columns = get_columns()
+ columns = get_columns(filters)
stock = get_total_stock(filters)
return columns, stock
-def get_columns():
+def get_columns(filters):
columns = [
- _("Company") + ":Link/Company:250",
- _("Warehouse") + ":Link/Warehouse:150",
_("Item") + ":Link/Item:150",
_("Description") + "::300",
_("Current Qty") + ":Float:100",
]
+ if filters.get("group_by") == "Warehouse":
+ columns.insert(0, _("Warehouse") + ":Link/Warehouse:150")
+ else:
+ columns.insert(0, _("Company") + ":Link/Company:250")
+
return columns
def get_total_stock(filters):
- conditions = ""
- columns = ""
+ bin = frappe.qb.DocType("Bin")
+ item = frappe.qb.DocType("Item")
+ wh = frappe.qb.DocType("Warehouse")
+
+ query = (
+ frappe.qb.from_(bin)
+ .inner_join(item)
+ .on(bin.item_code == item.item_code)
+ .inner_join(wh)
+ .on(wh.name == bin.warehouse)
+ .where(bin.actual_qty != 0)
+ )
if filters.get("group_by") == "Warehouse":
if filters.get("company"):
- conditions += " AND warehouse.company = %s" % frappe.db.escape(
- filters.get("company"), percent=False
- )
+ query = query.where(wh.company == filters.get("company"))
- conditions += " GROUP BY ledger.warehouse, item.item_code"
- columns += "'' as company, ledger.warehouse"
+ query = query.select(bin.warehouse).groupby(bin.warehouse)
else:
- conditions += " GROUP BY warehouse.company, item.item_code"
- columns += " warehouse.company, '' as warehouse"
+ query = query.select(wh.company).groupby(wh.company)
- return frappe.db.sql(
- """
- SELECT
- %s,
- item.item_code,
- item.description,
- sum(ledger.actual_qty) as actual_qty
- FROM
- `tabBin` AS ledger
- INNER JOIN `tabItem` AS item
- ON ledger.item_code = item.item_code
- INNER JOIN `tabWarehouse` warehouse
- ON warehouse.name = ledger.warehouse
- WHERE
- ledger.actual_qty != 0 %s"""
- % (columns, conditions)
- )
+ query = query.select(
+ item.item_code, item.description, Sum(bin.actual_qty).as_("actual_qty")
+ ).groupby(item.item_code)
+
+ return query.run()
diff --git a/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py b/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py
index a54373f364..eedf1a0460 100644
--- a/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py
+++ b/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py
@@ -7,6 +7,7 @@
import frappe
from frappe import _
+from frappe.query_builder.functions import Count
from frappe.utils import flt
from erpnext.stock.report.stock_ageing.stock_ageing import FIFOSlots, get_average_age
@@ -98,7 +99,7 @@ def get_columns(filters):
def validate_filters(filters):
if not (filters.get("item_code") or filters.get("warehouse")):
- sle_count = flt(frappe.db.sql("""select count(name) from `tabStock Ledger Entry`""")[0][0])
+ sle_count = flt(frappe.qb.from_("Stock Ledger Entry").select(Count("name")).run()[0][0])
if sle_count > 500000:
frappe.throw(_("Please set filter based on Item or Warehouse"))
if not filters.get("company"):
@@ -108,25 +109,16 @@ def validate_filters(filters):
def get_warehouse_list(filters):
from frappe.core.doctype.user_permission.user_permission import get_permitted_documents
- condition = ""
- user_permitted_warehouse = get_permitted_documents("Warehouse")
- value = ()
- if user_permitted_warehouse:
- condition = "and name in %s"
- value = set(user_permitted_warehouse)
- elif not user_permitted_warehouse and filters.get("warehouse"):
- condition = "and name = %s"
- value = filters.get("warehouse")
+ wh = frappe.qb.DocType("Warehouse")
+ query = frappe.qb.from_(wh).select(wh.name).where(wh.is_group == 0)
- return frappe.db.sql(
- """select name
- from `tabWarehouse` where is_group = 0
- {condition}""".format(
- condition=condition
- ),
- value,
- as_dict=1,
- )
+ user_permitted_warehouse = get_permitted_documents("Warehouse")
+ if user_permitted_warehouse:
+ query = query.where(wh.name.isin(set(user_permitted_warehouse)))
+ elif filters.get("warehouse"):
+ query = query.where(wh.name == filters.get("warehouse"))
+
+ return query.run(as_dict=True)
def add_warehouse_column(columns, warehouse_list):
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 9ca40c3675..cdf6e89fcb 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -542,6 +542,14 @@ class update_entries_after(object):
if not self.args.get("sle_id"):
self.get_dynamic_incoming_outgoing_rate(sle)
+ if (
+ sle.voucher_type in ["Purchase Receipt", "Purchase Invoice"]
+ and sle.voucher_detail_no
+ and sle.actual_qty < 0
+ and frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "is_internal_supplier")
+ ):
+ sle.outgoing_rate = get_incoming_rate_for_inter_company_transfer(sle)
+
if get_serial_nos(sle.serial_no):
self.get_serialized_values(sle)
self.wh_data.qty_after_transaction += flt(sle.actual_qty)
@@ -589,6 +597,7 @@ class update_entries_after(object):
sle.stock_queue = json.dumps(self.wh_data.stock_queue)
sle.stock_value_difference = stock_value_difference
sle.doctype = "Stock Ledger Entry"
+
frappe.get_doc(sle).db_update()
if not self.args.get("sle_id"):
@@ -652,22 +661,7 @@ class update_entries_after(object):
and sle.voucher_detail_no
and frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "is_internal_supplier")
):
- field = (
- "delivery_note_item" if sle.voucher_type == "Purchase Receipt" else "sales_invoice_item"
- )
- doctype = (
- "Delivery Note Item" if sle.voucher_type == "Purchase Receipt" else "Sales Invoice Item"
- )
- refernce_name = frappe.get_cached_value(
- sle.voucher_type + " Item", sle.voucher_detail_no, field
- )
-
- if refernce_name:
- rate = frappe.get_cached_value(
- doctype,
- refernce_name,
- "incoming_rate",
- )
+ rate = get_incoming_rate_for_inter_company_transfer(sle)
else:
if sle.voucher_type in ("Purchase Receipt", "Purchase Invoice"):
rate_field = "valuation_rate"
@@ -748,14 +742,12 @@ class update_entries_after(object):
def update_rate_on_purchase_receipt(self, sle, outgoing_rate):
if frappe.db.exists(sle.voucher_type + " Item", sle.voucher_detail_no):
- frappe.db.set_value(
- sle.voucher_type + " Item",
- sle.voucher_detail_no,
- {
- "base_net_rate": outgoing_rate,
- "valuation_rate": outgoing_rate,
- },
- )
+ if sle.voucher_type in ["Purchase Receipt", "Purchase Invoice"] and frappe.get_cached_value(
+ sle.voucher_type, sle.voucher_no, "is_internal_supplier"
+ ):
+ frappe.db.set_value(
+ f"{sle.voucher_type} Item", sle.voucher_detail_no, "valuation_rate", sle.outgoing_rate
+ )
else:
frappe.db.set_value(
"Purchase Receipt Item Supplied", sle.voucher_detail_no, "rate", outgoing_rate
@@ -1546,3 +1538,25 @@ def is_negative_stock_allowed(*, item_code: Optional[str] = None) -> bool:
if item_code and cint(frappe.db.get_value("Item", item_code, "allow_negative_stock", cache=True)):
return True
return False
+
+
+def get_incoming_rate_for_inter_company_transfer(sle) -> float:
+ """
+ For inter company transfer, incoming rate is the average of the outgoing rate
+ """
+ rate = 0.0
+
+ field = "delivery_note_item" if sle.voucher_type == "Purchase Receipt" else "sales_invoice_item"
+
+ doctype = "Delivery Note Item" if sle.voucher_type == "Purchase Receipt" else "Sales Invoice Item"
+
+ reference_name = frappe.get_cached_value(sle.voucher_type + " Item", sle.voucher_detail_no, field)
+
+ if reference_name:
+ rate = frappe.get_cached_value(
+ doctype,
+ reference_name,
+ "incoming_rate",
+ )
+
+ return rate
diff --git a/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
index 4e00138906..472f6bc24e 100644
--- a/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
@@ -15,8 +15,30 @@ from erpnext.support.doctype.service_level_agreement.service_level_agreement imp
class TestServiceLevelAgreement(unittest.TestCase):
def setUp(self):
+ self.create_company()
frappe.db.set_value("Support Settings", None, "track_service_level_agreement", 1)
- frappe.db.sql("delete from `tabLead`")
+ lead = frappe.qb.DocType("Lead")
+ frappe.qb.from_(lead).delete().where(lead.company == self.company).run()
+
+ def create_company(self):
+ name = "_Test Support SLA"
+ company = None
+ if frappe.db.exists("Company", name):
+ company = frappe.get_doc("Company", name)
+ else:
+ company = frappe.get_doc(
+ {
+ "doctype": "Company",
+ "company_name": name,
+ "country": "India",
+ "default_currency": "INR",
+ "create_chart_of_accounts_based_on": "Standard Template",
+ "chart_of_accounts": "Standard",
+ }
+ )
+ company = company.save()
+
+ self.company = company.name
def test_service_level_agreement(self):
# Default Service Level Agreement
@@ -205,7 +227,7 @@ class TestServiceLevelAgreement(unittest.TestCase):
# make lead with default SLA
creation = datetime.datetime(2019, 3, 4, 12, 0)
- lead = make_lead(creation=creation, index=1)
+ lead = make_lead(creation=creation, index=1, company=self.company)
self.assertEqual(lead.service_level_agreement, lead_sla.name)
self.assertEqual(lead.response_by, datetime.datetime(2019, 3, 4, 16, 0))
@@ -233,7 +255,7 @@ class TestServiceLevelAgreement(unittest.TestCase):
)
creation = datetime.datetime(2020, 3, 4, 4, 0)
- lead = make_lead(creation, index=2)
+ lead = make_lead(creation, index=2, company=self.company)
frappe.flags.current_time = datetime.datetime(2020, 3, 4, 4, 15)
lead.reload()
@@ -267,7 +289,7 @@ class TestServiceLevelAgreement(unittest.TestCase):
)
creation = datetime.datetime(2019, 3, 4, 12, 0)
- lead = make_lead(creation=creation, index=1)
+ lead = make_lead(creation=creation, index=1, company=self.company)
self.assertEqual(lead.response_by, datetime.datetime(2019, 3, 4, 16, 0))
# failed with response time only
@@ -294,7 +316,7 @@ class TestServiceLevelAgreement(unittest.TestCase):
# fulfilled with response time only
creation = datetime.datetime(2019, 3, 4, 12, 0)
- lead = make_lead(creation=creation, index=2)
+ lead = make_lead(creation=creation, index=2, company=self.company)
self.assertEqual(lead.service_level_agreement, lead_sla.name)
self.assertEqual(lead.response_by, datetime.datetime(2019, 3, 4, 16, 0))
@@ -321,7 +343,7 @@ class TestServiceLevelAgreement(unittest.TestCase):
apply_sla_for_resolution=0,
)
creation = datetime.datetime(2019, 3, 4, 12, 0)
- lead = make_lead(creation=creation, index=4)
+ lead = make_lead(creation=creation, index=4, company=self.company)
applied_sla = frappe.db.get_value("Lead", lead.name, "service_level_agreement")
self.assertFalse(applied_sla)
@@ -611,7 +633,7 @@ def create_custom_doctype():
return frappe.get_doc("DocType", "Test SLA on Custom Dt")
-def make_lead(creation=None, index=0):
+def make_lead(creation=None, index=0, company=None):
return frappe.get_doc(
{
"doctype": "Lead",
@@ -621,5 +643,6 @@ def make_lead(creation=None, index=0):
"creation": creation,
"service_level_agreement_creation": creation,
"priority": "Medium",
+ "company": company,
}
).insert(ignore_permissions=True)
diff --git a/erpnext/utilities/doctype/video/video.py b/erpnext/utilities/doctype/video/video.py
index 15dbccde89..13b7877b21 100644
--- a/erpnext/utilities/doctype/video/video.py
+++ b/erpnext/utilities/doctype/video/video.py
@@ -59,7 +59,7 @@ def update_youtube_data():
"Video Settings", "Video Settings", ["enable_youtube_tracking", "frequency"]
)
- if not enable_youtube_tracking:
+ if not cint(enable_youtube_tracking):
return
frequency = get_frequency(frequency)