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/bank_clearance/bank_clearance.js b/erpnext/accounts/doctype/bank_clearance/bank_clearance.js index 63cc46518f..7e57c2fc47 100644 --- a/erpnext/accounts/doctype/bank_clearance/bank_clearance.js +++ b/erpnext/accounts/doctype/bank_clearance/bank_clearance.js @@ -4,6 +4,23 @@ frappe.ui.form.on("Bank Clearance", { setup: function(frm) { frm.add_fetch("account", "account_currency", "account_currency"); + + frm.set_query("account", function() { + return { + "filters": { + "account_type": ["in",["Bank","Cash"]], + "is_group": 0, + } + }; + }); + + frm.set_query("bank_account", function () { + return { + filters: { + 'is_company_account': 1 + }, + }; + }); }, onload: function(frm) { @@ -12,14 +29,7 @@ frappe.ui.form.on("Bank Clearance", { locals[":Company"][frappe.defaults.get_user_default("Company")]["default_bank_account"]: ""; frm.set_value("account", default_bank_account); - frm.set_query("account", function() { - return { - "filters": { - "account_type": ["in",["Bank","Cash"]], - "is_group": 0 - } - }; - }); + frm.set_value("from_date", frappe.datetime.month_start()); frm.set_value("to_date", frappe.datetime.month_end()); 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..637ac7a04c 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,8 +103,11 @@ 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): + +def validate_expense_against_budget(args, expense_amount=0): args = frappe._dict(args) if args.get("company") and not args.fiscal_year: @@ -178,13 +175,13 @@ def validate_expense_against_budget(args): ) # nosec if budget_records: - validate_budget_records(args, budget_records) + validate_budget_records(args, budget_records, expense_amount) -def validate_budget_records(args, budget_records): +def validate_budget_records(args, budget_records, expense_amount): for budget in budget_records: if flt(budget.budget_amount): - amount = get_amount(args, budget) + amount = expense_amount or get_amount(args, budget) yearly_action, monthly_action = get_actions(args, budget) if monthly_action in ["Stop", "Warn"]: diff --git a/erpnext/accounts/doctype/budget/test_budget.py b/erpnext/accounts/doctype/budget/test_budget.py index c48c7d97a2..11af9a29f6 100644 --- a/erpnext/accounts/doctype/budget/test_budget.py +++ b/erpnext/accounts/doctype/budget/test_budget.py @@ -334,6 +334,39 @@ class TestBudget(unittest.TestCase): budget.cancel() jv.cancel() + def test_monthly_budget_against_main_cost_center(self): + from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center + from erpnext.accounts.doctype.cost_center_allocation.test_cost_center_allocation import ( + create_cost_center_allocation, + ) + + cost_centers = [ + "Main Budget Cost Center 1", + "Sub Budget Cost Center 1", + "Sub Budget Cost Center 2", + ] + + for cc in cost_centers: + create_cost_center(cost_center_name=cc, company="_Test Company") + + create_cost_center_allocation( + "_Test Company", + "Main Budget Cost Center 1 - _TC", + {"Sub Budget Cost Center 1 - _TC": 60, "Sub Budget Cost Center 2 - _TC": 40}, + ) + + make_budget(budget_against="Cost Center", cost_center="Main Budget Cost Center 1 - _TC") + + jv = make_journal_entry( + "_Test Account Cost for Goods Sold - _TC", + "_Test Bank - _TC", + 400000, + "Main Budget Cost Center 1 - _TC", + posting_date=nowdate(), + ) + + self.assertRaises(BudgetError, jv.submit) + def set_total_expense_zero(posting_date, budget_against_field=None, budget_against_CC=None): if budget_against_field == "project": diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js index 7af41f398a..a5ff7f1aa7 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.js +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js @@ -173,8 +173,8 @@ frappe.ui.form.on("Journal Entry", { var update_jv_details = function(doc, r) { $.each(r, function(i, d) { var row = frappe.model.add_child(doc, "Journal Entry Account", "accounts"); - row.account = d.account; - row.balance = d.balance; + frappe.model.set_value(row.doctype, row.name, "account", d.account) + frappe.model.set_value(row.doctype, row.name, "balance", d.balance) }); refresh_field("accounts"); } @@ -312,8 +312,7 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro } } - get_outstanding(doctype, docname, company, child, due_date) { - var me = this; + get_outstanding(doctype, docname, company, child) { var args = { "doctype": doctype, "docname": docname, diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 52690e1e66..de012b28ec 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -1210,6 +1210,7 @@ def get_outstanding(args): args = json.loads(args) company_currency = erpnext.get_company_currency(args.get("company")) + due_date = None if args.get("doctype") == "Journal Entry": condition = " and party=%(party)s" if args.get("party") else "" @@ -1234,10 +1235,12 @@ def get_outstanding(args): invoice = frappe.db.get_value( args["doctype"], args["docname"], - ["outstanding_amount", "conversion_rate", scrub(party_type)], + ["outstanding_amount", "conversion_rate", scrub(party_type), "due_date"], as_dict=1, ) + due_date = invoice.get("due_date") + exchange_rate = ( invoice.conversion_rate if (args.get("account_currency") != company_currency) else 1 ) @@ -1260,6 +1263,7 @@ def get_outstanding(args): "exchange_rate": exchange_rate, "party_type": party_type, "party": invoice.get(scrub(party_type)), + "reference_due_date": due_date, } 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..47ad19e0f9 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" + "fieldtype": "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-26 20:03:10.906259", "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/opening_invoice_creation_tool/opening_invoice_creation_tool.js b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js index 7eb5c4234d..1f4166151a 100644 --- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js +++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js @@ -22,13 +22,13 @@ frappe.ui.form.on('Opening Invoice Creation Tool', { } if (data.user != frappe.session.user) return; if (data.count == data.total) { - setTimeout((title) => { + setTimeout(() => { frm.doc.import_in_progress = false; frm.clear_table("invoices"); frm.refresh_fields(); frm.page.clear_indicator(); - frm.dashboard.hide_progress(title); - frappe.msgprint(__("Opening {0} Invoice created", [frm.doc.invoice_type])); + frm.dashboard.hide_progress(); + frappe.msgprint(__("Opening {0} Invoices created", [frm.doc.invoice_type])); }, 1500, data.title); return; } @@ -51,13 +51,6 @@ frappe.ui.form.on('Opening Invoice Creation Tool', { method: "make_invoices", freeze: 1, freeze_message: __("Creating {0} Invoice", [frm.doc.invoice_type]), - callback: function(r) { - if (r.message.length == 1) { - frappe.msgprint(__("{0} Invoice created successfully.", [frm.doc.invoice_type])); - } else if (r.message.length < 50) { - frappe.msgprint(__("{0} Invoices created successfully.", [frm.doc.invoice_type])); - } - } }); }); diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py index f7df1ff4a1..57fe4059c7 100644 --- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py +++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py @@ -255,8 +255,6 @@ def start_import(invoices): def publish(index, total, doctype): - if total < 50: - return frappe.publish_realtime( "opening_invoice_creation_progress", dict( 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/payment_ledger_entry/test_payment_ledger_entry.py b/erpnext/accounts/doctype/payment_ledger_entry/test_payment_ledger_entry.py index a71b19e092..fc6dbba7e7 100644 --- a/erpnext/accounts/doctype/payment_ledger_entry/test_payment_ledger_entry.py +++ b/erpnext/accounts/doctype/payment_ledger_entry/test_payment_ledger_entry.py @@ -3,12 +3,13 @@ import frappe from frappe import qb -from frappe.tests.utils import FrappeTestCase +from frappe.tests.utils import FrappeTestCase, change_settings from frappe.utils import nowdate from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice +from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order from erpnext.stock.doctype.item.test_item import create_item @@ -127,6 +128,25 @@ class TestPaymentLedgerEntry(FrappeTestCase): payment.posting_date = posting_date return payment + def create_sales_order( + self, qty=1, rate=100, posting_date=nowdate(), do_not_save=False, do_not_submit=False + ): + so = make_sales_order( + company=self.company, + transaction_date=posting_date, + customer=self.customer, + item_code=self.item, + cost_center=self.cost_center, + warehouse=self.warehouse, + debit_to=self.debit_to, + currency="INR", + qty=qty, + rate=100, + do_not_save=do_not_save, + do_not_submit=do_not_submit, + ) + return so + def clear_old_entries(self): doctype_list = [ "GL Entry", @@ -406,3 +426,89 @@ class TestPaymentLedgerEntry(FrappeTestCase): ] self.assertEqual(pl_entries_for_crnote[0], expected_values[0]) self.assertEqual(pl_entries_for_crnote[1], expected_values[1]) + + @change_settings( + "Accounts Settings", + {"unlink_payment_on_cancellation_of_invoice": 1, "delete_linked_ledger_entries": 1}, + ) + def test_multi_payment_unlink_on_invoice_cancellation(self): + transaction_date = nowdate() + amount = 100 + si = self.create_sales_invoice(qty=1, rate=amount, posting_date=transaction_date) + + for amt in [40, 40, 20]: + # payment 1 + pe = get_payment_entry(si.doctype, si.name) + pe.paid_amount = amt + pe.get("references")[0].allocated_amount = amt + pe = pe.save().submit() + + si.reload() + si.cancel() + + entries = frappe.db.get_list( + "Payment Ledger Entry", + filters={"against_voucher_type": si.doctype, "against_voucher_no": si.name, "delinked": 0}, + ) + self.assertEqual(entries, []) + + # with references removed, deletion should be possible + si.delete() + self.assertRaises(frappe.DoesNotExistError, frappe.get_doc, si.doctype, si.name) + + @change_settings( + "Accounts Settings", + {"unlink_payment_on_cancellation_of_invoice": 1, "delete_linked_ledger_entries": 1}, + ) + def test_multi_je_unlink_on_invoice_cancellation(self): + transaction_date = nowdate() + amount = 100 + si = self.create_sales_invoice(qty=1, rate=amount, posting_date=transaction_date) + + # multiple JE's against invoice + for amt in [40, 40, 20]: + je1 = self.create_journal_entry( + self.income_account, self.debit_to, amt, posting_date=transaction_date + ) + je1.get("accounts")[1].party_type = "Customer" + je1.get("accounts")[1].party = self.customer + je1.get("accounts")[1].reference_type = si.doctype + je1.get("accounts")[1].reference_name = si.name + je1 = je1.save().submit() + + si.reload() + si.cancel() + + entries = frappe.db.get_list( + "Payment Ledger Entry", + filters={"against_voucher_type": si.doctype, "against_voucher_no": si.name, "delinked": 0}, + ) + self.assertEqual(entries, []) + + # with references removed, deletion should be possible + si.delete() + self.assertRaises(frappe.DoesNotExistError, frappe.get_doc, si.doctype, si.name) + + @change_settings( + "Accounts Settings", + {"unlink_payment_on_cancellation_of_invoice": 1, "delete_linked_ledger_entries": 1}, + ) + def test_advance_payment_unlink_on_order_cancellation(self): + transaction_date = nowdate() + amount = 100 + so = self.create_sales_order(qty=1, rate=amount, posting_date=transaction_date).save().submit() + + pe = get_payment_entry(so.doctype, so.name).save().submit() + + so.reload() + so.cancel() + + entries = frappe.db.get_list( + "Payment Ledger Entry", + filters={"against_voucher_type": so.doctype, "against_voucher_no": so.name, "delinked": 0}, + ) + self.assertEqual(entries, []) + + # with references removed, deletion should be possible + so.delete() + self.assertRaises(frappe.DoesNotExistError, frappe.get_doc, so.doctype, so.name) diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json index 6f8b3822c2..eedaaaf338 100644 --- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json +++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json @@ -343,7 +343,8 @@ "no_copy": 1, "options": "POS Invoice", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "search_index": 1 }, { "default": "0", @@ -1553,7 +1554,7 @@ "icon": "fa fa-file-text", "is_submittable": 1, "links": [], - "modified": "2022-09-27 13:00:24.166684", + "modified": "2022-09-30 03:49:50.455199", "modified_by": "Administrator", "module": "Accounts", "name": "POS Invoice", diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py index fbe0ef39f8..54a3e934b2 100644 --- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py +++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py @@ -743,7 +743,3 @@ def add_return_modes(doc, pos_profile): ]: payment_mode = get_mode_of_payment_info(mode_of_payment, doc.company) append_payment(payment_mode[0]) - - -def on_doctype_update(): - frappe.db.add_index("POS Invoice", ["return_against"]) 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.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json index 6e7ebd1414..ce9ce647db 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json @@ -52,7 +52,10 @@ "free_item_rate", "column_break_42", "free_item_uom", + "round_free_qty", "is_recursive", + "recurse_for", + "apply_recursion_over", "section_break_23", "valid_from", "valid_upto", @@ -578,12 +581,34 @@ "fieldtype": "Select", "label": "Naming Series", "options": "PRLE-.####" + }, + { + "default": "0", + "fieldname": "round_free_qty", + "fieldtype": "Check", + "label": "Round Free Qty" + }, + { + "depends_on": "is_recursive", + "description": "Give free item for every N quantity", + "fieldname": "recurse_for", + "fieldtype": "Float", + "label": "Recurse Every (As Per Transaction UOM)", + "mandatory_depends_on": "is_recursive" + }, + { + "default": "0", + "depends_on": "is_recursive", + "description": "Qty for which recursion isn't applicable.", + "fieldname": "apply_recursion_over", + "fieldtype": "Float", + "label": "Apply Recursion Over (As Per Transaction UOM)" } ], "icon": "fa fa-gift", "idx": 1, "links": [], - "modified": "2022-09-16 16:00:38.356266", + "modified": "2022-10-13 19:05:35.056304", "modified_by": "Administrator", "module": "Accounts", "name": "Pricing Rule", diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index 9af3188e47..ed46d85e3a 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -24,6 +24,7 @@ class PricingRule(Document): self.validate_applicable_for_selling_or_buying() self.validate_min_max_amt() self.validate_min_max_qty() + self.validate_recursion() self.cleanup_fields_value() self.validate_rate_or_discount() self.validate_max_discount() @@ -109,6 +110,18 @@ class PricingRule(Document): if self.min_amt and self.max_amt and flt(self.min_amt) > flt(self.max_amt): throw(_("Min Amt can not be greater than Max Amt")) + def validate_recursion(self): + if self.price_or_product_discount != "Product": + return + if self.free_item or self.same_item: + if flt(self.recurse_for) <= 0: + self.recurse_for = 1 + if self.is_recursive: + if flt(self.apply_recursion_over) > flt(self.min_qty): + throw(_("Min Qty should be greater than Recurse Over Qty")) + if flt(self.apply_recursion_over) < 0: + throw(_("Recurse Over Qty cannot be less than 0")) + def cleanup_fields_value(self): for logic_field in ["apply_on", "applicable_for", "rate_or_discount"]: fieldname = frappe.scrub(self.get(logic_field) or "") @@ -268,6 +281,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 +349,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 +466,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..d27f65eba0 100644 --- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py @@ -595,6 +595,247 @@ 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_item_group_price_with_blank_uom_pricing_rule(self): + group = frappe.get_doc(doctype="Item Group", item_group_name="_Test Pricing Rule Item Group") + group.save() + properties = { + "item_code": "Item with Group Blank UOM", + "item_group": "_Test Pricing Rule Item Group", + "stock_uom": "Nos", + "sales_uom": "Box", + "uoms": [dict(uom="Box", conversion_factor=10)], + } + item = make_item(properties=properties) + + make_item_price("Item with Group Blank UOM", "_Test Price List", 100) + + pricing_rule_record = { + "doctype": "Pricing Rule", + "title": "_Test Item with Group Blank UOM Rule", + "apply_on": "Item Group", + "item_groups": [ + { + "item_group": "_Test Pricing Rule Item Group", + } + ], + "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 with Group 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 with Group 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 with Group Blank UOM"}).delete() + item.delete() + group.delete() + + def test_item_group_price_with_selling_uom_pricing_rule(self): + group = frappe.get_doc(doctype="Item Group", item_group_name="_Test Pricing Rule Item Group UOM") + group.save() + properties = { + "item_code": "Item with Group UOM other than Stock", + "item_group": "_Test Pricing Rule Item Group UOM", + "stock_uom": "Nos", + "sales_uom": "Box", + "uoms": [dict(uom="Box", conversion_factor=10)], + } + item = make_item(properties=properties) + + make_item_price("Item with Group UOM other than Stock", "_Test Price List", 100) + + pricing_rule_record = { + "doctype": "Pricing Rule", + "title": "_Test Item with Group UOM other than Stock Rule", + "apply_on": "Item Group", + "item_groups": [ + { + "item_group": "_Test Pricing Rule Item Group UOM", + "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 with Group 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 with Group 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 with Group UOM other than Stock"}).delete() + item.delete() + group.delete() + def test_pricing_rule_for_different_currency(self): make_item("Test Sanitizer Item") @@ -828,6 +1069,45 @@ class TestPricingRule(unittest.TestCase): si.delete() rule.delete() + def test_pricing_rule_for_product_free_item_rounded_qty_and_recursion(self): + frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule") + test_record = { + "doctype": "Pricing Rule", + "title": "_Test Pricing Rule", + "apply_on": "Item Code", + "currency": "USD", + "items": [ + { + "item_code": "_Test Item", + } + ], + "selling": 1, + "rate": 0, + "min_qty": 3, + "max_qty": 7, + "price_or_product_discount": "Product", + "same_item": 1, + "free_qty": 1, + "round_free_qty": 1, + "is_recursive": 1, + "recurse_for": 2, + "company": "_Test Company", + } + frappe.get_doc(test_record.copy()).insert() + + # With pricing rule + so = make_sales_order(item_code="_Test Item", qty=5) + so.load_from_db() + self.assertEqual(so.items[1].is_free_item, 1) + self.assertEqual(so.items[1].item_code, "_Test Item") + self.assertEqual(so.items[1].qty, 2) + + so = make_sales_order(item_code="_Test Item", qty=7) + so.load_from_db() + self.assertEqual(so.items[1].is_free_item, 1) + self.assertEqual(so.items[1].item_code, "_Test Item") + self.assertEqual(so.items[1].qty, 4) + test_dependencies = ["Campaign"] diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py index 1f29d732ba..bb54b23e26 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") @@ -121,6 +127,12 @@ def _get_pricing_rules(apply_on, args, values): values["variant_of"] = args.variant_of elif apply_on_field == "item_group": item_conditions = _get_tree_conditions(args, "Item Group", child_doc, False) + 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") + ) + ) conditions += get_other_conditions(conditions, values, args) warehouse_conditions = _get_tree_conditions(args, "Warehouse", "`tabPricing Rule`") @@ -621,9 +633,13 @@ def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None): qty = pricing_rule.free_qty or 1 if pricing_rule.is_recursive: - transaction_qty = args.get("qty") if args else doc.total_qty + transaction_qty = ( + args.get("qty") if args else doc.total_qty + ) - pricing_rule.apply_recursion_over if transaction_qty: - qty = flt(transaction_qty) * qty + qty = flt(transaction_qty) * qty / pricing_rule.recurse_for + if pricing_rule.round_free_qty: + qty = round(qty) free_item_data_args = { "item_code": free_item, diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js index 7dd77fbb3c..7dd5ef36f2 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js @@ -9,6 +9,7 @@ frappe.ui.form.on('Process Statement Of Accounts', { refresh: function(frm){ if(!frm.doc.__islocal) { frm.add_custom_button(__('Send Emails'), function(){ + if (frm.is_dirty()) frappe.throw(__("Please save before proceeding.")) frappe.call({ method: "erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.send_emails", args: { @@ -25,7 +26,8 @@ frappe.ui.form.on('Process Statement Of Accounts', { }); }); frm.add_custom_button(__('Download'), function(){ - var url = frappe.urllib.get_full_url( + if (frm.is_dirty()) frappe.throw(__("Please save before proceeding.")) + let url = frappe.urllib.get_full_url( '/api/method/erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.download_statements?' + 'document_name='+encodeURIComponent(frm.doc.name)) $.ajax({ diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json index a26267ba5e..83e637077e 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json @@ -27,6 +27,7 @@ "customers", "preferences", "orientation", + "include_break", "include_ageing", "ageing_based_on", "section_break_14", @@ -284,10 +285,16 @@ "fieldtype": "Link", "label": "Terms and Conditions", "options": "Terms and Conditions" + }, + { + "default": "1", + "fieldname": "include_break", + "fieldtype": "Check", + "label": "Page Break After Each SoA" } ], "links": [], - "modified": "2021-09-06 21:00:45.732505", + "modified": "2022-10-17 17:47:08.662475", "modified_by": "Administrator", "module": "Accounts", "name": "Process Statement Of Accounts", @@ -321,5 +328,6 @@ ], "sort_field": "modified", "sort_order": "DESC", + "states": [], "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py index 01f716daa2..c6b0c57ce5 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py @@ -6,6 +6,7 @@ import copy import frappe from frappe import _ +from frappe.desk.reportview import get_match_cond from frappe.model.document import Document from frappe.utils import add_days, add_months, format_date, getdate, today from frappe.utils.jinja import validate_template @@ -128,7 +129,8 @@ def get_report_pdf(doc, consolidated=True): if not bool(statement_dict): return False elif consolidated: - result = "".join(list(statement_dict.values())) + delimiter = '
' if doc.include_break else "" + result = delimiter.join(list(statement_dict.values())) return get_pdf(result, {"orientation": doc.orientation}) else: for customer, statement_html in statement_dict.items(): @@ -240,8 +242,6 @@ def fetch_customers(customer_collection, collection_name, primary_mandatory): if int(primary_mandatory): if primary_email == "": continue - elif (billing_email == "") and (primary_email == ""): - continue customer_list.append( {"name": customer.name, "primary_email": primary_email, "billing_email": billing_email} @@ -273,8 +273,12 @@ def get_customer_emails(customer_name, primary_mandatory, billing_and_primary=Tr link.link_doctype='Customer' and link.link_name=%s and contact.is_billing_contact=1 + {mcond} ORDER BY - contact.creation desc""", + contact.creation desc + """.format( + mcond=get_match_cond("Contact") + ), customer_name, ) @@ -313,6 +317,8 @@ def send_emails(document_name, from_scheduler=False): attachments = [{"fname": customer + ".pdf", "fcontent": report_pdf}] recipients, cc = get_recipients_and_cc(customer, doc) + if not recipients: + continue context = get_context(customer, doc) subject = frappe.render_template(doc.subject, context) message = frappe.render_template(doc.body, context) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js index ec861a2787..39a623519a 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 @@ -569,6 +569,10 @@ frappe.ui.form.on("Purchase Invoice", { erpnext.queries.setup_queries(frm, "Warehouse", function() { return erpnext.queries.warehouse(frm.doc); }); + + if (frm.is_new()) { + frm.clear_table("tax_withheld_vouchers"); + } }, is_subcontracted: function(frm) { diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json index 4fb879c0d2..25b128b893 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json @@ -1,1515 +1,1586 @@ { - "actions": [], - "allow_import": 1, - "autoname": "naming_series:", - "creation": "2013-05-21 16:16:39", - "doctype": "DocType", - "document_type": "Document", - "engine": "InnoDB", - "field_order": [ - "title", - "naming_series", - "supplier", - "supplier_name", - "tax_id", - "due_date", - "tax_withholding_category", - "column_break1", - "company", - "posting_date", - "posting_time", - "set_posting_time", - "is_paid", - "is_return", - "apply_tds", - "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", - "column_break2", - "buying_price_list", - "price_list_currency", - "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", - "items", - "pricing_rule_details", - "pricing_rules", - "raw_materials_supplied", - "supplied_items", - "section_break_26", - "total_qty", - "base_total", - "base_net_total", - "column_break_28", - "total_net_weight", - "total", - "net_total", - "tax_withholding_net_total", - "taxes_section", - "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", - "base_total_taxes_and_charges", - "column_break_40", - "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", - "base_rounded_total", - "base_in_words", - "column_break8", - "grand_total", - "rounding_adjustment", - "rounded_total", - "in_words", - "total_advance", - "outstanding_amount", - "disable_rounded_total", - "payments_section", - "mode_of_payment", - "cash_bank_account", - "clearance_date", - "col_br_payments", - "paid_amount", - "base_paid_amount", - "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", - "payment_schedule_section", - "payment_terms_template", - "ignore_default_payment_terms_template", - "payment_schedule", - "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", - "status", - "inter_company_invoice_reference", - "represents_company", - "column_break_147", - "is_internal_supplier", - "accounting_details_section", - "credit_to", - "party_account_currency", - "is_opening", - "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" - ], - "fields": [ - { - "allow_on_submit": 1, - "default": "{supplier_name}", - "fieldname": "title", - "fieldtype": "Data", - "hidden": 1, - "label": "Title", - "no_copy": 1, - "print_hide": 1 - }, - { - "fieldname": "naming_series", - "fieldtype": "Select", - "label": "Series", - "no_copy": 1, - "oldfieldname": "naming_series", - "oldfieldtype": "Select", - "options": "ACC-PINV-.YYYY.-\nACC-PINV-RET-.YYYY.-", - "print_hide": 1, - "reqd": 1, - "set_only_once": 1 - }, - { - "fieldname": "supplier", - "fieldtype": "Link", - "in_standard_filter": 1, - "label": "Supplier", - "oldfieldname": "supplier", - "oldfieldtype": "Link", - "options": "Supplier", - "print_hide": 1, - "reqd": 1, - "search_index": 1 - }, - { - "bold": 1, - "depends_on": "supplier", - "fetch_from": "supplier.supplier_name", - "fieldname": "supplier_name", - "fieldtype": "Data", - "in_global_search": 1, - "label": "Supplier Name", - "oldfieldname": "supplier_name", - "oldfieldtype": "Data", - "read_only": 1 - }, - { - "fetch_from": "supplier.tax_id", - "fieldname": "tax_id", - "fieldtype": "Read Only", - "label": "Tax Id", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "due_date", - "fieldtype": "Date", - "label": "Due Date", - "oldfieldname": "due_date", - "oldfieldtype": "Date" - }, - { - "default": "0", - "fieldname": "is_paid", - "fieldtype": "Check", - "label": "Is Paid", - "print_hide": 1 - }, - { - "default": "0", - "fieldname": "is_return", - "fieldtype": "Check", - "label": "Is Return (Debit Note)", - "no_copy": 1, - "print_hide": 1 - }, - { - "default": "0", - "fieldname": "apply_tds", - "fieldtype": "Check", - "label": "Apply Tax Withholding Amount", - "print_hide": 1 - }, - { - "fieldname": "column_break1", - "fieldtype": "Column Break", - "oldfieldtype": "Column Break", - "width": "50%" - }, - { - "fieldname": "company", - "fieldtype": "Link", - "in_standard_filter": 1, - "label": "Company", - "options": "Company", - "print_hide": 1, - "remember_last_selected_value": 1 - }, - { - "fieldname": "cost_center", - "fieldtype": "Link", - "label": "Cost Center", - "options": "Cost Center" - }, - { - "default": "Today", - "fieldname": "posting_date", - "fieldtype": "Date", - "in_list_view": 1, - "label": "Date", - "oldfieldname": "posting_date", - "oldfieldtype": "Date", - "print_hide": 1, - "reqd": 1, - "search_index": 1 - }, - { - "fieldname": "posting_time", - "fieldtype": "Time", - "label": "Posting Time", - "no_copy": 1, - "print_hide": 1, - "print_width": "100px", - "width": "100px" - }, - { - "default": "0", - "depends_on": "eval:doc.docstatus==0", - "fieldname": "set_posting_time", - "fieldtype": "Check", - "label": "Edit Posting Date and Time", - "print_hide": 1 - }, - { - "fieldname": "amended_from", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "label": "Amended From", - "no_copy": 1, - "oldfieldname": "amended_from", - "oldfieldtype": "Link", - "options": "Purchase Invoice", - "print_hide": 1, - "read_only": 1 - }, - { - "collapsible": 1, - "collapsible_depends_on": "eval:doc.on_hold", - "fieldname": "sb_14", - "fieldtype": "Section Break", - "label": "Hold Invoice" - }, - { - "default": "0", - "fieldname": "on_hold", - "fieldtype": "Check", - "label": "Hold Invoice" - }, - { - "depends_on": "eval:doc.on_hold", - "description": "Once set, this invoice will be on hold till the set date", - "fieldname": "release_date", - "fieldtype": "Date", - "label": "Release Date" - }, - { - "fieldname": "cb_17", - "fieldtype": "Column Break" - }, - { - "depends_on": "eval:doc.on_hold", - "fieldname": "hold_comment", - "fieldtype": "Small Text", - "label": "Reason For Putting On Hold" - }, - { - "collapsible": 1, - "collapsible_depends_on": "bill_no", - "fieldname": "supplier_invoice_details", - "fieldtype": "Section Break", - "label": "Supplier Invoice Details" - }, - { - "fieldname": "bill_no", - "fieldtype": "Data", - "label": "Supplier Invoice No", - "oldfieldname": "bill_no", - "oldfieldtype": "Data", - "print_hide": 1 - }, - { - "fieldname": "column_break_15", - "fieldtype": "Column Break" - }, - { - "fieldname": "bill_date", - "fieldtype": "Date", - "label": "Supplier Invoice Date", - "no_copy": 1, - "oldfieldname": "bill_date", - "oldfieldtype": "Date", - "print_hide": 1 - }, - { - "depends_on": "return_against", - "fieldname": "returns", - "fieldtype": "Section Break", - "label": "Returns" - }, - { - "depends_on": "return_against", - "fieldname": "return_against", - "fieldtype": "Link", - "label": "Return Against Purchase Invoice", - "no_copy": 1, - "options": "Purchase Invoice", - "print_hide": 1, - "read_only": 1 - }, - { - "collapsible": 1, - "fieldname": "section_addresses", - "fieldtype": "Section Break", - "label": "Address and Contact" - }, - { - "fieldname": "supplier_address", - "fieldtype": "Link", - "label": "Select Supplier Address", - "options": "Address", - "print_hide": 1 - }, - { - "fieldname": "address_display", - "fieldtype": "Small Text", - "label": "Address", - "read_only": 1 - }, - { - "fieldname": "contact_person", - "fieldtype": "Link", - "in_global_search": 1, - "label": "Contact Person", - "options": "Contact", - "print_hide": 1 - }, - { - "fieldname": "contact_display", - "fieldtype": "Small Text", - "label": "Contact", - "read_only": 1 - }, - { - "fieldname": "contact_mobile", - "fieldtype": "Small Text", - "label": "Mobile No", - "read_only": 1 - }, - { - "fieldname": "contact_email", - "fieldtype": "Small Text", - "label": "Contact Email", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "col_break_address", - "fieldtype": "Column Break" - }, - { - "fieldname": "shipping_address", - "fieldtype": "Link", - "label": "Select Shipping Address", - "options": "Address", - "print_hide": 1 - }, - { - "fieldname": "shipping_address_display", - "fieldtype": "Small Text", - "label": "Shipping Address", - "print_hide": 1, - "read_only": 1 - }, - { - "collapsible": 1, - "fieldname": "currency_and_price_list", - "fieldtype": "Section Break", - "label": "Currency and Price List", - "options": "fa fa-tag" - }, - { - "fieldname": "currency", - "fieldtype": "Link", - "label": "Currency", - "oldfieldname": "currency", - "oldfieldtype": "Select", - "options": "Currency", - "print_hide": 1 - }, - { - "fieldname": "conversion_rate", - "fieldtype": "Float", - "label": "Exchange Rate", - "oldfieldname": "conversion_rate", - "oldfieldtype": "Currency", - "precision": "9", - "print_hide": 1 - }, - { - "fieldname": "column_break2", - "fieldtype": "Column Break" - }, - { - "fieldname": "buying_price_list", - "fieldtype": "Link", - "label": "Price List", - "options": "Price List", - "print_hide": 1 - }, - { - "fieldname": "price_list_currency", - "fieldtype": "Link", - "label": "Price List Currency", - "options": "Currency", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "plc_conversion_rate", - "fieldtype": "Float", - "label": "Price List Exchange Rate", - "precision": "9", - "print_hide": 1 - }, - { - "default": "0", - "fieldname": "ignore_pricing_rule", - "fieldtype": "Check", - "label": "Ignore Pricing Rule", - "permlevel": 1, - "print_hide": 1 - }, - { - "fieldname": "sec_warehouse", - "fieldtype": "Section Break" - }, - { - "depends_on": "update_stock", - "description": "Sets 'Accepted Warehouse' in each row of the items table.", - "fieldname": "set_warehouse", - "fieldtype": "Link", - "label": "Set Accepted Warehouse", - "options": "Warehouse", - "print_hide": 1 - }, - { - "depends_on": "update_stock", - "description": "Warehouse where you are maintaining stock of rejected items", - "fieldname": "rejected_warehouse", - "fieldtype": "Link", - "label": "Rejected Warehouse", - "no_copy": 1, - "options": "Warehouse", - "print_hide": 1 - }, - { - "fieldname": "col_break_warehouse", - "fieldtype": "Column Break" - }, - { - "default": "0", - "fieldname": "is_subcontracted", - "fieldtype": "Check", - "label": "Is Subcontracted", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "items_section", - "fieldtype": "Section Break", - "oldfieldtype": "Section Break", - "options": "fa fa-shopping-cart" - }, - { - "default": "0", - "fieldname": "update_stock", - "fieldtype": "Check", - "label": "Update Stock", - "print_hide": 1 - }, - { - "fieldname": "scan_barcode", - "fieldtype": "Data", - "label": "Scan Barcode", - "options": "Barcode" - }, - { - "allow_bulk_edit": 1, - "fieldname": "items", - "fieldtype": "Table", - "label": "Items", - "oldfieldname": "entries", - "oldfieldtype": "Table", - "options": "Purchase Invoice Item", - "reqd": 1 - }, - { - "fieldname": "pricing_rule_details", - "fieldtype": "Section Break", - "label": "Pricing Rules" - }, - { - "fieldname": "pricing_rules", - "fieldtype": "Table", - "label": "Pricing Rule Detail", - "options": "Pricing Rule Detail", - "read_only": 1 - }, - { - "collapsible_depends_on": "supplied_items", - "fieldname": "raw_materials_supplied", - "fieldtype": "Section Break", - "label": "Raw Materials Supplied" - }, - { - "depends_on": "update_stock", - "fieldname": "supplied_items", - "fieldtype": "Table", - "label": "Supplied Items", - "no_copy": 1, - "options": "Purchase Receipt Item Supplied" - }, - { - "fieldname": "section_break_26", - "fieldtype": "Section Break" - }, - { - "fieldname": "total_qty", - "fieldtype": "Float", - "label": "Total Quantity", - "read_only": 1 - }, - { - "fieldname": "base_total", - "fieldtype": "Currency", - "label": "Total (Company Currency)", - "options": "Company:company:default_currency", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "base_net_total", - "fieldtype": "Currency", - "label": "Net Total (Company Currency)", - "oldfieldname": "net_total", - "oldfieldtype": "Currency", - "options": "Company:company:default_currency", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "column_break_28", - "fieldtype": "Column Break" - }, - { - "fieldname": "total", - "fieldtype": "Currency", - "label": "Total", - "options": "currency", - "read_only": 1 - }, - { - "fieldname": "net_total", - "fieldtype": "Currency", - "label": "Net Total", - "oldfieldname": "net_total_import", - "oldfieldtype": "Currency", - "options": "currency", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "total_net_weight", - "fieldtype": "Float", - "label": "Total Net Weight", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "taxes_section", - "fieldtype": "Section Break", - "oldfieldtype": "Section Break", - "options": "fa fa-money" - }, - { - "fieldname": "tax_category", - "fieldtype": "Link", - "label": "Tax Category", - "options": "Tax Category", - "print_hide": 1 - }, - { - "fieldname": "column_break_49", - "fieldtype": "Column Break" - }, - { - "fieldname": "shipping_rule", - "fieldtype": "Link", - "label": "Shipping Rule", - "options": "Shipping Rule", - "print_hide": 1 - }, - { - "fieldname": "section_break_51", - "fieldtype": "Section Break" - }, - { - "fieldname": "taxes_and_charges", - "fieldtype": "Link", - "label": "Purchase Taxes and Charges Template", - "oldfieldname": "purchase_other_charges", - "oldfieldtype": "Link", - "options": "Purchase Taxes and Charges Template", - "print_hide": 1 - }, - { - "fieldname": "taxes", - "fieldtype": "Table", - "label": "Purchase Taxes and Charges", - "oldfieldname": "purchase_tax_details", - "oldfieldtype": "Table", - "options": "Purchase Taxes and Charges" - }, - { - "collapsible": 1, - "fieldname": "sec_tax_breakup", - "fieldtype": "Section Break", - "label": "Tax Breakup" - }, - { - "fieldname": "other_charges_calculation", - "fieldtype": "Long Text", - "label": "Taxes and Charges Calculation", - "no_copy": 1, - "oldfieldtype": "HTML", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "totals", - "fieldtype": "Section Break", - "oldfieldtype": "Section Break", - "options": "fa fa-money" - }, - { - "fieldname": "base_taxes_and_charges_added", - "fieldtype": "Currency", - "label": "Taxes and Charges Added (Company Currency)", - "oldfieldname": "other_charges_added", - "oldfieldtype": "Currency", - "options": "Company:company:default_currency", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "base_taxes_and_charges_deducted", - "fieldtype": "Currency", - "label": "Taxes and Charges Deducted (Company Currency)", - "oldfieldname": "other_charges_deducted", - "oldfieldtype": "Currency", - "options": "Company:company:default_currency", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "base_total_taxes_and_charges", - "fieldtype": "Currency", - "label": "Total Taxes and Charges (Company Currency)", - "oldfieldname": "total_tax", - "oldfieldtype": "Currency", - "options": "Company:company:default_currency", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "column_break_40", - "fieldtype": "Column Break" - }, - { - "fieldname": "taxes_and_charges_added", - "fieldtype": "Currency", - "label": "Taxes and Charges Added", - "oldfieldname": "other_charges_added_import", - "oldfieldtype": "Currency", - "options": "currency", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "taxes_and_charges_deducted", - "fieldtype": "Currency", - "label": "Taxes and Charges Deducted", - "oldfieldname": "other_charges_deducted_import", - "oldfieldtype": "Currency", - "options": "currency", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "total_taxes_and_charges", - "fieldtype": "Currency", - "label": "Total Taxes and Charges", - "options": "currency", - "print_hide": 1, - "read_only": 1 - }, - { - "collapsible": 1, - "collapsible_depends_on": "discount_amount", - "fieldname": "section_break_44", - "fieldtype": "Section Break", - "label": "Additional Discount" - }, - { - "default": "Grand Total", - "fieldname": "apply_discount_on", - "fieldtype": "Select", - "label": "Apply Additional Discount On", - "options": "\nGrand Total\nNet Total", - "print_hide": 1 - }, - { - "fieldname": "base_discount_amount", - "fieldtype": "Currency", - "label": "Additional Discount Amount (Company Currency)", - "options": "Company:company:default_currency", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "column_break_46", - "fieldtype": "Column Break" - }, - { - "fieldname": "additional_discount_percentage", - "fieldtype": "Float", - "label": "Additional Discount Percentage", - "print_hide": 1 - }, - { - "fieldname": "discount_amount", - "fieldtype": "Currency", - "label": "Additional Discount Amount", - "options": "currency", - "print_hide": 1 - }, - { - "fieldname": "section_break_49", - "fieldtype": "Section Break" - }, - { - "fieldname": "base_grand_total", - "fieldtype": "Currency", - "label": "Grand Total (Company Currency)", - "oldfieldname": "grand_total", - "oldfieldtype": "Currency", - "options": "Company:company:default_currency", - "print_hide": 1, - "read_only": 1 - }, - { - "depends_on": "eval:!doc.disable_rounded_total", - "fieldname": "base_rounding_adjustment", - "fieldtype": "Currency", - "label": "Rounding Adjustment (Company Currency)", - "no_copy": 1, - "options": "Company:company:default_currency", - "print_hide": 1, - "read_only": 1 - }, - { - "depends_on": "eval:!doc.disable_rounded_total", - "fieldname": "base_rounded_total", - "fieldtype": "Currency", - "label": "Rounded Total (Company Currency)", - "no_copy": 1, - "options": "Company:company:default_currency", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "base_in_words", - "fieldtype": "Data", - "label": "In Words (Company Currency)", - "length": 240, - "oldfieldname": "in_words", - "oldfieldtype": "Data", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "column_break8", - "fieldtype": "Column Break", - "oldfieldtype": "Column Break", - "print_hide": 1, - "width": "50%" - }, - { - "fieldname": "grand_total", - "fieldtype": "Currency", - "in_list_view": 1, - "label": "Grand Total", - "oldfieldname": "grand_total_import", - "oldfieldtype": "Currency", - "options": "currency", - "read_only": 1 - }, - { - "depends_on": "eval:!doc.disable_rounded_total", - "fieldname": "rounding_adjustment", - "fieldtype": "Currency", - "label": "Rounding Adjustment", - "no_copy": 1, - "options": "currency", - "print_hide": 1, - "read_only": 1 - }, - { - "depends_on": "eval:!doc.disable_rounded_total", - "fieldname": "rounded_total", - "fieldtype": "Currency", - "label": "Rounded Total", - "no_copy": 1, - "options": "currency", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "in_words", - "fieldtype": "Data", - "label": "In Words", - "length": 240, - "oldfieldname": "in_words_import", - "oldfieldtype": "Data", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "total_advance", - "fieldtype": "Currency", - "label": "Total Advance", - "no_copy": 1, - "oldfieldname": "total_advance", - "oldfieldtype": "Currency", - "options": "party_account_currency", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "outstanding_amount", - "fieldtype": "Currency", - "label": "Outstanding Amount", - "no_copy": 1, - "oldfieldname": "outstanding_amount", - "oldfieldtype": "Currency", - "options": "party_account_currency", - "print_hide": 1, - "read_only": 1 - }, - { - "default": "0", - "depends_on": "grand_total", - "fieldname": "disable_rounded_total", - "fieldtype": "Check", - "label": "Disable Rounded Total" - }, - { - "collapsible": 1, - "collapsible_depends_on": "paid_amount", - "depends_on": "eval:doc.is_paid===1||(doc.advances && doc.advances.length>0)", - "fieldname": "payments_section", - "fieldtype": "Section Break", - "label": "Payments" - }, - { - "fieldname": "mode_of_payment", - "fieldtype": "Link", - "label": "Mode of Payment", - "options": "Mode of Payment", - "print_hide": 1 - }, - { - "fieldname": "cash_bank_account", - "fieldtype": "Link", - "label": "Cash/Bank Account", - "options": "Account" - }, - { - "fieldname": "clearance_date", - "fieldtype": "Date", - "label": "Clearance Date", - "no_copy": 1, - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "col_br_payments", - "fieldtype": "Column Break" - }, - { - "depends_on": "is_paid", - "fieldname": "paid_amount", - "fieldtype": "Currency", - "label": "Paid Amount", - "no_copy": 1, - "options": "currency", - "print_hide": 1 - }, - { - "fieldname": "base_paid_amount", - "fieldtype": "Currency", - "label": "Paid Amount (Company Currency)", - "no_copy": 1, - "options": "Company:company:default_currency", - "print_hide": 1, - "read_only": 1 - }, - { - "collapsible": 1, - "collapsible_depends_on": "write_off_amount", - "depends_on": "grand_total", - "fieldname": "write_off", - "fieldtype": "Section Break", - "label": "Write Off" - }, - { - "fieldname": "write_off_amount", - "fieldtype": "Currency", - "label": "Write Off Amount", - "no_copy": 1, - "options": "currency", - "print_hide": 1 - }, - { - "fieldname": "base_write_off_amount", - "fieldtype": "Currency", - "label": "Write Off Amount (Company Currency)", - "no_copy": 1, - "options": "Company:company:default_currency", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "column_break_61", - "fieldtype": "Column Break" - }, - { - "depends_on": "eval:flt(doc.write_off_amount)!=0", - "fieldname": "write_off_account", - "fieldtype": "Link", - "label": "Write Off Account", - "options": "Account", - "print_hide": 1 - }, - { - "depends_on": "eval:flt(doc.write_off_amount)!=0", - "fieldname": "write_off_cost_center", - "fieldtype": "Link", - "label": "Write Off Cost Center", - "options": "Cost Center", - "print_hide": 1 - }, - { - "collapsible": 1, - "collapsible_depends_on": "advances", - "fieldname": "advances_section", - "fieldtype": "Section Break", - "label": "Advance Payments", - "oldfieldtype": "Section Break", - "options": "fa fa-money", - "print_hide": 1 - }, - { - "default": "0", - "fieldname": "allocate_advances_automatically", - "fieldtype": "Check", - "label": "Set Advances and Allocate (FIFO)" - }, - { - "depends_on": "eval:!doc.allocate_advances_automatically", - "fieldname": "get_advances", - "fieldtype": "Button", - "label": "Get Advances Paid", - "oldfieldtype": "Button", - "print_hide": 1 - }, - { - "fieldname": "advances", - "fieldtype": "Table", - "label": "Advances", - "no_copy": 1, - "oldfieldname": "advance_allocation_details", - "oldfieldtype": "Table", - "options": "Purchase Invoice Advance", - "print_hide": 1 - }, - { - "collapsible": 1, - "collapsible_depends_on": "eval:(!doc.is_return)", - "fieldname": "payment_schedule_section", - "fieldtype": "Section Break", - "label": "Payment Terms" - }, - { - "fieldname": "payment_terms_template", - "fieldtype": "Link", - "label": "Payment Terms Template", - "options": "Payment Terms Template" - }, - { - "fieldname": "payment_schedule", - "fieldtype": "Table", - "label": "Payment Schedule", - "no_copy": 1, - "options": "Payment Schedule", - "print_hide": 1 - }, - { - "collapsible": 1, - "collapsible_depends_on": "terms", - "fieldname": "terms_section_break", - "fieldtype": "Section Break", - "label": "Terms and Conditions", - "options": "fa fa-legal" - }, - { - "fieldname": "tc_name", - "fieldtype": "Link", - "label": "Terms", - "options": "Terms and Conditions", - "print_hide": 1 - }, - { - "fieldname": "terms", - "fieldtype": "Text Editor", - "label": "Terms and Conditions1" - }, - { - "collapsible": 1, - "fieldname": "printing_settings", - "fieldtype": "Section Break", - "label": "Printing Settings" - }, - { - "allow_on_submit": 1, - "fieldname": "letter_head", - "fieldtype": "Link", - "label": "Letter Head", - "options": "Letter Head", - "print_hide": 1 - }, - { - "allow_on_submit": 1, - "default": "0", - "fieldname": "group_same_items", - "fieldtype": "Check", - "label": "Group same items", - "print_hide": 1 - }, - { - "fieldname": "column_break_112", - "fieldtype": "Column Break" - }, - { - "allow_on_submit": 1, - "fieldname": "select_print_heading", - "fieldtype": "Link", - "label": "Print Heading", - "no_copy": 1, - "oldfieldname": "select_print_heading", - "oldfieldtype": "Link", - "options": "Print Heading", - "print_hide": 1, - "report_hide": 1 - }, - { - "fieldname": "language", - "fieldtype": "Data", - "label": "Print Language", - "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", - "fieldname": "is_internal_supplier", - "fieldtype": "Check", - "ignore_user_permissions": 1, - "label": "Is Internal Supplier", - "read_only": 1 - }, - { - "fieldname": "credit_to", - "fieldtype": "Link", - "label": "Credit To", - "oldfieldname": "credit_to", - "oldfieldtype": "Link", - "options": "Account", - "print_hide": 1, - "reqd": 1, - "search_index": 1 - }, - { - "fieldname": "party_account_currency", - "fieldtype": "Link", - "hidden": 1, - "label": "Party Account Currency", - "no_copy": 1, - "options": "Currency", - "print_hide": 1, - "read_only": 1 - }, - { - "default": "No", - "fieldname": "is_opening", - "fieldtype": "Select", - "label": "Is Opening Entry", - "oldfieldname": "is_opening", - "oldfieldtype": "Select", - "options": "No\nYes", - "print_hide": 1 - }, - { - "fieldname": "against_expense_account", - "fieldtype": "Small Text", - "hidden": 1, - "label": "Against Expense Account", - "no_copy": 1, - "oldfieldname": "against_expense_account", - "oldfieldtype": "Small Text", - "print_hide": 1 - }, - { - "fieldname": "column_break_63", - "fieldtype": "Column Break" - }, - { - "default": "Draft", - "fieldname": "status", - "fieldtype": "Select", - "in_standard_filter": 1, - "label": "Status", - "options": "\nDraft\nReturn\nDebit Note Issued\nSubmitted\nPaid\nPartly Paid\nUnpaid\nOverdue\nCancelled\nInternal Transfer", - "print_hide": 1 - }, - { - "fieldname": "inter_company_invoice_reference", - "fieldtype": "Link", - "label": "Inter Company Invoice Reference", - "no_copy": 1, - "options": "Sales Invoice", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "remarks", - "fieldtype": "Small Text", - "label": "Remarks", - "no_copy": 1, - "oldfieldname": "remarks", - "oldfieldtype": "Text", - "print_hide": 1 - }, - { - "collapsible": 1, - "fieldname": "subscription_section", - "fieldtype": "Section Break", - "label": "Subscription Section", - "print_hide": 1 - }, - { - "allow_on_submit": 1, - "description": "Start date of current invoice's period", - "fieldname": "from_date", - "fieldtype": "Date", - "label": "From Date", - "no_copy": 1, - "print_hide": 1 - }, - { - "allow_on_submit": 1, - "description": "End date of current invoice's period", - "fieldname": "to_date", - "fieldtype": "Date", - "label": "To Date", - "no_copy": 1, - "print_hide": 1 - }, - { - "fieldname": "column_break_114", - "fieldtype": "Column Break" - }, - { - "fieldname": "auto_repeat", - "fieldtype": "Link", - "label": "Auto Repeat", - "no_copy": 1, - "options": "Auto Repeat", - "print_hide": 1, - "read_only": 1 - }, - { - "allow_on_submit": 1, - "depends_on": "eval: doc.auto_repeat", - "fieldname": "update_auto_repeat_reference", - "fieldtype": "Button", - "label": "Update Auto Repeat Reference" - }, - { - "collapsible": 1, - "fieldname": "accounting_dimensions_section", - "fieldtype": "Section Break", - "label": "Accounting Dimensions " - }, - { - "fieldname": "dimension_col_break", - "fieldtype": "Column Break" - }, - { - "fieldname": "tax_withholding_category", - "fieldtype": "Link", - "hidden": 1, - "label": "Tax Withholding Category", - "options": "Tax Withholding Category", - "print_hide": 1 - }, - { - "fieldname": "billing_address", - "fieldtype": "Link", - "label": "Select Billing Address", - "options": "Address" - }, - { - "fieldname": "billing_address_display", - "fieldtype": "Small Text", - "label": "Billing Address", - "read_only": 1 - }, - { - "fieldname": "project", - "fieldtype": "Link", - "label": "Project", - "options": "Project" - }, - { - "depends_on": "eval:doc.is_internal_supplier", - "description": "Unrealized Profit / Loss account for intra-company transfers", - "fieldname": "unrealized_profit_loss_account", - "fieldtype": "Link", - "label": "Unrealized Profit / Loss Account", - "options": "Account" - }, - { - "depends_on": "eval:doc.is_internal_supplier", - "description": "Company which internal supplier represents", - "fetch_from": "supplier.represents_company", - "fieldname": "represents_company", - "fieldtype": "Link", - "label": "Represents Company", - "options": "Company" - }, - { - "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", - "no_copy": 1, - "options": "Warehouse", - "print_hide": 1, - "print_width": "50px", - "width": "50px" - }, - { - "depends_on": "eval:doc.is_subcontracted", - "fieldname": "supplier_warehouse", - "fieldtype": "Link", - "label": "Supplier Warehouse", - "no_copy": 1, - "options": "Warehouse", - "print_hide": 1, - "print_width": "50px", - "width": "50px" - }, - { - "fieldname": "per_received", - "fieldtype": "Percent", - "hidden": 1, - "label": "Per Received", - "no_copy": 1, - "print_hide": 1, - "read_only": 1 - }, - { - "default": "0", - "fieldname": "ignore_default_payment_terms_template", - "fieldtype": "Check", - "hidden": 1, - "label": "Ignore Default Payment Terms Template", - "read_only": 1 - }, - { - "collapsible": 1, - "fieldname": "accounting_details_section", - "fieldtype": "Section Break", - "label": "Accounting Details", - "print_hide": 1 - }, - { - "fieldname": "column_break_147", - "fieldtype": "Column Break" - }, - { - "fieldname": "advance_tax", - "fieldtype": "Table", - "hidden": 1, - "label": "Advance Tax", - "options": "Advance Tax", - "read_only": 1 - }, - { - "default": "0", - "fieldname": "is_old_subcontracting_flow", - "fieldtype": "Check", - "hidden": 1, - "label": "Is Old Subcontracting Flow", - "read_only": 1 - }, - { - "default": "0", - "fieldname": "tax_withholding_net_total", - "fieldtype": "Currency", - "label": "Tax Withholding Net Total", - "no_copy": 1, - "options": "currency", - "read_only": 1 - }, - { - "fieldname": "tax_withheld_vouchers_section", - "fieldtype": "Section Break", - "label": "Tax Withheld Vouchers" - }, - { - "fieldname": "tax_withheld_vouchers", - "fieldtype": "Table", - "label": "Tax Withheld Vouchers", - "options": "Tax Withheld Vouchers", - "read_only": 1 - } - ], - "icon": "fa fa-file-text", - "idx": 204, - "is_submittable": 1, - "links": [], - "modified": "2022-09-27 13:52:55.766844", - "modified_by": "Administrator", - "module": "Accounts", - "name": "Purchase Invoice", - "name_case": "Title Case", - "naming_rule": "By \"Naming Series\" field", - "owner": "Administrator", - "permissions": [ - { - "amend": 1, - "cancel": 1, - "create": 1, - "email": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Accounts User", - "share": 1, - "submit": 1, - "write": 1 - }, - { - "email": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Purchase User" - }, - { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Accounts Manager", - "share": 1, - "submit": 1, - "write": 1 - }, - { - "email": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Auditor" - }, - { - "permlevel": 1, - "read": 1, - "role": "Accounts Manager", - "write": 1 - } - ], - "search_fields": "posting_date, supplier, bill_no, base_grand_total, outstanding_amount", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "states": [], - "timeline_field": "supplier", - "title_field": "title", - "track_changes": 1 - } \ No newline at end of file + "actions": [], + "allow_import": 1, + "autoname": "naming_series:", + "creation": "2013-05-21 16:16:39", + "doctype": "DocType", + "document_type": "Document", + "engine": "InnoDB", + "field_order": [ + "title", + "naming_series", + "supplier", + "supplier_name", + "tax_id", + "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", + "currency_and_price_list", + "currency", + "conversion_rate", + "column_break2", + "buying_price_list", + "price_list_currency", + "plc_conversion_rate", + "ignore_pricing_rule", + "sec_warehouse", + "scan_barcode", + "col_break_warehouse", + "update_stock", + "set_warehouse", + "set_from_warehouse", + "is_subcontracted", + "rejected_warehouse", + "supplier_warehouse", + "items_section", + "items", + "section_break_26", + "total_qty", + "total_net_weight", + "column_break_50", + "base_total", + "base_net_total", + "column_break_28", + "total", + "net_total", + "taxes_section", + "taxes_and_charges", + "column_break_58", + "tax_category", + "column_break_49", + "shipping_rule", + "section_break_51", + "taxes", + "totals", + "base_taxes_and_charges_added", + "base_taxes_and_charges_deducted", + "base_total_taxes_and_charges", + "column_break_40", + "taxes_and_charges_added", + "taxes_and_charges_deducted", + "total_taxes_and_charges", + "section_break_49", + "base_grand_total", + "base_rounding_adjustment", + "base_rounded_total", + "base_in_words", + "column_break8", + "grand_total", + "rounding_adjustment", + "rounded_total", + "in_words", + "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", + "base_paid_amount", + "clearance_date", + "col_br_payments", + "cash_bank_account", + "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", + "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", + "payment_schedule", + "terms_section_break", + "tc_name", + "terms", + "more_info_tab", + "status_section", + "status", + "column_break_177", + "per_received", + "supplier_invoice_details", + "bill_no", + "column_break_15", + "bill_date", + "accounting_details_section", + "credit_to", + "party_account_currency", + "is_opening", + "against_expense_account", + "column_break_63", + "unrealized_profit_loss_account", + "subscription_section", + "auto_repeat", + "update_auto_repeat_reference", + "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": [ + { + "allow_on_submit": 1, + "default": "{supplier_name}", + "fieldname": "title", + "fieldtype": "Data", + "hidden": 1, + "label": "Title", + "no_copy": 1, + "print_hide": 1 + }, + { + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Series", + "no_copy": 1, + "oldfieldname": "naming_series", + "oldfieldtype": "Select", + "options": "ACC-PINV-.YYYY.-\nACC-PINV-RET-.YYYY.-", + "print_hide": 1, + "reqd": 1, + "set_only_once": 1 + }, + { + "fieldname": "supplier", + "fieldtype": "Link", + "in_standard_filter": 1, + "label": "Supplier", + "oldfieldname": "supplier", + "oldfieldtype": "Link", + "options": "Supplier", + "print_hide": 1, + "reqd": 1, + "search_index": 1 + }, + { + "bold": 1, + "depends_on": "supplier", + "fetch_from": "supplier.supplier_name", + "fieldname": "supplier_name", + "fieldtype": "Data", + "in_global_search": 1, + "label": "Supplier Name", + "oldfieldname": "supplier_name", + "oldfieldtype": "Data", + "read_only": 1 + }, + { + "fetch_from": "supplier.tax_id", + "fieldname": "tax_id", + "fieldtype": "Read Only", + "label": "Tax Id", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "due_date", + "fieldtype": "Date", + "label": "Due Date", + "oldfieldname": "due_date", + "oldfieldtype": "Date" + }, + { + "default": "0", + "fieldname": "is_paid", + "fieldtype": "Check", + "label": "Is Paid", + "print_hide": 1 + }, + { + "default": "0", + "fieldname": "is_return", + "fieldtype": "Check", + "label": "Is Return (Debit Note)", + "no_copy": 1, + "print_hide": 1 + }, + { + "default": "0", + "fieldname": "apply_tds", + "fieldtype": "Check", + "label": "Apply Tax Withholding Amount", + "print_hide": 1 + }, + { + "fieldname": "column_break1", + "fieldtype": "Column Break", + "oldfieldtype": "Column Break", + "width": "50%" + }, + { + "fieldname": "company", + "fieldtype": "Link", + "in_standard_filter": 1, + "label": "Company", + "options": "Company", + "print_hide": 1, + "remember_last_selected_value": 1 + }, + { + "fieldname": "cost_center", + "fieldtype": "Link", + "label": "Cost Center", + "options": "Cost Center" + }, + { + "default": "Today", + "fieldname": "posting_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Date", + "oldfieldname": "posting_date", + "oldfieldtype": "Date", + "print_hide": 1, + "reqd": 1, + "search_index": 1 + }, + { + "fieldname": "posting_time", + "fieldtype": "Time", + "label": "Posting Time", + "no_copy": 1, + "print_hide": 1, + "print_width": "100px", + "width": "100px" + }, + { + "default": "0", + "depends_on": "eval:doc.docstatus==0", + "fieldname": "set_posting_time", + "fieldtype": "Check", + "label": "Edit Posting Date and Time", + "print_hide": 1 + }, + { + "fieldname": "amended_from", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Amended From", + "no_copy": 1, + "oldfieldname": "amended_from", + "oldfieldtype": "Link", + "options": "Purchase Invoice", + "print_hide": 1, + "read_only": 1 + }, + { + "collapsible": 1, + "collapsible_depends_on": "eval:doc.on_hold", + "fieldname": "sb_14", + "fieldtype": "Section Break", + "label": "Hold Invoice" + }, + { + "default": "0", + "fieldname": "on_hold", + "fieldtype": "Check", + "label": "Hold Invoice" + }, + { + "depends_on": "eval:doc.on_hold", + "description": "Once set, this invoice will be on hold till the set date", + "fieldname": "release_date", + "fieldtype": "Date", + "label": "Release Date" + }, + { + "fieldname": "cb_17", + "fieldtype": "Column Break" + }, + { + "depends_on": "eval:doc.on_hold", + "fieldname": "hold_comment", + "fieldtype": "Small Text", + "label": "Reason For Putting On Hold" + }, + { + "collapsible": 1, + "collapsible_depends_on": "bill_no", + "fieldname": "supplier_invoice_details", + "fieldtype": "Section Break", + "label": "Supplier Invoice" + }, + { + "fieldname": "bill_no", + "fieldtype": "Data", + "label": "Supplier Invoice No", + "oldfieldname": "bill_no", + "oldfieldtype": "Data", + "print_hide": 1 + }, + { + "fieldname": "column_break_15", + "fieldtype": "Column Break" + }, + { + "fieldname": "bill_date", + "fieldtype": "Date", + "label": "Supplier Invoice Date", + "no_copy": 1, + "oldfieldname": "bill_date", + "oldfieldtype": "Date", + "print_hide": 1 + }, + { + "depends_on": "return_against", + "fieldname": "return_against", + "fieldtype": "Link", + "label": "Return Against Purchase Invoice", + "no_copy": 1, + "options": "Purchase Invoice", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "section_addresses", + "fieldtype": "Section Break", + "label": "Supplier Address" + }, + { + "fieldname": "supplier_address", + "fieldtype": "Link", + "label": "Select Supplier Address", + "options": "Address", + "print_hide": 1 + }, + { + "fieldname": "address_display", + "fieldtype": "Small Text", + "label": "Address", + "read_only": 1 + }, + { + "fieldname": "contact_person", + "fieldtype": "Link", + "in_global_search": 1, + "label": "Contact Person", + "options": "Contact", + "print_hide": 1 + }, + { + "fieldname": "contact_display", + "fieldtype": "Small Text", + "label": "Contact", + "read_only": 1 + }, + { + "fieldname": "contact_mobile", + "fieldtype": "Small Text", + "label": "Mobile No", + "read_only": 1 + }, + { + "fieldname": "contact_email", + "fieldtype": "Small Text", + "label": "Contact Email", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "col_break_address", + "fieldtype": "Column Break" + }, + { + "fieldname": "shipping_address", + "fieldtype": "Link", + "label": "Select Shipping Address", + "options": "Address", + "print_hide": 1 + }, + { + "fieldname": "shipping_address_display", + "fieldtype": "Small Text", + "label": "Shipping Address", + "print_hide": 1, + "read_only": 1 + }, + { + "collapsible": 1, + "fieldname": "currency_and_price_list", + "fieldtype": "Section Break", + "label": "Currency and Price List", + "options": "fa fa-tag" + }, + { + "fieldname": "currency", + "fieldtype": "Link", + "label": "Currency", + "oldfieldname": "currency", + "oldfieldtype": "Select", + "options": "Currency", + "print_hide": 1 + }, + { + "fieldname": "conversion_rate", + "fieldtype": "Float", + "label": "Exchange Rate", + "oldfieldname": "conversion_rate", + "oldfieldtype": "Currency", + "precision": "9", + "print_hide": 1 + }, + { + "fieldname": "column_break2", + "fieldtype": "Column Break" + }, + { + "fieldname": "buying_price_list", + "fieldtype": "Link", + "label": "Price List", + "options": "Price List", + "print_hide": 1 + }, + { + "fieldname": "price_list_currency", + "fieldtype": "Link", + "label": "Price List Currency", + "options": "Currency", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "plc_conversion_rate", + "fieldtype": "Float", + "label": "Price List Exchange Rate", + "precision": "9", + "print_hide": 1 + }, + { + "default": "0", + "fieldname": "ignore_pricing_rule", + "fieldtype": "Check", + "label": "Ignore Pricing Rule", + "permlevel": 1, + "print_hide": 1 + }, + { + "fieldname": "sec_warehouse", + "fieldtype": "Section Break", + "hide_border": 1, + "label": "Items" + }, + { + "depends_on": "update_stock", + "fieldname": "set_warehouse", + "fieldtype": "Link", + "label": "Set Accepted Warehouse", + "options": "Warehouse", + "print_hide": 1 + }, + { + "depends_on": "update_stock", + "fieldname": "rejected_warehouse", + "fieldtype": "Link", + "label": "Rejected Warehouse", + "no_copy": 1, + "options": "Warehouse", + "print_hide": 1 + }, + { + "fieldname": "col_break_warehouse", + "fieldtype": "Column Break" + }, + { + "default": "0", + "fieldname": "is_subcontracted", + "fieldtype": "Check", + "label": "Is Subcontracted", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "items_section", + "fieldtype": "Section Break", + "hide_border": 1, + "oldfieldtype": "Section Break", + "options": "fa fa-shopping-cart" + }, + { + "default": "0", + "fieldname": "update_stock", + "fieldtype": "Check", + "label": "Update Stock", + "print_hide": 1 + }, + { + "fieldname": "scan_barcode", + "fieldtype": "Data", + "label": "Scan Barcode", + "options": "Barcode" + }, + { + "allow_bulk_edit": 1, + "fieldname": "items", + "fieldtype": "Table", + "label": "Items", + "oldfieldname": "entries", + "oldfieldtype": "Table", + "options": "Purchase Invoice Item", + "reqd": 1 + }, + { + "collapsible": 1, + "fieldname": "pricing_rule_details", + "fieldtype": "Section Break", + "label": "Pricing Rules" + }, + { + "fieldname": "pricing_rules", + "fieldtype": "Table", + "label": "Pricing Rule Detail", + "options": "Pricing Rule Detail", + "read_only": 1 + }, + { + "collapsible": 1, + "collapsible_depends_on": "supplied_items", + "fieldname": "raw_materials_supplied", + "fieldtype": "Section Break", + "label": "Raw Materials Supplied" + }, + { + "depends_on": "update_stock", + "fieldname": "supplied_items", + "fieldtype": "Table", + "label": "Supplied Items", + "no_copy": 1, + "options": "Purchase Receipt Item Supplied" + }, + { + "fieldname": "section_break_26", + "fieldtype": "Section Break" + }, + { + "fieldname": "total_qty", + "fieldtype": "Float", + "label": "Total Quantity", + "read_only": 1 + }, + { + "fieldname": "base_total", + "fieldtype": "Currency", + "label": "Total (Company Currency)", + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "base_net_total", + "fieldtype": "Currency", + "label": "Net Total (Company Currency)", + "oldfieldname": "net_total", + "oldfieldtype": "Currency", + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "column_break_28", + "fieldtype": "Column Break" + }, + { + "fieldname": "total", + "fieldtype": "Currency", + "label": "Total", + "options": "currency", + "read_only": 1 + }, + { + "fieldname": "net_total", + "fieldtype": "Currency", + "label": "Net Total", + "oldfieldname": "net_total_import", + "oldfieldtype": "Currency", + "options": "currency", + "print_hide": 1, + "read_only": 1 + }, + { + "depends_on": "total_net_weight", + "fieldname": "total_net_weight", + "fieldtype": "Float", + "label": "Total Net Weight", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "taxes_section", + "fieldtype": "Section Break", + "hide_border": 1, + "label": "Taxes and Charges", + "oldfieldtype": "Section Break", + "options": "fa fa-money" + }, + { + "fieldname": "tax_category", + "fieldtype": "Link", + "label": "Tax Category", + "options": "Tax Category", + "print_hide": 1 + }, + { + "fieldname": "column_break_49", + "fieldtype": "Column Break" + }, + { + "fieldname": "shipping_rule", + "fieldtype": "Link", + "label": "Shipping Rule", + "options": "Shipping Rule", + "print_hide": 1 + }, + { + "fieldname": "section_break_51", + "fieldtype": "Section Break", + "hide_border": 1 + }, + { + "fieldname": "taxes_and_charges", + "fieldtype": "Link", + "label": "Purchase Taxes and Charges Template", + "oldfieldname": "purchase_other_charges", + "oldfieldtype": "Link", + "options": "Purchase Taxes and Charges Template", + "print_hide": 1 + }, + { + "fieldname": "taxes", + "fieldtype": "Table", + "label": "Purchase Taxes and Charges", + "oldfieldname": "purchase_tax_details", + "oldfieldtype": "Table", + "options": "Purchase Taxes and Charges" + }, + { + "collapsible": 1, + "fieldname": "sec_tax_breakup", + "fieldtype": "Section Break", + "label": "Tax Breakup" + }, + { + "fieldname": "other_charges_calculation", + "fieldtype": "Long Text", + "label": "Taxes and Charges Calculation", + "no_copy": 1, + "oldfieldtype": "HTML", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "totals", + "fieldtype": "Section Break", + "oldfieldtype": "Section Break", + "options": "fa fa-money" + }, + { + "fieldname": "base_taxes_and_charges_added", + "fieldtype": "Currency", + "label": "Taxes and Charges Added (Company Currency)", + "oldfieldname": "other_charges_added", + "oldfieldtype": "Currency", + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "base_taxes_and_charges_deducted", + "fieldtype": "Currency", + "label": "Taxes and Charges Deducted (Company Currency)", + "oldfieldname": "other_charges_deducted", + "oldfieldtype": "Currency", + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "base_total_taxes_and_charges", + "fieldtype": "Currency", + "label": "Total Taxes and Charges (Company Currency)", + "oldfieldname": "total_tax", + "oldfieldtype": "Currency", + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "column_break_40", + "fieldtype": "Column Break" + }, + { + "fieldname": "taxes_and_charges_added", + "fieldtype": "Currency", + "label": "Taxes and Charges Added", + "oldfieldname": "other_charges_added_import", + "oldfieldtype": "Currency", + "options": "currency", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "taxes_and_charges_deducted", + "fieldtype": "Currency", + "label": "Taxes and Charges Deducted", + "oldfieldname": "other_charges_deducted_import", + "oldfieldtype": "Currency", + "options": "currency", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "total_taxes_and_charges", + "fieldtype": "Currency", + "label": "Total Taxes and Charges", + "options": "currency", + "print_hide": 1, + "read_only": 1 + }, + { + "collapsible": 1, + "fieldname": "section_break_44", + "fieldtype": "Section Break", + "label": "Additional Discount" + }, + { + "default": "Grand Total", + "fieldname": "apply_discount_on", + "fieldtype": "Select", + "label": "Apply Additional Discount On", + "options": "\nGrand Total\nNet Total", + "print_hide": 1 + }, + { + "fieldname": "base_discount_amount", + "fieldtype": "Currency", + "label": "Additional Discount Amount (Company Currency)", + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "column_break_46", + "fieldtype": "Column Break" + }, + { + "fieldname": "additional_discount_percentage", + "fieldtype": "Float", + "label": "Additional Discount Percentage", + "print_hide": 1 + }, + { + "fieldname": "discount_amount", + "fieldtype": "Currency", + "label": "Additional Discount Amount", + "options": "currency", + "print_hide": 1 + }, + { + "fieldname": "section_break_49", + "fieldtype": "Section Break", + "label": "Totals" + }, + { + "fieldname": "base_grand_total", + "fieldtype": "Currency", + "label": "Grand Total (Company Currency)", + "oldfieldname": "grand_total", + "oldfieldtype": "Currency", + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1 + }, + { + "depends_on": "eval:!doc.disable_rounded_total", + "fieldname": "base_rounding_adjustment", + "fieldtype": "Currency", + "label": "Rounding Adjustment (Company Currency)", + "no_copy": 1, + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1 + }, + { + "depends_on": "eval:!doc.disable_rounded_total", + "fieldname": "base_rounded_total", + "fieldtype": "Currency", + "label": "Rounded Total (Company Currency)", + "no_copy": 1, + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "base_in_words", + "fieldtype": "Data", + "label": "In Words (Company Currency)", + "length": 240, + "oldfieldname": "in_words", + "oldfieldtype": "Data", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "column_break8", + "fieldtype": "Column Break", + "oldfieldtype": "Column Break", + "print_hide": 1, + "width": "50%" + }, + { + "fieldname": "grand_total", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Grand Total", + "oldfieldname": "grand_total_import", + "oldfieldtype": "Currency", + "options": "currency", + "read_only": 1 + }, + { + "depends_on": "eval:!doc.disable_rounded_total", + "fieldname": "rounding_adjustment", + "fieldtype": "Currency", + "label": "Rounding Adjustment", + "no_copy": 1, + "options": "currency", + "print_hide": 1, + "read_only": 1 + }, + { + "depends_on": "eval:!doc.disable_rounded_total", + "fieldname": "rounded_total", + "fieldtype": "Currency", + "label": "Rounded Total", + "no_copy": 1, + "options": "currency", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "in_words", + "fieldtype": "Data", + "label": "In Words", + "length": 240, + "oldfieldname": "in_words_import", + "oldfieldtype": "Data", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "total_advance", + "fieldtype": "Currency", + "label": "Total Advance", + "no_copy": 1, + "oldfieldname": "total_advance", + "oldfieldtype": "Currency", + "options": "party_account_currency", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "outstanding_amount", + "fieldtype": "Currency", + "label": "Outstanding Amount", + "no_copy": 1, + "oldfieldname": "outstanding_amount", + "oldfieldtype": "Currency", + "options": "party_account_currency", + "print_hide": 1, + "read_only": 1 + }, + { + "default": "0", + "depends_on": "grand_total", + "fieldname": "disable_rounded_total", + "fieldtype": "Check", + "label": "Disable Rounded Total" + }, + { + "collapsible": 1, + "collapsible_depends_on": "paid_amount", + "depends_on": "eval:doc.is_paid===1||(doc.advances && doc.advances.length>0)", + "fieldname": "payments_section", + "fieldtype": "Section Break", + "label": "Payments" + }, + { + "fieldname": "mode_of_payment", + "fieldtype": "Link", + "label": "Mode of Payment", + "options": "Mode of Payment", + "print_hide": 1 + }, + { + "fieldname": "cash_bank_account", + "fieldtype": "Link", + "label": "Cash/Bank Account", + "options": "Account" + }, + { + "fieldname": "clearance_date", + "fieldtype": "Date", + "label": "Clearance Date", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "col_br_payments", + "fieldtype": "Column Break" + }, + { + "depends_on": "is_paid", + "fieldname": "paid_amount", + "fieldtype": "Currency", + "label": "Paid Amount", + "no_copy": 1, + "options": "currency", + "print_hide": 1 + }, + { + "fieldname": "base_paid_amount", + "fieldtype": "Currency", + "label": "Paid Amount (Company Currency)", + "no_copy": 1, + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1 + }, + { + "collapsible": 1, + "fieldname": "write_off", + "fieldtype": "Section Break", + "label": "Write Off" + }, + { + "fieldname": "write_off_amount", + "fieldtype": "Currency", + "label": "Write Off Amount", + "no_copy": 1, + "options": "currency", + "print_hide": 1 + }, + { + "fieldname": "base_write_off_amount", + "fieldtype": "Currency", + "label": "Write Off Amount (Company Currency)", + "no_copy": 1, + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "column_break_61", + "fieldtype": "Column Break" + }, + { + "depends_on": "eval:flt(doc.write_off_amount)!=0", + "fieldname": "write_off_account", + "fieldtype": "Link", + "label": "Write Off Account", + "options": "Account", + "print_hide": 1 + }, + { + "depends_on": "eval:flt(doc.write_off_amount)!=0", + "fieldname": "write_off_cost_center", + "fieldtype": "Link", + "label": "Write Off Cost Center", + "options": "Cost Center", + "print_hide": 1 + }, + { + "collapsible": 1, + "collapsible_depends_on": "advances", + "fieldname": "advances_section", + "fieldtype": "Section Break", + "label": "Advance Payments", + "oldfieldtype": "Section Break", + "options": "fa fa-money", + "print_hide": 1 + }, + { + "default": "0", + "fieldname": "allocate_advances_automatically", + "fieldtype": "Check", + "label": "Set Advances and Allocate (FIFO)" + }, + { + "depends_on": "eval:!doc.allocate_advances_automatically", + "fieldname": "get_advances", + "fieldtype": "Button", + "label": "Get Advances Paid", + "oldfieldtype": "Button", + "print_hide": 1 + }, + { + "fieldname": "advances", + "fieldtype": "Table", + "label": "Advances", + "no_copy": 1, + "oldfieldname": "advance_allocation_details", + "oldfieldtype": "Table", + "options": "Purchase Invoice Advance", + "print_hide": 1 + }, + { + "collapsible_depends_on": "eval:(!doc.is_return)", + "fieldname": "payment_schedule_section", + "fieldtype": "Section Break", + "label": "Payment Terms" + }, + { + "fieldname": "payment_terms_template", + "fieldtype": "Link", + "label": "Payment Terms Template", + "options": "Payment Terms Template" + }, + { + "fieldname": "payment_schedule", + "fieldtype": "Table", + "label": "Payment Schedule", + "no_copy": 1, + "options": "Payment Schedule", + "print_hide": 1 + }, + { + "fieldname": "terms_section_break", + "fieldtype": "Section Break", + "label": "Terms and Conditions", + "options": "fa fa-legal" + }, + { + "fieldname": "tc_name", + "fieldtype": "Link", + "label": "Terms", + "options": "Terms and Conditions", + "print_hide": 1 + }, + { + "fieldname": "terms", + "fieldtype": "Text Editor", + "label": "Terms and Conditions" + }, + { + "collapsible": 1, + "fieldname": "printing_settings", + "fieldtype": "Section Break", + "label": "Print Settings" + }, + { + "allow_on_submit": 1, + "fieldname": "letter_head", + "fieldtype": "Link", + "label": "Letter Head", + "options": "Letter Head", + "print_hide": 1 + }, + { + "allow_on_submit": 1, + "default": "0", + "fieldname": "group_same_items", + "fieldtype": "Check", + "label": "Group same items", + "print_hide": 1 + }, + { + "fieldname": "column_break_112", + "fieldtype": "Column Break" + }, + { + "allow_on_submit": 1, + "fieldname": "select_print_heading", + "fieldtype": "Link", + "label": "Print Heading", + "no_copy": 1, + "oldfieldname": "select_print_heading", + "oldfieldtype": "Link", + "options": "Print Heading", + "print_hide": 1, + "report_hide": 1 + }, + { + "fieldname": "language", + "fieldtype": "Data", + "label": "Print Language", + "print_hide": 1, + "read_only": 1 + }, + { + "default": "0", + "fetch_from": "supplier.is_internal_supplier", + "fieldname": "is_internal_supplier", + "fieldtype": "Check", + "ignore_user_permissions": 1, + "label": "Is Internal Supplier", + "read_only": 1 + }, + { + "fieldname": "credit_to", + "fieldtype": "Link", + "label": "Credit To", + "oldfieldname": "credit_to", + "oldfieldtype": "Link", + "options": "Account", + "print_hide": 1, + "reqd": 1, + "search_index": 1 + }, + { + "fieldname": "party_account_currency", + "fieldtype": "Link", + "hidden": 1, + "label": "Party Account Currency", + "no_copy": 1, + "options": "Currency", + "print_hide": 1, + "read_only": 1 + }, + { + "default": "No", + "fieldname": "is_opening", + "fieldtype": "Select", + "label": "Is Opening Entry", + "oldfieldname": "is_opening", + "oldfieldtype": "Select", + "options": "No\nYes", + "print_hide": 1 + }, + { + "fieldname": "against_expense_account", + "fieldtype": "Small Text", + "hidden": 1, + "label": "Against Expense Account", + "no_copy": 1, + "oldfieldname": "against_expense_account", + "oldfieldtype": "Small Text", + "print_hide": 1 + }, + { + "fieldname": "column_break_63", + "fieldtype": "Column Break" + }, + { + "default": "Draft", + "fieldname": "status", + "fieldtype": "Select", + "in_standard_filter": 1, + "label": "Status", + "options": "\nDraft\nReturn\nDebit Note Issued\nSubmitted\nPaid\nPartly Paid\nUnpaid\nOverdue\nCancelled\nInternal Transfer", + "print_hide": 1 + }, + { + "fieldname": "inter_company_invoice_reference", + "fieldtype": "Link", + "label": "Inter Company Invoice Reference", + "no_copy": 1, + "options": "Sales Invoice", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "remarks", + "fieldtype": "Small Text", + "label": "Remarks", + "no_copy": 1, + "oldfieldname": "remarks", + "oldfieldtype": "Text", + "print_hide": 1 + }, + { + "collapsible": 1, + "fieldname": "subscription_section", + "fieldtype": "Section Break", + "label": "Subscription", + "print_hide": 1 + }, + { + "allow_on_submit": 1, + "description": "Start date of current invoice's period", + "fieldname": "from_date", + "fieldtype": "Date", + "label": "From Date", + "no_copy": 1, + "print_hide": 1 + }, + { + "allow_on_submit": 1, + "description": "End date of current invoice's period", + "fieldname": "to_date", + "fieldtype": "Date", + "label": "To Date", + "no_copy": 1, + "print_hide": 1 + }, + { + "fieldname": "column_break_114", + "fieldtype": "Column Break" + }, + { + "fieldname": "auto_repeat", + "fieldtype": "Link", + "label": "Auto Repeat", + "no_copy": 1, + "options": "Auto Repeat", + "print_hide": 1, + "read_only": 1 + }, + { + "allow_on_submit": 1, + "depends_on": "eval: doc.auto_repeat", + "fieldname": "update_auto_repeat_reference", + "fieldtype": "Button", + "label": "Update Auto Repeat Reference" + }, + { + "collapsible": 1, + "fieldname": "accounting_dimensions_section", + "fieldtype": "Section Break", + "label": "Accounting Dimensions " + }, + { + "fieldname": "dimension_col_break", + "fieldtype": "Column Break" + }, + { + "fieldname": "tax_withholding_category", + "fieldtype": "Link", + "hidden": 1, + "label": "Tax Withholding Category", + "options": "Tax Withholding Category", + "print_hide": 1 + }, + { + "fieldname": "billing_address", + "fieldtype": "Link", + "label": "Select Billing Address", + "options": "Address" + }, + { + "fieldname": "billing_address_display", + "fieldtype": "Small Text", + "label": "Billing Address", + "read_only": 1 + }, + { + "fieldname": "project", + "fieldtype": "Link", + "label": "Project", + "options": "Project" + }, + { + "depends_on": "eval:doc.is_internal_supplier", + "description": "Unrealized Profit/Loss account for intra-company transfers", + "fieldname": "unrealized_profit_loss_account", + "fieldtype": "Link", + "label": "Unrealized Profit / Loss Account", + "options": "Account" + }, + { + "depends_on": "eval:doc.is_internal_supplier", + "description": "Company which internal supplier represents", + "fetch_from": "supplier.represents_company", + "fieldname": "represents_company", + "fieldtype": "Link", + "label": "Represents Company", + "options": "Company" + }, + { + "depends_on": "eval:doc.update_stock && doc.is_internal_supplier", + "fieldname": "set_from_warehouse", + "fieldtype": "Link", + "label": "Set From Warehouse", + "no_copy": 1, + "options": "Warehouse", + "print_hide": 1, + "print_width": "50px", + "width": "50px" + }, + { + "depends_on": "eval:doc.is_subcontracted", + "fieldname": "supplier_warehouse", + "fieldtype": "Link", + "label": "Supplier Warehouse", + "no_copy": 1, + "options": "Warehouse", + "print_hide": 1, + "print_width": "50px", + "width": "50px" + }, + { + "fieldname": "per_received", + "fieldtype": "Percent", + "hidden": 1, + "label": "Per Received", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 + }, + { + "default": "0", + "fieldname": "ignore_default_payment_terms_template", + "fieldtype": "Check", + "hidden": 1, + "label": "Ignore Default Payment Terms Template", + "read_only": 1 + }, + { + "collapsible": 1, + "fieldname": "accounting_details_section", + "fieldtype": "Section Break", + "label": "Accounting Details", + "print_hide": 1 + }, + { + "fieldname": "column_break_147", + "fieldtype": "Column Break" + }, + { + "fieldname": "advance_tax", + "fieldtype": "Table", + "hidden": 1, + "label": "Advance Tax", + "options": "Advance Tax", + "read_only": 1 + }, + { + "default": "0", + "fieldname": "is_old_subcontracting_flow", + "fieldtype": "Check", + "hidden": 1, + "label": "Is Old Subcontracting Flow", + "read_only": 1 + }, + { + "collapsible_depends_on": "tax_withheld_vouchers", + "fieldname": "tax_withheld_vouchers_section", + "fieldtype": "Section Break", + "label": "Tax Withheld Vouchers" + }, + { + "fieldname": "tax_withheld_vouchers", + "fieldtype": "Table", + "label": "Tax Withheld Vouchers", + "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-11 13:04:44.304389", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Purchase Invoice", + "name_case": "Title Case", + "naming_rule": "By \"Naming Series\" field", + "owner": "Administrator", + "permissions": [ + { + "amend": 1, + "cancel": 1, + "create": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts User", + "share": 1, + "submit": 1, + "write": 1 + }, + { + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Purchase User" + }, + { + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts Manager", + "share": 1, + "submit": 1, + "write": 1 + }, + { + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Auditor" + }, + { + "permlevel": 1, + "read": 1, + "role": "Accounts Manager", + "write": 1 + } + ], + "search_fields": "posting_date, supplier, bill_no, base_grand_total, outstanding_amount", + "show_name_in_global_search": 1, + "sort_field": "modified", + "sort_order": "DESC", + "states": [], + "timeline_field": "supplier", + "title_field": "title", + "track_changes": 1 +} diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 2b633cb8c3..882a374046 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -71,6 +71,9 @@ class PurchaseInvoice(BuyingController): supplier_tds = frappe.db.get_value("Supplier", self.supplier, "tax_withholding_category") self.set_onload("supplier_tds", supplier_tds) + if self.is_new(): + self.set("tax_withheld_vouchers", []) + def before_save(self): if not self.on_hold: self.release_date = "" @@ -705,6 +708,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 +721,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 +1418,7 @@ class PurchaseInvoice(BuyingController): "Stock Ledger Entry", "Repost Item Valuation", "Payment Ledger Entry", + "Tax Withheld Vouchers", ) 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 bee6e0982f..5c1cb0dcc6 100644 --- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json +++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json @@ -215,6 +215,7 @@ "reqd": 1 }, { + "default": "1", "depends_on": "eval:doc.uom != doc.stock_uom", "fieldname": "conversion_factor", "fieldtype": "Float", @@ -712,6 +713,7 @@ "label": "Valuation Rate", "no_copy": 1, "options": "Company:company:default_currency", + "precision": "6", "print_hide": 1, "read_only": 1 }, @@ -820,6 +822,7 @@ }, { "collapsible": 1, + "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount", "fieldname": "section_break_26", "fieldtype": "Section Break", "label": "Discount and Margin" @@ -877,7 +880,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2022-09-27 10:54:23.980713", + "modified": "2022-10-26 16:05:37.304788", "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..cb0d1a75a0 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 @@ -955,7 +965,8 @@ class TestSalesInvoice(unittest.TestCase): pos_return.insert() pos_return.submit() - self.assertEqual(pos_return.get("payments")[0].amount, -1000) + self.assertEqual(pos_return.get("payments")[0].amount, -500) + self.assertEqual(pos_return.get("payments")[1].amount, -500) def test_pos_change_amount(self): make_pos_profile( @@ -1705,7 +1716,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 +1760,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 +2378,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 +2428,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 +2497,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 +2513,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 +2569,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 +3079,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 +3229,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 +3324,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 +3337,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 +3450,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 +3500,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..7f1a1eccc4 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -247,6 +247,7 @@ }, { "collapsible": 1, + "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount", "fieldname": "discount_and_margin", "fieldtype": "Section Break", "label": "Discount and Margin" @@ -820,6 +821,7 @@ "label": "Incoming Rate (Costing)", "no_copy": 1, "options": "Company:company:default_currency", + "precision": "6", "print_hide": 1 }, { @@ -875,7 +877,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2022-09-06 14:17:43.394309", + "modified": "2022-10-26 11:38:36.119339", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", diff --git a/erpnext/accounts/doctype/subscription_plan/subscription_plan.py b/erpnext/accounts/doctype/subscription_plan/subscription_plan.py index a95e0a9c2d..f3acdc5aa8 100644 --- a/erpnext/accounts/doctype/subscription_plan/subscription_plan.py +++ b/erpnext/accounts/doctype/subscription_plan/subscription_plan.py @@ -3,6 +3,7 @@ import frappe +from dateutil import relativedelta from frappe import _ from frappe.model.document import Document from frappe.utils import date_diff, flt, get_first_day, get_last_day, getdate @@ -49,7 +50,7 @@ def get_plan_rate( start_date = getdate(start_date) end_date = getdate(end_date) - no_of_months = (end_date.year - start_date.year) * 12 + (end_date.month - start_date.month) + 1 + no_of_months = relativedelta.relativedelta(end_date, start_date).months + 1 cost = plan.cost * no_of_months # Adjust cost if start or end date is not month start or end diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py index 92cb9489e0..737338e04f 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -252,6 +252,9 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N ) else: tax_amount = net_total * tax_details.rate / 100 if net_total > 0 else 0 + + # once tds is deducted, not need to add vouchers in the invoice + voucher_wise_amount = {} else: tax_amount = get_tds_amount(ldc, parties, inv, tax_details, tax_deducted, vouchers) @@ -428,8 +431,11 @@ def get_tds_amount(ldc, parties, inv, tax_details, tax_deducted, vouchers): ): # Get net total again as TDS is calculated on net total # Grand is used to just check for threshold breach - net_total = frappe.db.get_value("Purchase Invoice", invoice_filters, "sum(tax_withholding_net_total)") or 0.0 - net_total += inv.tax_withholding_net_total + net_total = 0 + if vouchers: + net_total = frappe.db.get_value("Purchase Invoice", invoice_filters, "sum(net_total)") + + net_total += inv.net_total supp_credit_amt = net_total - cumulative_threshold if ldc and is_valid_certificate( diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index f4a50a5f91..6d164eef2b 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -128,6 +128,12 @@ def distribute_gl_based_on_cost_center_allocation(gl_map, precision=None): new_gl_map = [] for d in gl_map: cost_center = d.get("cost_center") + + # Validate budget against main cost center + validate_expense_against_budget( + d, expense_amount=flt(d.debit, precision) - flt(d.credit, precision) + ) + if cost_center and cost_center_allocation.get(cost_center): for sub_cost_center, percentage in cost_center_allocation.get(cost_center, {}).items(): gle = copy.deepcopy(d) diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.js b/erpnext/accounts/report/accounts_payable/accounts_payable.js index 7cf14e6738..e1a30a4b77 100644 --- a/erpnext/accounts/report/accounts_payable/accounts_payable.js +++ b/erpnext/accounts/report/accounts_payable/accounts_payable.js @@ -51,6 +51,8 @@ frappe.query_reports["Accounts Payable"] = { } else { frappe.query_report.set_filter_value('tax_id', ""); } + + frappe.query_report.refresh(); } }, { diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 8557c03bd5..f2ee1eb10e 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -748,7 +748,7 @@ class ReceivablePayableReport(object): self.add_accounting_dimensions_filters() - def get_cost_center_conditions(self, conditions): + def get_cost_center_conditions(self): lft, rgt = frappe.db.get_value("Cost Center", self.filters.cost_center, ["lft", "rgt"]) cost_center_list = [ center.name diff --git a/erpnext/accounts/report/general_ledger/general_ledger.html b/erpnext/accounts/report/general_ledger/general_ledger.html index 378fa3791c..c04f518d7e 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.html +++ b/erpnext/accounts/report/general_ledger/general_ledger.html @@ -52,22 +52,22 @@ {% } %} - {%= format_currency(data[i].debit, filters.presentation_currency) %} + {%= format_currency(data[i].debit, filters.presentation_currency || data[i].account_currency) %} - {%= format_currency(data[i].credit, filters.presentation_currency) %} + {%= format_currency(data[i].credit, filters.presentation_currency || data[i].account_currency) %} {% } else { %} {%= frappe.format(data[i].account, {fieldtype: "Link"}) || " " %} - {%= data[i].account && format_currency(data[i].debit, filters.presentation_currency) %} + {%= data[i].account && format_currency(data[i].debit, filters.presentation_currency || data[i].account_currency) %} - {%= data[i].account && format_currency(data[i].credit, filters.presentation_currency) %} + {%= data[i].account && format_currency(data[i].credit, filters.presentation_currency || data[i].account_currency) %} {% } %} - {%= format_currency(data[i].balance, filters.presentation_currency) %} + {%= format_currency(data[i].balance, filters.presentation_currency || data[i].account_currency) %} {% } %} diff --git a/erpnext/accounts/report/payment_ledger/__init__.py b/erpnext/accounts/report/payment_ledger/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/accounts/report/payment_ledger/payment_ledger.js b/erpnext/accounts/report/payment_ledger/payment_ledger.js new file mode 100644 index 0000000000..9779844dc9 --- /dev/null +++ b/erpnext/accounts/report/payment_ledger/payment_ledger.js @@ -0,0 +1,59 @@ +// Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt +/* eslint-disable */ + +function get_filters() { + let filters = [ + { + "fieldname":"company", + "label": __("Company"), + "fieldtype": "Link", + "options": "Company", + "default": frappe.defaults.get_user_default("Company"), + "reqd": 1 + }, + { + "fieldname":"period_start_date", + "label": __("Start Date"), + "fieldtype": "Date", + "reqd": 1, + "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1) + }, + { + "fieldname":"period_end_date", + "label": __("End Date"), + "fieldtype": "Date", + "reqd": 1, + "default": frappe.datetime.get_today() + }, + { + "fieldname":"account", + "label": __("Account"), + "fieldtype": "MultiSelectList", + "options": "Account", + get_data: function(txt) { + return frappe.db.get_link_options('Account', txt, { + company: frappe.query_report.get_filter_value("company") + }); + } + }, + { + "fieldname":"voucher_no", + "label": __("Voucher No"), + "fieldtype": "Data", + "width": 100, + }, + { + "fieldname":"against_voucher_no", + "label": __("Against Voucher No"), + "fieldtype": "Data", + "width": 100, + }, + + ] + return filters; +} + +frappe.query_reports["Payment Ledger"] = { + "filters": get_filters() +}; diff --git a/erpnext/accounts/report/payment_ledger/payment_ledger.json b/erpnext/accounts/report/payment_ledger/payment_ledger.json new file mode 100644 index 0000000000..716329fbef --- /dev/null +++ b/erpnext/accounts/report/payment_ledger/payment_ledger.json @@ -0,0 +1,32 @@ +{ + "add_total_row": 0, + "columns": [], + "creation": "2022-06-06 08:50:43.933708", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "modified": "2022-06-06 08:50:43.933708", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Payment Ledger", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Payment Ledger Entry", + "report_name": "Payment Ledger", + "report_type": "Script Report", + "roles": [ + { + "role": "Accounts User" + }, + { + "role": "Accounts Manager" + }, + { + "role": "Auditor" + } + ] +} \ No newline at end of file diff --git a/erpnext/accounts/report/payment_ledger/payment_ledger.py b/erpnext/accounts/report/payment_ledger/payment_ledger.py new file mode 100644 index 0000000000..e470c2727e --- /dev/null +++ b/erpnext/accounts/report/payment_ledger/payment_ledger.py @@ -0,0 +1,222 @@ +# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from collections import OrderedDict + +import frappe +from frappe import _, qb +from frappe.query_builder import Criterion + + +class PaymentLedger(object): + def __init__(self, filters=None): + self.filters = filters + self.columns, self.data = [], [] + self.voucher_dict = OrderedDict() + self.voucher_amount = [] + self.ple = qb.DocType("Payment Ledger Entry") + + def init_voucher_dict(self): + + if self.voucher_amount: + s = set() + # build a set of unique vouchers + for ple in self.voucher_amount: + key = (ple.voucher_type, ple.voucher_no, ple.party) + s.add(key) + + # for each unique vouchers, initialize +/- list + for key in s: + self.voucher_dict[key] = frappe._dict(increase=list(), decrease=list()) + + # for each ple, using against voucher and amount, assign it to +/- list + # group by against voucher + for ple in self.voucher_amount: + against_key = (ple.against_voucher_type, ple.against_voucher_no, ple.party) + target = None + if self.voucher_dict.get(against_key): + if ple.amount > 0: + target = self.voucher_dict.get(against_key).increase + else: + target = self.voucher_dict.get(against_key).decrease + + # this if condition will lose unassigned ple entries(against_voucher doc doesn't have ple) + # need to somehow include the stray entries as well. + if target is not None: + entry = frappe._dict( + company=ple.company, + account=ple.account, + party_type=ple.party_type, + party=ple.party, + voucher_type=ple.voucher_type, + voucher_no=ple.voucher_no, + against_voucher_type=ple.against_voucher_type, + against_voucher_no=ple.against_voucher_no, + amount=ple.amount, + currency=ple.account_currency, + ) + + if self.filters.include_account_currency: + entry["amount_in_account_currency"] = ple.amount_in_account_currency + + target.append(entry) + + def build_data(self): + self.data.clear() + + for value in self.voucher_dict.values(): + voucher_data = [] + if value.increase != []: + voucher_data.extend(value.increase) + if value.decrease != []: + voucher_data.extend(value.decrease) + + if voucher_data: + # balance row + total = 0 + total_in_account_currency = 0 + + for x in voucher_data: + total += x.amount + if self.filters.include_account_currency: + total_in_account_currency += x.amount_in_account_currency + + entry = frappe._dict( + against_voucher_no="Outstanding:", + amount=total, + currency=voucher_data[0].currency, + ) + + if self.filters.include_account_currency: + entry["amount_in_account_currency"] = total_in_account_currency + + voucher_data.append(entry) + + # empty row + voucher_data.append(frappe._dict()) + self.data.extend(voucher_data) + + def build_conditions(self): + self.conditions = [] + + if self.filters.company: + self.conditions.append(self.ple.company == self.filters.company) + + if self.filters.account: + self.conditions.append(self.ple.account.isin(self.filters.account)) + + if self.filters.period_start_date: + self.conditions.append(self.ple.posting_date.gte(self.filters.period_start_date)) + + if self.filters.period_end_date: + self.conditions.append(self.ple.posting_date.lte(self.filters.period_end_date)) + + if self.filters.voucher_no: + self.conditions.append(self.ple.voucher_no == self.filters.voucher_no) + + if self.filters.against_voucher_no: + self.conditions.append(self.ple.against_voucher_no == self.filters.against_voucher_no) + + def get_data(self): + ple = self.ple + + self.build_conditions() + + # fetch data from table + self.voucher_amount = ( + qb.from_(ple) + .select(ple.star) + .where(ple.delinked == 0) + .where(Criterion.all(self.conditions)) + .run(as_dict=True) + ) + + def get_columns(self): + options = None + self.columns.append( + dict(label=_("Company"), fieldname="company", fieldtype="data", options=options, width="100") + ) + + self.columns.append( + dict(label=_("Account"), fieldname="account", fieldtype="data", options=options, width="100") + ) + + self.columns.append( + dict( + label=_("Party Type"), fieldname="party_type", fieldtype="data", options=options, width="100" + ) + ) + self.columns.append( + dict(label=_("Party"), fieldname="party", fieldtype="data", options=options, width="100") + ) + self.columns.append( + dict( + label=_("Voucher Type"), + fieldname="voucher_type", + fieldtype="data", + options=options, + width="100", + ) + ) + self.columns.append( + dict( + label=_("Voucher No"), fieldname="voucher_no", fieldtype="data", options=options, width="100" + ) + ) + self.columns.append( + dict( + label=_("Against Voucher Type"), + fieldname="against_voucher_type", + fieldtype="data", + options=options, + width="100", + ) + ) + self.columns.append( + dict( + label=_("Against Voucher No"), + fieldname="against_voucher_no", + fieldtype="data", + options=options, + width="100", + ) + ) + self.columns.append( + dict( + label=_("Amount"), + fieldname="amount", + fieldtype="Currency", + options="Company:company:default_currency", + width="100", + ) + ) + + if self.filters.include_account_currency: + self.columns.append( + dict( + label=_("Amount in Account Currency"), + fieldname="amount_in_account_currency", + fieldtype="Currency", + options="currency", + width="100", + ) + ) + self.columns.append( + dict(label=_("Currency"), fieldname="currency", fieldtype="Currency", hidden=True) + ) + + def run(self): + self.get_columns() + self.get_data() + + # initialize dictionary and group using against voucher + self.init_voucher_dict() + + # convert dictionary to list and add balance rows + self.build_data() + + return self.columns, self.data + + +def execute(filters=None): + return PaymentLedger(filters).run() diff --git a/erpnext/accounts/report/payment_ledger/test_payment_ledger.py b/erpnext/accounts/report/payment_ledger/test_payment_ledger.py new file mode 100644 index 0000000000..5ae9b87cde --- /dev/null +++ b/erpnext/accounts/report/payment_ledger/test_payment_ledger.py @@ -0,0 +1,65 @@ +import unittest + +import frappe +from frappe import qb +from frappe.tests.utils import FrappeTestCase + +from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry +from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice +from erpnext.accounts.report.payment_ledger.payment_ledger import execute + + +class TestPaymentLedger(FrappeTestCase): + def setUp(self): + self.create_company() + self.cleanup() + + def cleanup(self): + doctypes = [] + doctypes.append(qb.DocType("GL Entry")) + doctypes.append(qb.DocType("Payment Ledger Entry")) + doctypes.append(qb.DocType("Sales Invoice")) + doctypes.append(qb.DocType("Payment Entry")) + + for doctype in doctypes: + qb.from_(doctype).delete().where(doctype.company == self.company).run() + + def create_company(self): + name = "Test Payment Ledger" + 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 + self.cost_center = company.cost_center + self.warehouse = "All Warehouses" + " - " + company.abbr + self.income_account = company.default_income_account + self.expense_account = company.default_expense_account + self.debit_to = company.default_receivable_account + + def test_unpaid_invoice_outstanding(self): + sinv = create_sales_invoice( + company=self.company, + debit_to=self.debit_to, + expense_account=self.expense_account, + cost_center=self.cost_center, + income_account=self.income_account, + warehouse=self.warehouse, + ) + pe = get_payment_entry(sinv.doctype, sinv.name).save().submit() + + filters = frappe._dict({"company": self.company}) + columns, data = execute(filters=filters) + outstanding = [x for x in data if x.get("against_voucher_no") == "Outstanding:"] + self.assertEqual(outstanding[0].get("amount"), 0) diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 9ede67848d..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): """ @@ -648,6 +644,16 @@ def unlink_ref_doc_from_payment_entries(ref_doc): (now(), frappe.session.user, ref_doc.doctype, ref_doc.name), ) + ple = qb.DocType("Payment Ledger Entry") + + qb.update(ple).set(ple.against_voucher_type, ple.voucher_type).set( + ple.against_voucher_no, ple.voucher_no + ).set(ple.modified, now()).set(ple.modified_by, frappe.session.user).where( + (ple.against_voucher_type == ref_doc.doctype) + & (ple.against_voucher_no == ref_doc.name) + & (ple.delinked == 0) + ).run() + if ref_doc.doctype in ("Sales Invoice", "Purchase Invoice"): ref_doc.set("advances", []) @@ -1161,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( @@ -1358,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 @@ -1400,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): @@ -1457,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/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index 370b13bb98..5c1311d68a 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -221,7 +221,7 @@ class TestAsset(AssetSetup): asset.precision("gross_purchase_amount"), ) pro_rata_amount, _, _ = asset.get_pro_rata_amt( - asset.finance_books[0], 9000, add_months(get_last_day(purchase_date), 1), date + asset.finance_books[0], 9000, get_last_day(add_months(purchase_date, 1)), date ) pro_rata_amount = flt(pro_rata_amount, asset.precision("gross_purchase_amount")) self.assertEquals(accumulated_depr_amount, 18000.00 + pro_rata_amount) @@ -283,7 +283,7 @@ class TestAsset(AssetSetup): self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Sold") pro_rata_amount, _, _ = asset.get_pro_rata_amt( - asset.finance_books[0], 9000, add_months(get_last_day(purchase_date), 1), date + asset.finance_books[0], 9000, get_last_day(add_months(purchase_date, 1)), date ) pro_rata_amount = flt(pro_rata_amount, asset.precision("gross_purchase_amount")) diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py index 8758e9c17d..d5913c5946 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/asset_repair.py @@ -135,6 +135,7 @@ class AssetRepair(AccountsController): "basic_rate": stock_item.valuation_rate, "serial_no": stock_item.serial_no, "cost_center": self.cost_center, + "project": self.project, }, ) diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py index 59ab6a910d..84aa8fa023 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py @@ -61,7 +61,9 @@ class AssetValueAdjustment(Document): je.naming_series = depreciation_series je.posting_date = self.date je.company = self.company - je.remark = "Depreciation Entry against {0} worth {1}".format(self.asset, self.difference_amount) + je.remark = _("Depreciation Entry against {0} worth {1}").format( + self.asset, self.difference_amount + ) je.finance_book = self.finance_book credit_entry = { diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index ddf81ca3ae..06fdea030c 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -101,6 +101,11 @@ frappe.ui.form.on("Purchase Order", { erpnext.queries.setup_queries(frm, "Warehouse", function() { return erpnext.queries.warehouse(frm.doc); }); + + // On cancel and amending a purchase order with advance payment, reset advance paid amount + if (frm.is_new()) { + frm.set_value("advance_paid", 0) + } }, apply_tds: function(frm) { 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 cd58d25136..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 @@ -349,7 +349,7 @@ class PurchaseOrder(BuyingController): update_linked_doc(self.doctype, self.name, self.inter_company_order_reference) def on_cancel(self): - self.ignore_linked_doctypes = "Payment Ledger Entry" + self.ignore_linked_doctypes = ("GL Entry", "Payment Ledger Entry") super(PurchaseOrder, self).on_cancel() if self.is_against_so(): @@ -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/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json index 82e92e87bc..b8203bd128 100644 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json @@ -777,6 +777,7 @@ }, { "collapsible": 1, + "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount", "fieldname": "discount_and_margin_section", "fieldtype": "Section Break", "label": "Discount and Margin" @@ -894,7 +895,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2022-09-07 11:12:38.634976", + "modified": "2022-10-26 16:47:41.364387", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order Item", diff --git a/erpnext/buying/doctype/supplier/test_supplier.py b/erpnext/buying/doctype/supplier/test_supplier.py index 55722686fe..e2dbf21be2 100644 --- a/erpnext/buying/doctype/supplier/test_supplier.py +++ b/erpnext/buying/doctype/supplier/test_supplier.py @@ -3,6 +3,7 @@ import frappe +from frappe.custom.doctype.property_setter.property_setter import make_property_setter from frappe.test_runner import make_test_records from erpnext.accounts.party import get_due_date @@ -152,6 +153,40 @@ class TestSupplier(FrappeTestCase): # Rollback address.delete() + def test_serach_fields_for_supplier(self): + from erpnext.controllers.queries import supplier_query + + supplier_name = create_supplier(supplier_name="Test Supplier 1").name + + make_property_setter( + "Supplier", None, "search_fields", "supplier_group", "Data", for_doctype="Doctype" + ) + + data = supplier_query( + "Supplier", supplier_name, "name", 0, 20, filters={"name": supplier_name}, as_dict=True + ) + + self.assertEqual(data[0].name, supplier_name) + self.assertEqual(data[0].supplier_group, "Services") + self.assertTrue("supplier_type" not in data[0]) + + make_property_setter( + "Supplier", + None, + "search_fields", + "supplier_group, supplier_type", + "Data", + for_doctype="Doctype", + ) + data = supplier_query( + "Supplier", supplier_name, "name", 0, 20, filters={"name": supplier_name}, as_dict=True + ) + + self.assertEqual(data[0].name, supplier_name) + self.assertEqual(data[0].supplier_group, "Services") + self.assertEqual(data[0].supplier_type, "Company") + self.assertTrue("supplier_type" in data[0]) + def create_supplier(**args): args = frappe._dict(args) 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/queries.py b/erpnext/controllers/queries.py index 8eae0a0702..3bdc017068 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -78,18 +78,16 @@ def lead_query(doctype, txt, searchfield, start, page_len, filters): @frappe.whitelist() @frappe.validate_and_sanitize_search_inputs -def customer_query(doctype, txt, searchfield, start, page_len, filters): +def customer_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False): doctype = "Customer" conditions = [] cust_master_name = frappe.defaults.get_user_default("cust_master_name") - if cust_master_name == "Customer Name": - fields = ["name", "customer_group", "territory"] - else: - fields = ["name", "customer_name", "customer_group", "territory"] + fields = ["name"] + if cust_master_name != "Customer Name": + fields = ["customer_name"] fields = get_fields(doctype, fields) - searchfields = frappe.get_meta(doctype).get_search_fields() searchfields = " or ".join(field + " like %(txt)s" for field in searchfields) @@ -112,20 +110,20 @@ def customer_query(doctype, txt, searchfield, start, page_len, filters): } ), {"txt": "%%%s%%" % txt, "_txt": txt.replace("%", ""), "start": start, "page_len": page_len}, + as_dict=as_dict, ) # searches for supplier @frappe.whitelist() @frappe.validate_and_sanitize_search_inputs -def supplier_query(doctype, txt, searchfield, start, page_len, filters): +def supplier_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False): doctype = "Supplier" supp_master_name = frappe.defaults.get_user_default("supp_master_name") - if supp_master_name == "Supplier Name": - fields = ["name", "supplier_group"] - else: - fields = ["name", "supplier_name", "supplier_group"] + fields = ["name"] + if supp_master_name != "Supplier Name": + fields = ["supplier_name"] fields = get_fields(doctype, fields) @@ -145,6 +143,7 @@ def supplier_query(doctype, txt, searchfield, start, page_len, filters): **{"field": ", ".join(fields), "key": searchfield, "mcond": get_match_cond(doctype)} ), {"txt": "%%%s%%" % txt, "_txt": txt.replace("%", ""), "start": start, "page_len": page_len}, + as_dict=as_dict, ) 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/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index 5182b2f0ca..a0bc6ba629 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -900,24 +900,33 @@ class calculate_taxes_and_totals(object): self.doc.other_charges_calculation = get_itemised_tax_breakup_html(self.doc) def set_total_amount_to_default_mop(self, total_amount_to_pay): - default_mode_of_payment = frappe.db.get_value( - "POS Payment Method", - {"parent": self.doc.pos_profile, "default": 1}, - ["mode_of_payment"], - as_dict=1, - ) - - if default_mode_of_payment: - self.doc.payments = [] - self.doc.append( - "payments", - { - "mode_of_payment": default_mode_of_payment.mode_of_payment, - "amount": total_amount_to_pay, - "default": 1, - }, + total_paid_amount = 0 + for payment in self.doc.get("payments"): + total_paid_amount += ( + payment.amount if self.doc.party_account_currency == self.doc.currency else payment.base_amount ) + pending_amount = total_amount_to_pay - total_paid_amount + + if pending_amount > 0: + default_mode_of_payment = frappe.db.get_value( + "POS Payment Method", + {"parent": self.doc.pos_profile, "default": 1}, + ["mode_of_payment"], + as_dict=1, + ) + + if default_mode_of_payment: + self.doc.payments = [] + self.doc.append( + "payments", + { + "mode_of_payment": default_mode_of_payment.mode_of_payment, + "amount": pending_amount, + "default": 1, + }, + ) + def get_itemised_tax_breakup_html(doc): if not doc.taxes: 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/e_commerce/doctype/website_item/website_item.json b/erpnext/e_commerce/doctype/website_item/website_item.json index c5775ee907..6556eabf4a 100644 --- a/erpnext/e_commerce/doctype/website_item/website_item.json +++ b/erpnext/e_commerce/doctype/website_item/website_item.json @@ -188,7 +188,8 @@ "in_list_view": 1, "label": "Item Group", "options": "Item Group", - "read_only": 1 + "read_only": 1, + "search_index": 1 }, { "default": "1", @@ -234,7 +235,8 @@ "fieldname": "brand", "fieldtype": "Link", "label": "Brand", - "options": "Brand" + "options": "Brand", + "search_index": 1 }, { "collapsible": 1, @@ -346,7 +348,7 @@ "index_web_pages_for_search": 1, "links": [], "make_attachments_public": 1, - "modified": "2022-09-13 04:05:11.614087", + "modified": "2022-09-30 04:01:52.090732", "modified_by": "Administrator", "module": "E-commerce", "name": "Website Item", diff --git a/erpnext/e_commerce/doctype/website_item/website_item.py b/erpnext/e_commerce/doctype/website_item/website_item.py index c0f8c79283..3e5d5f768f 100644 --- a/erpnext/e_commerce/doctype/website_item/website_item.py +++ b/erpnext/e_commerce/doctype/website_item/website_item.py @@ -403,9 +403,6 @@ def on_doctype_update(): # since route is a Text column, it needs a length for indexing frappe.db.add_index("Website Item", ["route(500)"]) - frappe.db.add_index("Website Item", ["item_group"]) - frappe.db.add_index("Website Item", ["brand"]) - def check_if_user_is_customer(user=None): from frappe.contacts.doctype.contact.contact import get_contact_name 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/loan_management/doctype/loan/loan.js b/erpnext/loan_management/doctype/loan/loan.js index 38328e6967..20e2b0b201 100644 --- a/erpnext/loan_management/doctype/loan/loan.js +++ b/erpnext/loan_management/doctype/loan/loan.js @@ -61,6 +61,10 @@ frappe.ui.form.on('Loan', { }, refresh: function (frm) { + if (frm.doc.repayment_schedule_type == "Pro-rated calendar months") { + frm.set_df_property("repayment_start_date", "label", "Interest Calculation Start Date"); + } + if (frm.doc.docstatus == 1) { if (["Disbursed", "Partially Disbursed"].includes(frm.doc.status) && (!frm.doc.repay_from_salary)) { frm.add_custom_button(__('Request Loan Closure'), function() { @@ -103,6 +107,14 @@ frappe.ui.form.on('Loan', { frm.trigger("toggle_fields"); }, + repayment_schedule_type: function(frm) { + if (frm.doc.repayment_schedule_type == "Pro-rated calendar months") { + frm.set_df_property("repayment_start_date", "label", "Interest Calculation Start Date"); + } else { + frm.set_df_property("repayment_start_date", "label", "Repayment Start Date"); + } + }, + loan_type: function(frm) { frm.toggle_reqd("repayment_method", frm.doc.is_term_loan); frm.toggle_display("repayment_method", frm.doc.is_term_loan); diff --git a/erpnext/loan_management/doctype/loan/loan.json b/erpnext/loan_management/doctype/loan/loan.json index 47488f43ce..dc8b03e89d 100644 --- a/erpnext/loan_management/doctype/loan/loan.json +++ b/erpnext/loan_management/doctype/loan/loan.json @@ -18,6 +18,7 @@ "status", "section_break_8", "loan_type", + "repayment_schedule_type", "loan_amount", "rate_of_interest", "is_secured_loan", @@ -158,7 +159,8 @@ "depends_on": "is_term_loan", "fieldname": "repayment_start_date", "fieldtype": "Date", - "label": "Repayment Start Date" + "label": "Repayment Start Date", + "mandatory_depends_on": "is_term_loan" }, { "fieldname": "column_break_11", @@ -402,12 +404,20 @@ "fieldname": "is_npa", "fieldtype": "Check", "label": "Is NPA" + }, + { + "depends_on": "is_term_loan", + "fetch_from": "loan_type.repayment_schedule_type", + "fieldname": "repayment_schedule_type", + "fieldtype": "Data", + "label": "Repayment Schedule Type", + "read_only": 1 } ], "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2022-07-12 11:50:31.957360", + "modified": "2022-09-30 10:36:47.902903", "modified_by": "Administrator", "module": "Loan Management", "name": "Loan", diff --git a/erpnext/loan_management/doctype/loan/loan.py b/erpnext/loan_management/doctype/loan/loan.py index d84eef6d8c..0c9c97f60f 100644 --- a/erpnext/loan_management/doctype/loan/loan.py +++ b/erpnext/loan_management/doctype/loan/loan.py @@ -7,7 +7,16 @@ import math import frappe from frappe import _ -from frappe.utils import add_months, flt, get_last_day, getdate, now_datetime, nowdate +from frappe.utils import ( + add_days, + add_months, + date_diff, + flt, + get_last_day, + getdate, + now_datetime, + nowdate, +) import erpnext from erpnext.accounts.doctype.journal_entry.journal_entry import get_payment_entry @@ -107,30 +116,81 @@ class Loan(AccountsController): if not self.repayment_start_date: frappe.throw(_("Repayment Start Date is mandatory for term loans")) + schedule_type_details = frappe.db.get_value( + "Loan Type", self.loan_type, ["repayment_schedule_type", "repayment_date_on"], as_dict=1 + ) + self.repayment_schedule = [] payment_date = self.repayment_start_date balance_amount = self.loan_amount - while balance_amount > 0: - interest_amount = flt(balance_amount * flt(self.rate_of_interest) / (12 * 100)) - principal_amount = self.monthly_repayment_amount - interest_amount - balance_amount = flt(balance_amount + interest_amount - self.monthly_repayment_amount) - if balance_amount < 0: - principal_amount += balance_amount - balance_amount = 0.0 - total_payment = principal_amount + interest_amount - self.append( - "repayment_schedule", - { - "payment_date": payment_date, - "principal_amount": principal_amount, - "interest_amount": interest_amount, - "total_payment": total_payment, - "balance_loan_amount": balance_amount, - }, + while balance_amount > 0: + interest_amount, principal_amount, balance_amount, total_payment = self.get_amounts( + payment_date, + balance_amount, + schedule_type_details.repayment_schedule_type, + schedule_type_details.repayment_date_on, ) - next_payment_date = add_single_month(payment_date) - payment_date = next_payment_date + + if schedule_type_details.repayment_schedule_type == "Pro-rated calendar months": + next_payment_date = get_last_day(payment_date) + if schedule_type_details.repayment_date_on == "Start of the next month": + next_payment_date = add_days(next_payment_date, 1) + + payment_date = next_payment_date + + self.add_repayment_schedule_row( + payment_date, principal_amount, interest_amount, total_payment, balance_amount + ) + + if ( + schedule_type_details.repayment_schedule_type == "Monthly as per repayment start date" + or schedule_type_details.repayment_date_on == "End of the current month" + ): + next_payment_date = add_single_month(payment_date) + payment_date = next_payment_date + + def get_amounts(self, payment_date, balance_amount, schedule_type, repayment_date_on): + if schedule_type == "Monthly as per repayment start date": + days = 1 + months = 12 + else: + expected_payment_date = get_last_day(payment_date) + if repayment_date_on == "Start of the next month": + expected_payment_date = add_days(expected_payment_date, 1) + + if expected_payment_date == payment_date: + # using 30 days for calculating interest for all full months + days = 30 + months = 365 + else: + days = date_diff(get_last_day(payment_date), payment_date) + months = 365 + + interest_amount = flt(balance_amount * flt(self.rate_of_interest) * days / (months * 100)) + principal_amount = self.monthly_repayment_amount - interest_amount + balance_amount = flt(balance_amount + interest_amount - self.monthly_repayment_amount) + if balance_amount < 0: + principal_amount += balance_amount + balance_amount = 0.0 + + total_payment = principal_amount + interest_amount + + return interest_amount, principal_amount, balance_amount, total_payment + + def add_repayment_schedule_row( + self, payment_date, principal_amount, interest_amount, total_payment, balance_loan_amount + ): + self.append( + "repayment_schedule", + { + "payment_date": payment_date, + "principal_amount": principal_amount, + "interest_amount": interest_amount, + "total_payment": total_payment, + "balance_loan_amount": balance_loan_amount, + }, + ) def set_repayment_period(self): if self.repayment_method == "Repay Fixed Amount per Period": diff --git a/erpnext/loan_management/doctype/loan/test_loan.py b/erpnext/loan_management/doctype/loan/test_loan.py index da05c8e90c..388e65d9e5 100644 --- a/erpnext/loan_management/doctype/loan/test_loan.py +++ b/erpnext/loan_management/doctype/loan/test_loan.py @@ -4,7 +4,16 @@ import unittest import frappe -from frappe.utils import add_days, add_months, add_to_date, date_diff, flt, get_datetime, nowdate +from frappe.utils import ( + add_days, + add_months, + add_to_date, + date_diff, + flt, + format_date, + get_datetime, + nowdate, +) from erpnext.loan_management.doctype.loan.loan import ( make_loan_write_off, @@ -47,6 +56,51 @@ class TestLoan(unittest.TestCase): loan_account="Loan Account - _TC", interest_income_account="Interest Income Account - _TC", penalty_income_account="Penalty Income Account - _TC", + repayment_schedule_type="Monthly as per repayment start date", + ) + + create_loan_type( + "Term Loan Type 1", + 12000, + 7.5, + is_term_loan=1, + mode_of_payment="Cash", + disbursement_account="Disbursement Account - _TC", + payment_account="Payment Account - _TC", + loan_account="Loan Account - _TC", + interest_income_account="Interest Income Account - _TC", + penalty_income_account="Penalty Income Account - _TC", + repayment_schedule_type="Monthly as per repayment start date", + ) + + create_loan_type( + "Term Loan Type 2", + 12000, + 7.5, + is_term_loan=1, + mode_of_payment="Cash", + disbursement_account="Disbursement Account - _TC", + payment_account="Payment Account - _TC", + loan_account="Loan Account - _TC", + interest_income_account="Interest Income Account - _TC", + penalty_income_account="Penalty Income Account - _TC", + repayment_schedule_type="Pro-rated calendar months", + repayment_date_on="Start of the next month", + ) + + create_loan_type( + "Term Loan Type 3", + 12000, + 7.5, + is_term_loan=1, + mode_of_payment="Cash", + disbursement_account="Disbursement Account - _TC", + payment_account="Payment Account - _TC", + loan_account="Loan Account - _TC", + interest_income_account="Interest Income Account - _TC", + penalty_income_account="Penalty Income Account - _TC", + repayment_schedule_type="Pro-rated calendar months", + repayment_date_on="End of the current month", ) create_loan_type( @@ -62,6 +116,7 @@ class TestLoan(unittest.TestCase): "Loan Account - _TC", "Interest Income Account - _TC", "Penalty Income Account - _TC", + repayment_schedule_type="Monthly as per repayment start date", ) create_loan_type( @@ -902,6 +957,69 @@ class TestLoan(unittest.TestCase): amounts = calculate_amounts(loan.name, add_days(last_date, 5)) self.assertEqual(flt(amounts["pending_principal_amount"], 0), 0) + def test_term_loan_schedule_types(self): + loan = create_loan( + self.applicant1, + "Term Loan Type 1", + 12000, + "Repay Over Number of Periods", + 12, + repayment_start_date="2022-10-17", + ) + + # Check for first, second and last installment date + self.assertEqual( + format_date(loan.get("repayment_schedule")[0].payment_date, "dd-MM-yyyy"), "17-10-2022" + ) + self.assertEqual( + format_date(loan.get("repayment_schedule")[1].payment_date, "dd-MM-yyyy"), "17-11-2022" + ) + self.assertEqual( + format_date(loan.get("repayment_schedule")[-1].payment_date, "dd-MM-yyyy"), "17-09-2023" + ) + + loan.loan_type = "Term Loan Type 2" + loan.save() + + # Check for first, second and last installment date + self.assertEqual( + format_date(loan.get("repayment_schedule")[0].payment_date, "dd-MM-yyyy"), "01-11-2022" + ) + self.assertEqual( + format_date(loan.get("repayment_schedule")[1].payment_date, "dd-MM-yyyy"), "01-12-2022" + ) + self.assertEqual( + format_date(loan.get("repayment_schedule")[-1].payment_date, "dd-MM-yyyy"), "01-10-2023" + ) + + loan.loan_type = "Term Loan Type 3" + loan.save() + + # Check for first, second and last installment date + self.assertEqual( + format_date(loan.get("repayment_schedule")[0].payment_date, "dd-MM-yyyy"), "31-10-2022" + ) + self.assertEqual( + format_date(loan.get("repayment_schedule")[1].payment_date, "dd-MM-yyyy"), "30-11-2022" + ) + self.assertEqual( + format_date(loan.get("repayment_schedule")[-1].payment_date, "dd-MM-yyyy"), "30-09-2023" + ) + + loan.repayment_method = "Repay Fixed Amount per Period" + loan.monthly_repayment_amount = 1042 + loan.save() + + self.assertEqual( + format_date(loan.get("repayment_schedule")[0].payment_date, "dd-MM-yyyy"), "31-10-2022" + ) + self.assertEqual( + format_date(loan.get("repayment_schedule")[1].payment_date, "dd-MM-yyyy"), "30-11-2022" + ) + self.assertEqual( + format_date(loan.get("repayment_schedule")[-1].payment_date, "dd-MM-yyyy"), "30-09-2023" + ) + def create_loan_scenario_for_penalty(doc): pledge = [{"loan_security": "Test Security 1", "qty": 4000.00}] @@ -1033,6 +1151,8 @@ def create_loan_type( penalty_income_account=None, repayment_method=None, repayment_periods=None, + repayment_schedule_type=None, + repayment_date_on=None, ): if not frappe.db.exists("Loan Type", loan_name): @@ -1042,6 +1162,7 @@ def create_loan_type( "company": "_Test Company", "loan_name": loan_name, "is_term_loan": is_term_loan, + "repayment_schedule_type": "Monthly as per repayment start date", "maximum_loan_amount": maximum_loan_amount, "rate_of_interest": rate_of_interest, "penalty_interest_rate": penalty_interest_rate, @@ -1056,8 +1177,14 @@ def create_loan_type( "repayment_periods": repayment_periods, "write_off_amount": 100, } - ).insert() + ) + if loan_type.is_term_loan: + loan_type.repayment_schedule_type = repayment_schedule_type + if loan_type.repayment_schedule_type != "Monthly as per repayment start date": + loan_type.repayment_date_on = repayment_date_on + + loan_type.insert() loan_type.submit() diff --git a/erpnext/loan_management/doctype/loan_type/loan_type.json b/erpnext/loan_management/doctype/loan_type/loan_type.json index 00337e4b4c..5cc9464585 100644 --- a/erpnext/loan_management/doctype/loan_type/loan_type.json +++ b/erpnext/loan_management/doctype/loan_type/loan_type.json @@ -16,6 +16,8 @@ "company", "is_term_loan", "disabled", + "repayment_schedule_type", + "repayment_date_on", "description", "account_details_section", "mode_of_payment", @@ -157,12 +159,30 @@ "label": "Disbursement Account", "options": "Account", "reqd": 1 + }, + { + "depends_on": "is_term_loan", + "description": "The schedule type that will be used for generating the term loan schedules (will affect the payment date and monthly repayment amount)", + "fieldname": "repayment_schedule_type", + "fieldtype": "Select", + "label": "Repayment Schedule Type", + "mandatory_depends_on": "is_term_loan", + "options": "\nMonthly as per repayment start date\nPro-rated calendar months" + }, + { + "depends_on": "eval:doc.repayment_schedule_type == \"Pro-rated calendar months\"", + "description": "Select whether the repayment date should be the end of the current month or start of the upcoming month", + "fieldname": "repayment_date_on", + "fieldtype": "Select", + "label": "Repayment Date On", + "mandatory_depends_on": "eval:doc.repayment_schedule_type == \"Pro-rated calendar months\"", + "options": "\nStart of the next month\nEnd of the current month" } ], "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2022-01-25 16:23:57.009349", + "modified": "2022-10-22 17:43:03.954201", "modified_by": "Administrator", "module": "Loan Management", "name": "Loan Type", diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index ff84991c36..580838e215 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -385,6 +385,7 @@ class BOM(WebsiteGenerator): if self.docstatus == 2: return + self.flags.cost_updated = False existing_bom_cost = self.total_cost if self.docstatus == 1: @@ -407,7 +408,11 @@ class BOM(WebsiteGenerator): frappe.get_doc("BOM", bom).update_cost(from_child_bom=True) if not from_child_bom: - frappe.msgprint(_("Cost Updated"), alert=True) + msg = "Cost Updated" + if not self.flags.cost_updated: + msg = "No changes in cost found" + + frappe.msgprint(_(msg), alert=True) def update_parent_cost(self): if self.total_cost: @@ -593,11 +598,16 @@ class BOM(WebsiteGenerator): # not via doc event, table is not regenerated and needs updation self.calculate_exploded_cost() + old_cost = self.total_cost + self.total_cost = self.operating_cost + self.raw_material_cost - self.scrap_material_cost self.base_total_cost = ( self.base_operating_cost + self.base_raw_material_cost - self.base_scrap_material_cost ) + if self.total_cost != old_cost: + self.flags.cost_updated = True + def calculate_op_cost(self, update_hour_rate=False): """Update workstation rate and calculates totals""" self.operating_cost = 0 diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py index 27f3cc905b..e34ac12cd2 100644 --- a/erpnext/manufacturing/doctype/bom/test_bom.py +++ b/erpnext/manufacturing/doctype/bom/test_bom.py @@ -9,7 +9,10 @@ import frappe from frappe.tests.utils import FrappeTestCase from frappe.utils import cstr, flt -from erpnext.controllers.tests.test_subcontracting_controller import set_backflush_based_on +from erpnext.controllers.tests.test_subcontracting_controller import ( + make_stock_in_entry, + set_backflush_based_on, +) from erpnext.manufacturing.doctype.bom.bom import BOMRecursionError, item_query, make_variant_bom from erpnext.manufacturing.doctype.bom_update_log.test_bom_update_log import ( update_cost_in_all_boms_in_test, @@ -639,6 +642,28 @@ class TestBOM(FrappeTestCase): bom.submit() self.assertEqual(bom.exploded_items[0].rate, bom.items[0].base_rate) + def test_bom_cost_update_flag(self): + rm_item = make_item( + properties={"is_stock_item": 1, "valuation_rate": 99, "last_purchase_rate": 89} + ).name + fg_item = make_item(properties={"is_stock_item": 1}).name + + from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom + + bom = make_bom(item=fg_item, raw_materials=[rm_item]) + + create_stock_reconciliation( + item_code=rm_item, warehouse="_Test Warehouse - _TC", qty=100, rate=600 + ) + + bom.load_from_db() + bom.update_cost() + self.assertTrue(bom.flags.cost_updated) + + bom.load_from_db() + bom.update_cost() + self.assertFalse(bom.flags.cost_updated) + def get_default_bom(item_code="_Test FG Item 2"): return frappe.db.get_value("BOM", {"item": item_code, "is_active": 1, "is_default": 1}) 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/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py index a53c42c5ec..804f03dc51 100644 --- a/erpnext/manufacturing/doctype/work_order/test_work_order.py +++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py @@ -17,6 +17,7 @@ from erpnext.manufacturing.doctype.work_order.work_order import ( close_work_order, make_job_card, make_stock_entry, + make_stock_return_entry, stop_unstop, ) from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order @@ -1408,6 +1409,77 @@ class TestWorkOrder(FrappeTestCase): ) self.assertEqual(manufacture_ste_doc2.items[1].qty, 1) + def test_non_consumed_material_return_against_work_order(self): + frappe.db.set_value( + "Manufacturing Settings", + None, + "backflush_raw_materials_based_on", + "Material Transferred for Manufacture", + ) + + item = make_item( + "Test FG Item To Test Return Case", + { + "is_stock_item": 1, + }, + ) + + item_code = item.name + bom_doc = make_bom( + item=item_code, + source_warehouse="Stores - _TC", + raw_materials=["Test Batch MCC Keyboard", "Test Serial No BTT Headphone"], + ) + + # Create a work order + wo_doc = make_wo_order_test_record(production_item=item_code, qty=5) + wo_doc.save() + + self.assertEqual(wo_doc.bom_no, bom_doc.name) + + # Transfer material for manufacture + ste_doc = frappe.get_doc(make_stock_entry(wo_doc.name, "Material Transfer for Manufacture", 5)) + for row in ste_doc.items: + row.qty += 2 + row.transfer_qty += 2 + nste_doc = test_stock_entry.make_stock_entry( + item_code=row.item_code, target="Stores - _TC", qty=row.qty, basic_rate=100 + ) + + row.batch_no = nste_doc.items[0].batch_no + row.serial_no = nste_doc.items[0].serial_no + + ste_doc.save() + ste_doc.submit() + ste_doc.load_from_db() + + # Create a stock entry to manufacture the item + ste_doc = frappe.get_doc(make_stock_entry(wo_doc.name, "Manufacture", 5)) + for row in ste_doc.items: + if row.s_warehouse and not row.t_warehouse: + row.qty -= 2 + row.transfer_qty -= 2 + + if row.serial_no: + serial_nos = get_serial_nos(row.serial_no) + row.serial_no = "\n".join(serial_nos[0:5]) + + ste_doc.save() + ste_doc.submit() + + wo_doc.load_from_db() + for row in wo_doc.required_items: + self.assertEqual(row.transferred_qty, 7) + self.assertEqual(row.consumed_qty, 5) + + self.assertEqual(wo_doc.status, "Completed") + return_ste_doc = make_stock_return_entry(wo_doc.name) + return_ste_doc.save() + + self.assertTrue(return_ste_doc.is_return) + for row in return_ste_doc.items: + self.assertEqual(row.qty, 2) + def prepare_data_for_backflush_based_on_materials_transferred(): batch_item_doc = make_item( diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js index f3640b93b2..4aab3fa373 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.js +++ b/erpnext/manufacturing/doctype/work_order/work_order.js @@ -180,6 +180,37 @@ frappe.ui.form.on("Work Order", { frm.trigger("make_bom"); }); } + + frm.trigger("add_custom_button_to_return_components"); + }, + + add_custom_button_to_return_components: function(frm) { + if (frm.doc.docstatus === 1 && in_list(["Closed", "Completed"], frm.doc.status)) { + let non_consumed_items = frm.doc.required_items.filter(d =>{ + return flt(d.consumed_qty) < flt(d.transferred_qty - d.returned_qty) + }); + + if (non_consumed_items && non_consumed_items.length) { + frm.add_custom_button(__("Return Components"), function() { + frm.trigger("create_stock_return_entry"); + }).addClass("btn-primary"); + } + } + }, + + create_stock_return_entry: function(frm) { + frappe.call({ + method: "erpnext.manufacturing.doctype.work_order.work_order.make_stock_return_entry", + args: { + "work_order": frm.doc.name, + }, + callback: function(r) { + if(!r.exc) { + let doc = frappe.model.sync(r.message); + frappe.set_route("Form", doc[0].doctype, doc[0].name); + } + } + }); }, make_job_card: function(frm) { @@ -517,7 +548,8 @@ frappe.ui.form.on("Work Order Operation", { erpnext.work_order = { set_custom_buttons: function(frm) { var doc = frm.doc; - if (doc.docstatus === 1 && doc.status != "Closed") { + + if (doc.status !== "Closed") { frm.add_custom_button(__('Close'), function() { frappe.confirm(__("Once the Work Order is Closed. It can't be resumed."), () => { @@ -525,7 +557,9 @@ erpnext.work_order = { } ); }, __("Status")); + } + if (doc.docstatus === 1 && !in_list(["Closed", "Completed"], doc.status)) { if (doc.status != 'Stopped' && doc.status != 'Completed') { frm.add_custom_button(__('Stop'), function() { erpnext.work_order.change_work_order_status(frm, "Stopped"); diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index 7b8625372a..1e6d982fc9 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -20,6 +20,7 @@ from frappe.utils import ( nowdate, time_diff_in_hours, ) +from pypika import functions as fn from erpnext.manufacturing.doctype.bom.bom import ( get_bom_item_rate, @@ -859,6 +860,7 @@ class WorkOrder(Document): if self.docstatus == 1: # calculate transferred qty based on submitted stock entries self.update_transferred_qty_for_required_items() + self.update_returned_qty() # update in bin self.update_reserved_qty_for_production() @@ -930,23 +932,62 @@ class WorkOrder(Document): self.set_available_qty() def update_transferred_qty_for_required_items(self): - """update transferred qty from submitted stock entries for that item against - the work order""" + ste = frappe.qb.DocType("Stock Entry") + ste_child = frappe.qb.DocType("Stock Entry Detail") - for d in self.required_items: - transferred_qty = frappe.db.sql( - """select sum(qty) - from `tabStock Entry` entry, `tabStock Entry Detail` detail - where - entry.work_order = %(name)s - and entry.purpose = 'Material Transfer for Manufacture' - and entry.docstatus = 1 - and detail.parent = entry.name - and (detail.item_code = %(item)s or detail.original_item = %(item)s)""", - {"name": self.name, "item": d.item_code}, - )[0][0] + query = ( + frappe.qb.from_(ste) + .inner_join(ste_child) + .on((ste_child.parent == ste.name)) + .select( + ste_child.item_code, + ste_child.original_item, + fn.Sum(ste_child.qty).as_("qty"), + ) + .where( + (ste.docstatus == 1) + & (ste.work_order == self.name) + & (ste.purpose == "Material Transfer for Manufacture") + & (ste.is_return == 0) + ) + .groupby(ste_child.item_code) + ) - d.db_set("transferred_qty", flt(transferred_qty), update_modified=False) + data = query.run(as_dict=1) or [] + transferred_items = frappe._dict({d.original_item or d.item_code: d.qty for d in data}) + + for row in self.required_items: + row.db_set( + "transferred_qty", (transferred_items.get(row.item_code) or 0.0), update_modified=False + ) + + def update_returned_qty(self): + ste = frappe.qb.DocType("Stock Entry") + ste_child = frappe.qb.DocType("Stock Entry Detail") + + query = ( + frappe.qb.from_(ste) + .inner_join(ste_child) + .on((ste_child.parent == ste.name)) + .select( + ste_child.item_code, + ste_child.original_item, + fn.Sum(ste_child.qty).as_("qty"), + ) + .where( + (ste.docstatus == 1) + & (ste.work_order == self.name) + & (ste.purpose == "Material Transfer for Manufacture") + & (ste.is_return == 1) + ) + .groupby(ste_child.item_code) + ) + + data = query.run(as_dict=1) or [] + returned_dict = frappe._dict({d.original_item or d.item_code: d.qty for d in data}) + + for row in self.required_items: + row.db_set("returned_qty", (returned_dict.get(row.item_code) or 0.0), update_modified=False) def update_consumed_qty_for_required_items(self): """ @@ -1470,3 +1511,25 @@ def get_reserved_qty_for_production(item_code: str, warehouse: str) -> float: ) ) ).run()[0][0] or 0.0 + + +@frappe.whitelist() +def make_stock_return_entry(work_order): + from erpnext.stock.doctype.stock_entry.stock_entry import get_available_materials + + non_consumed_items = get_available_materials(work_order) + if not non_consumed_items: + return + + wo_doc = frappe.get_cached_doc("Work Order", work_order) + + stock_entry = frappe.new_doc("Stock Entry") + stock_entry.from_bom = 1 + stock_entry.is_return = 1 + stock_entry.work_order = work_order + stock_entry.purpose = "Material Transfer for Manufacture" + stock_entry.bom_no = wo_doc.bom_no + stock_entry.add_transfered_raw_materials_in_items() + stock_entry.set_stock_entry_type() + + return stock_entry diff --git a/erpnext/manufacturing/doctype/work_order_item/work_order_item.json b/erpnext/manufacturing/doctype/work_order_item/work_order_item.json index 3acf5727d1..f354d45381 100644 --- a/erpnext/manufacturing/doctype/work_order_item/work_order_item.json +++ b/erpnext/manufacturing/doctype/work_order_item/work_order_item.json @@ -20,6 +20,7 @@ "column_break_11", "transferred_qty", "consumed_qty", + "returned_qty", "available_qty_at_source_warehouse", "available_qty_at_wip_warehouse" ], @@ -97,6 +98,7 @@ "fieldtype": "Column Break" }, { + "columns": 1, "depends_on": "eval:!parent.skip_transfer", "fieldname": "consumed_qty", "fieldtype": "Float", @@ -127,11 +129,19 @@ "fieldtype": "Currency", "label": "Amount", "read_only": 1 + }, + { + "columns": 1, + "fieldname": "returned_qty", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Returned Qty ", + "read_only": 1 } ], "istable": 1, "links": [], - "modified": "2020-04-13 18:46:32.966416", + "modified": "2022-09-28 10:50:43.512562", "modified_by": "Administrator", "module": "Manufacturing", "name": "Work Order Item", @@ -140,5 +150,6 @@ "quick_entry": 1, "sort_field": "modified", "sort_order": "DESC", + "states": [], "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/manufacturing/report/work_order_consumed_materials/work_order_consumed_materials.js b/erpnext/manufacturing/report/work_order_consumed_materials/work_order_consumed_materials.js index b2428e85b7..2fb4ec6791 100644 --- a/erpnext/manufacturing/report/work_order_consumed_materials/work_order_consumed_materials.js +++ b/erpnext/manufacturing/report/work_order_consumed_materials/work_order_consumed_materials.js @@ -50,7 +50,7 @@ frappe.query_reports["Work Order Consumed Materials"] = { label: __("Status"), fieldname: "status", fieldtype: "Select", - options: ["In Process", "Completed", "Stopped"] + options: ["", "In Process", "Completed", "Stopped"] }, { label: __("Excess Materials Consumed"), diff --git a/erpnext/manufacturing/report/work_order_consumed_materials/work_order_consumed_materials.py b/erpnext/manufacturing/report/work_order_consumed_materials/work_order_consumed_materials.py index 8158bc9a02..14e97d3dd7 100644 --- a/erpnext/manufacturing/report/work_order_consumed_materials/work_order_consumed_materials.py +++ b/erpnext/manufacturing/report/work_order_consumed_materials/work_order_consumed_materials.py @@ -1,6 +1,8 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt +from collections import defaultdict + import frappe from frappe import _ @@ -18,7 +20,11 @@ def get_data(report_filters): filters = get_filter_condition(report_filters) wo_items = {} - for d in frappe.get_all("Work Order", filters=filters, fields=fields): + + work_orders = frappe.get_all("Work Order", filters=filters, fields=fields) + returned_materials = get_returned_materials(work_orders) + + for d in work_orders: d.extra_consumed_qty = 0.0 if d.consumed_qty and d.consumed_qty > d.required_qty: d.extra_consumed_qty = d.consumed_qty - d.required_qty @@ -39,6 +45,28 @@ def get_data(report_filters): return data +def get_returned_materials(work_orders): + raw_materials_qty = defaultdict(float) + + raw_materials = frappe.get_all( + "Stock Entry", + fields=["`tabStock Entry Detail`.`item_code`", "`tabStock Entry Detail`.`qty`"], + filters=[ + ["Stock Entry", "is_return", "=", 1], + ["Stock Entry Detail", "docstatus", "=", 1], + ["Stock Entry", "work_order", "in", [d.name for d in work_orders]], + ], + ) + + for d in raw_materials: + raw_materials_qty[d.item_code] += d.qty + + for row in work_orders: + row.returned_qty = 0.0 + if raw_materials_qty.get(row.raw_material_item_code): + row.returned_qty = raw_materials_qty.get(row.raw_material_item_code) + + def get_fields(): return [ "`tabWork Order Item`.`parent`", @@ -65,7 +93,7 @@ def get_filter_condition(report_filters): for field in ["name", "production_item", "company", "status"]: value = report_filters.get(field) if value: - key = f"`{field}`" + key = f"{field}" filters.update({key: value}) return filters @@ -112,4 +140,10 @@ def get_columns(): "fieldtype": "Float", "width": 100, }, + { + "label": _("Returned Qty"), + "fieldname": "returned_qty", + "fieldtype": "Float", + "width": 100, + }, ] diff --git a/erpnext/patches.txt b/erpnext/patches.txt index fc63f124e1..6a8c21f654 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -315,4 +315,5 @@ erpnext.patches.v14_0.fix_crm_no_of_employees erpnext.patches.v14_0.create_accounting_dimensions_in_subcontracting_doctypes erpnext.patches.v14_0.fix_subcontracting_receipt_gl_entries erpnext.patches.v14_0.migrate_remarks_from_gl_to_payment_ledger +erpnext.patches.v13_0.update_schedule_type_in_loans erpnext.patches.v14_0.create_accounting_dimensions_for_asset_capitalization diff --git a/erpnext/patches/v13_0/update_schedule_type_in_loans.py b/erpnext/patches/v13_0/update_schedule_type_in_loans.py new file mode 100644 index 0000000000..e5b5f64360 --- /dev/null +++ b/erpnext/patches/v13_0/update_schedule_type_in_loans.py @@ -0,0 +1,14 @@ +import frappe + + +def execute(): + loan = frappe.qb.DocType("Loan") + loan_type = frappe.qb.DocType("Loan Type") + + frappe.qb.update(loan_type).set( + loan_type.repayment_schedule_type, "Monthly as per repayment start date" + ).where(loan_type.is_term_loan == 1).run() + + frappe.qb.update(loan).set( + loan.repayment_schedule_type, "Monthly as per repayment start date" + ).where(loan.is_term_loan == 1).run() diff --git a/erpnext/patches/v14_0/migrate_remarks_from_gl_to_payment_ledger.py b/erpnext/patches/v14_0/migrate_remarks_from_gl_to_payment_ledger.py index 062d24b78b..fd2a2a39cc 100644 --- a/erpnext/patches/v14_0/migrate_remarks_from_gl_to_payment_ledger.py +++ b/erpnext/patches/v14_0/migrate_remarks_from_gl_to_payment_ledger.py @@ -3,6 +3,29 @@ from frappe import qb from frappe.utils import create_batch +def remove_duplicate_entries(pl_entries): + unique_vouchers = set() + for x in pl_entries: + unique_vouchers.add( + (x.company, x.account, x.party_type, x.party, x.voucher_type, x.voucher_no, x.gle_remarks) + ) + + entries = [] + for x in unique_vouchers: + entries.append( + frappe._dict( + company=x[0], + account=x[1], + party_type=x[2], + party=x[3], + voucher_type=x[4], + voucher_no=x[5], + gle_remarks=x[6], + ) + ) + return entries + + def execute(): if frappe.reload_doc("accounts", "doctype", "payment_ledger_entry"): @@ -34,6 +57,8 @@ def execute(): .run(as_dict=True) ) + pl_entries = remove_duplicate_entries(pl_entries) + if pl_entries: # split into multiple batches, update and commit for each batch batch_size = 1000 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..dd957c72ac 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); @@ -1401,7 +1404,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe if (!r.exc && r.message) { me._set_values_for_item_list(r.message); if(item) me.set_gross_profit(item); - if(me.frm.doc.apply_discount_on) me.frm.trigger("apply_discount_on") + if (me.frm.doc.apply_discount_on) me.frm.trigger("apply_discount_on") } } }); @@ -1574,6 +1577,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe for (let key in pr_row) { row_to_modify[key] = pr_row[key]; } + this.frm.script_manager.copy_from_first_row("items", row_to_modify, ["expense_account", "income_account"]); }); // free_item_data is a temporary variable 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/public/js/utils/party.js b/erpnext/public/js/utils/party.js index 58594b0a13..644adff1e2 100644 --- a/erpnext/public/js/utils/party.js +++ b/erpnext/public/js/utils/party.js @@ -242,20 +242,29 @@ erpnext.utils.set_taxes = function(frm, triggered_from_field) { }); }; -erpnext.utils.get_contact_details = function(frm) { +erpnext.utils.get_contact_details = function (frm) { if (frm.updating_party_details) return; if (frm.doc["contact_person"]) { frappe.call({ method: "frappe.contacts.doctype.contact.contact.get_contact_details", - args: {contact: frm.doc.contact_person }, - callback: function(r) { - if (r.message) - frm.set_value(r.message); - } - }) + args: { contact: frm.doc.contact_person }, + callback: function (r) { + if (r.message) frm.set_value(r.message); + }, + }); + } else { + frm.set_value({ + contact_person: "", + contact_display: "", + contact_email: "", + contact_mobile: "", + contact_phone: "", + contact_designation: "", + contact_department: "", + }); } -} +}; erpnext.utils.validate_mandatory = function(frm, label, value, trigger_on) { if (!value) { diff --git a/erpnext/public/scss/order-page.scss b/erpnext/public/scss/order-page.scss new file mode 100644 index 0000000000..6f5fe5d4d7 --- /dev/null +++ b/erpnext/public/scss/order-page.scss @@ -0,0 +1,115 @@ +#page-order { + .main-column { + .page-content-wrapper { + + .breadcrumb-container { + @media screen and (min-width: 567px) { + padding-left: var(--padding-sm); + } + } + + .container.my-4 { + background-color: var(--fg-color); + + @media screen and (min-width: 567px) { + padding: 1.25rem 1.5rem; + border-radius: var(--border-radius-md); + box-shadow: var(--card-shadow); + } + } + } + } +} + +.indicator-container { + @media screen and (max-width: 567px) { + padding-bottom: 0.8rem; + } +} + +.order-items { + padding: 1.5rem 0; + border-bottom: 1px solid var(--border-color); + color: var(--gray-700); + + @media screen and (max-width: 567px) { + align-items: flex-start !important; + } + .col-2 { + @media screen and (max-width: 567px) { + flex: auto; + max-width: 28%; + } + } + + .order-item-name { + font-size: var(--text-base); + font-weight: 500; + } + + .btn:focus, + .btn:hover { + background-color: var(--control-bg); + } + + + .col-6 { + @media screen and (max-width: 567px) { + max-width: 100%; + } + + &.order-item-name { + font-size: var(--text-base); + } + } +} + +.item-grand-total { + font-size: var(--text-base); +} + +.list-item-name, +.item-total, +.order-container, +.order-qty { + font-size: var(--text-md); +} + +.d-s-n { + @media screen and (max-width: 567px) { + display: none; + } +} + +.d-l-n { + @media screen and (min-width: 567px) { + display: none; + } +} + +.border-btm { + border-bottom: 1px solid var(--border-color); +} + +.order-taxes { + display: flex; + + @media screen and (min-width: 567px) { + justify-content: flex-end; + } + + .col-4 { + padding-right: 0; + + .col-8 { + padding-left: 0; + padding-right: 0; + } + + @media screen and (max-width: 567px) { + padding-left: 0; + flex: auto; + max-width: 100%; + } + } +} \ No newline at end of file diff --git a/erpnext/public/scss/website.scss b/erpnext/public/scss/website.scss index 9ea8416034..b5e97f1c34 100644 --- a/erpnext/public/scss/website.scss +++ b/erpnext/public/scss/website.scss @@ -1,3 +1,4 @@ +@import './order-page'; .filter-options { max-height: 300px; @@ -32,19 +33,29 @@ height: 24px; } -.website-list .result { - margin-top: 2rem; -} +.website-list { + background-color: var(--fg-color); + padding: 0 var(--padding-lg); + border-radius: var(--border-radius-md); -.result { - border-bottom: 1px solid var(--border-color); + @media screen and (max-width: 567px) { + margin-left: -2rem; + } + + &.result { + border-bottom: 1px solid var(--border-color); + } } .transaction-list-item { padding: 1rem 0; - border-top: 1px solid var(--border-color); + border-bottom: 1px solid var(--border-color); position: relative; + &:only-child, &:last-child { + border: 0; + } + a.transaction-item-link { position: absolute; top: 0; @@ -68,3 +79,13 @@ line-height: 1.3; } } + +.list-item-name, .item-total { + font-size: var(--font-size-sm); +} + +.items-preview { + @media screen and (max-width: 567px) { + margin-top: 1rem; + } +} \ No newline at end of file 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/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py index 7dc3fab623..691adccd4d 100644 --- a/erpnext/selling/doctype/customer/test_customer.py +++ b/erpnext/selling/doctype/customer/test_customer.py @@ -3,6 +3,7 @@ import frappe +from frappe.custom.doctype.property_setter.property_setter import make_property_setter from frappe.test_runner import make_test_records from frappe.tests.utils import FrappeTestCase from frappe.utils import flt @@ -341,6 +342,33 @@ class TestCustomer(FrappeTestCase): due_date = get_due_date("2017-01-22", "Customer", "_Test Customer") self.assertEqual(due_date, "2017-01-22") + def test_serach_fields_for_customer(self): + from erpnext.controllers.queries import customer_query + + make_property_setter( + "Customer", None, "search_fields", "customer_group", "Data", for_doctype="Doctype" + ) + + data = customer_query( + "Customer", "_Test Customer", "", 0, 20, filters={"name": "_Test Customer"}, as_dict=True + ) + + self.assertEqual(data[0].name, "_Test Customer") + self.assertEqual(data[0].customer_group, "_Test Customer Group") + self.assertTrue("territory" not in data[0]) + + make_property_setter( + "Customer", None, "search_fields", "customer_group, territory", "Data", for_doctype="Doctype" + ) + data = customer_query( + "Customer", "_Test Customer", "", 0, 20, filters={"name": "_Test Customer"}, as_dict=True + ) + + self.assertEqual(data[0].name, "_Test Customer") + self.assertEqual(data[0].customer_group, "_Test Customer Group") + self.assertEqual(data[0].territory, "_Test Territory") + self.assertTrue("territory" in data[0]) + def get_customer_dict(customer_name): return { 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.js b/erpnext/selling/doctype/sales_order/sales_order.js index 386c12b638..fb64772479 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -124,6 +124,11 @@ frappe.ui.form.on("Sales Order", { return query; }); + // On cancel and amending a sales order with advance payment, reset advance paid amount + if (frm.is_new()) { + frm.set_value("advance_paid", 0) + } + frm.ignore_doctypes_on_cancel_all = ['Purchase Order']; }, 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..1f3419fd5d 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, @@ -626,6 +627,7 @@ def make_project(source_name, target_doc=None): "field_map": { "name": "sales_order", "base_grand_total": "estimated_costing", + "net_total": "total_sales_amount", }, }, }, @@ -727,6 +729,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/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index 2cf836f9fc..ea0b25f41c 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -272,6 +272,7 @@ }, { "collapsible": 1, + "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount", "fieldname": "discount_and_margin", "fieldtype": "Section Break", "label": "Discount and Margin" @@ -842,7 +843,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2022-09-06 13:24:18.065312", + "modified": "2022-10-26 16:05:02.712705", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", diff --git a/erpnext/selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.js b/erpnext/selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.js index c068ae3b5a..991ac719cd 100644 --- a/erpnext/selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.js +++ b/erpnext/selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.js @@ -74,7 +74,35 @@ function get_filters() { ] } } - } + }, + { + "fieldname":"from_due_date", + "label": __("From Due Date"), + "fieldtype": "Date", + }, + { + "fieldname":"to_due_date", + "label": __("To Due Date"), + "fieldtype": "Date", + }, + { + "fieldname":"status", + "label": __("Status"), + "fieldtype": "MultiSelectList", + "width": 100, + get_data: function(txt) { + let status = ["Overdue", "Unpaid", "Completed", "Partly Paid"] + let options = [] + for (let option of status){ + options.push({ + "value": option, + "label": __(option), + "description": "" + }) + } + return options + } + }, ] return filters; } diff --git a/erpnext/selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.py b/erpnext/selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.py index 91f4a5e50a..8bf56865a7 100644 --- a/erpnext/selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.py +++ b/erpnext/selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.py @@ -162,6 +162,12 @@ def build_filter_criterions(filters): if filters.item: qb_criterions.append(qb.DocType("Sales Order Item").item_code == filters.item) + if filters.from_due_date: + qb_criterions.append(qb.DocType("Payment Schedule").due_date.gte(filters.from_due_date)) + + if filters.to_due_date: + qb_criterions.append(qb.DocType("Payment Schedule").due_date.lte(filters.to_due_date)) + return qb_criterions @@ -279,11 +285,19 @@ def prepare_chart(s_orders): return chart +def filter_on_calculated_status(filters, sales_orders): + if filters.status and sales_orders: + return [x for x in sales_orders if x.status in filters.status] + return sales_orders + + def execute(filters=None): columns = get_columns() sales_orders, so_invoices = get_so_with_invoices(filters) sales_orders, so_invoices = set_payment_terms_statuses(sales_orders, so_invoices, filters) + sales_orders = filter_on_calculated_status(filters, sales_orders) + prepare_chart(sales_orders) data = sales_orders diff --git a/erpnext/selling/report/payment_terms_status_for_sales_order/test_payment_terms_status_for_sales_order.py b/erpnext/selling/report/payment_terms_status_for_sales_order/test_payment_terms_status_for_sales_order.py index 9d542f5079..525ae8e7ea 100644 --- a/erpnext/selling/report/payment_terms_status_for_sales_order/test_payment_terms_status_for_sales_order.py +++ b/erpnext/selling/report/payment_terms_status_for_sales_order/test_payment_terms_status_for_sales_order.py @@ -2,7 +2,7 @@ import datetime import frappe from frappe.tests.utils import FrappeTestCase -from frappe.utils import add_days +from frappe.utils import add_days, nowdate from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order @@ -77,12 +77,14 @@ class TestPaymentTermsStatusForSalesOrder(FrappeTestCase): sinv.insert() sinv.submit() columns, data, message, chart = execute( - { - "company": "_Test Company", - "period_start_date": "2021-06-01", - "period_end_date": "2021-06-30", - "item": item.item_code, - } + frappe._dict( + { + "company": "_Test Company", + "period_start_date": "2021-06-01", + "period_end_date": "2021-06-30", + "item": item.item_code, + } + ) ) expected_value = [ @@ -167,12 +169,14 @@ class TestPaymentTermsStatusForSalesOrder(FrappeTestCase): sinv.insert() sinv.submit() columns, data, message, chart = execute( - { - "company": "_Test Company", - "period_start_date": "2021-06-01", - "period_end_date": "2021-06-30", - "item": item.item_code, - } + frappe._dict( + { + "company": "_Test Company", + "period_start_date": "2021-06-01", + "period_end_date": "2021-06-30", + "item": item.item_code, + } + ) ) # report defaults to company currency. @@ -338,3 +342,60 @@ class TestPaymentTermsStatusForSalesOrder(FrappeTestCase): with self.subTest(filters=filters): columns, data, message, chart = execute(filters) self.assertEqual(data, expected_values_for_group_filters[idx]) + + def test_04_due_date_filter(self): + self.create_payment_terms_template() + item = create_item(item_code="_Test Excavator 1", is_stock_item=0) + transaction_date = nowdate() + so = make_sales_order( + transaction_date=add_days(transaction_date, -30), + delivery_date=add_days(transaction_date, -15), + item=item.item_code, + qty=10, + rate=100000, + do_not_save=True, + ) + so.po_no = "" + so.taxes_and_charges = "" + so.taxes = "" + so.payment_terms_template = self.template.name + so.save() + so.submit() + + # make invoice with 60% of the total sales order value + sinv = make_sales_invoice(so.name) + sinv.taxes_and_charges = "" + sinv.taxes = "" + sinv.items[0].qty = 6 + sinv.insert() + sinv.submit() + columns, data, message, chart = execute( + frappe._dict( + { + "company": "_Test Company", + "item": item.item_code, + "from_due_date": add_days(transaction_date, -30), + "to_due_date": add_days(transaction_date, -15), + } + ) + ) + + expected_value = [ + { + "name": so.name, + "customer": so.customer, + "submitted": datetime.date.fromisoformat(add_days(transaction_date, -30)), + "status": "Completed", + "payment_term": None, + "description": "_Test 50-50", + "due_date": datetime.date.fromisoformat(add_days(transaction_date, -15)), + "invoice_portion": 50.0, + "currency": "INR", + "base_payment_amount": 500000.0, + "paid_amount": 500000.0, + "invoices": "," + sinv.name, + }, + ] + # Only the first term should be pulled + self.assertEqual(len(data), 1) + self.assertEqual(data, expected_value) 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/bin/bin.py b/erpnext/stock/doctype/bin/bin.py index 548df318fa..c28f45aed4 100644 --- a/erpnext/stock/doctype/bin/bin.py +++ b/erpnext/stock/doctype/bin/bin.py @@ -37,8 +37,10 @@ class Bin(Document): self.set_projected_qty() - self.db_set("reserved_qty_for_production", flt(self.reserved_qty_for_production)) - self.db_set("projected_qty", self.projected_qty) + self.db_set( + "reserved_qty_for_production", flt(self.reserved_qty_for_production), update_modified=True + ) + self.db_set("projected_qty", self.projected_qty, update_modified=True) def update_reserved_qty_for_sub_contracting(self, subcontract_doctype="Subcontracting Order"): # reserved qty @@ -118,9 +120,9 @@ class Bin(Document): else: reserved_qty_for_sub_contract = 0 - self.db_set("reserved_qty_for_sub_contract", reserved_qty_for_sub_contract) + self.db_set("reserved_qty_for_sub_contract", reserved_qty_for_sub_contract, update_modified=True) self.set_projected_qty() - self.db_set("projected_qty", self.projected_qty) + self.db_set("projected_qty", self.projected_qty, update_modified=True) def on_doctype_update(): @@ -193,4 +195,5 @@ def update_qty(bin_name, args): "planned_qty": planned_qty, "projected_qty": projected_qty, }, + update_modified=True, ) 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..77c3253432 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -261,6 +261,7 @@ }, { "collapsible": 1, + "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount", "fieldname": "discount_and_margin", "fieldtype": "Section Break", "label": "Discount and Margin" @@ -753,6 +754,7 @@ "fieldtype": "Currency", "label": "Incoming Rate", "no_copy": 1, + "precision": "6", "print_hide": 1, "read_only": 1 }, @@ -813,7 +815,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2022-09-06 14:19:42.876357", + "modified": "2022-10-26 16:05:17.720768", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", diff --git a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py index 9e8c10b394..7b99b0097b 100644 --- a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py +++ b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py @@ -121,18 +121,24 @@ class InventoryDimension(Document): if self.apply_to_all_doctypes: for doctype in get_inventory_documents(): - custom_fields.setdefault(doctype[0], dimension_fields) - else: + if not field_exists(doctype[0], self.source_fieldname): + custom_fields.setdefault(doctype[0], dimension_fields) + elif not field_exists(self.document_type, self.source_fieldname): custom_fields.setdefault(self.document_type, dimension_fields) if not frappe.db.get_value( "Custom Field", {"dt": "Stock Ledger Entry", "fieldname": self.target_fieldname} - ): + ) and not field_exists("Stock Ledger Entry", self.target_fieldname): dimension_field = dimension_fields[1] dimension_field["fieldname"] = self.target_fieldname custom_fields["Stock Ledger Entry"] = dimension_field - create_custom_fields(custom_fields) + if custom_fields: + create_custom_fields(custom_fields) + + +def field_exists(doctype, fieldname) -> str or None: + return frappe.db.get_value("DocField", {"parent": doctype, "fieldname": fieldname}, "name") @frappe.whitelist() diff --git a/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py b/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py index 19ddc449f0..52b3deb3f0 100644 --- a/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py +++ b/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py @@ -191,6 +191,21 @@ class TestInventoryDimension(FrappeTestCase): self.assertEqual(sle_rack, "Rack 1") + def test_check_standard_dimensions(self): + create_inventory_dimension( + reference_document="Project", + type_of_transaction="Outward", + dimension_name="Project", + apply_to_all_doctypes=0, + document_type="Stock Ledger Entry", + ) + + self.assertFalse( + frappe.db.get_value( + "Custom Field", {"fieldname": "project", "dt": "Stock Ledger Entry"}, "name" + ) + ) + def prepare_test_data(): if not frappe.db.exists("DocType", "Shelf"): 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/material_request/material_request_dashboard.py b/erpnext/stock/doctype/material_request/material_request_dashboard.py index b073e6a22e..691a8b39b1 100644 --- a/erpnext/stock/doctype/material_request/material_request_dashboard.py +++ b/erpnext/stock/doctype/material_request/material_request_dashboard.py @@ -4,10 +4,13 @@ from frappe import _ def get_data(): return { "fieldname": "material_request", + "internal_links": { + "Sales Order": ["items", "sales_order"], + }, "transactions": [ { "label": _("Reference"), - "items": ["Request for Quotation", "Supplier Quotation", "Purchase Order"], + "items": ["Sales Order", "Request for Quotation", "Supplier Quotation", "Purchase Order"], }, {"label": _("Stock"), "items": ["Stock Entry", "Purchase Receipt", "Pick List"]}, {"label": _("Manufacturing"), "items": ["Work Order"]}, diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py index 78af1532ea..f02462c596 100644 --- a/erpnext/stock/doctype/material_request/test_material_request.py +++ b/erpnext/stock/doctype/material_request/test_material_request.py @@ -590,6 +590,7 @@ class TestMaterialRequest(FrappeTestCase): mr = frappe.copy_doc(test_records[0]) mr.material_request_type = "Material Issue" mr.submit() + frappe.db.value_cache = {} # testing bin value after material request is submitted self.assertEqual(_get_requested_qty(), existing_requested_qty - 54.0) 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/purchase_receipt_dashboard.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_dashboard.py index 06ba936556..b3ae7b58b4 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_dashboard.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_dashboard.py @@ -12,13 +12,17 @@ def get_data(): "Purchase Receipt": "return_against", }, "internal_links": { + "Material Request": ["items", "material_request"], "Purchase Order": ["items", "purchase_order"], "Project": ["items", "project"], "Quality Inspection": ["items", "quality_inspection"], }, "transactions": [ {"label": _("Related"), "items": ["Purchase Invoice", "Landed Cost Voucher", "Asset"]}, - {"label": _("Reference"), "items": ["Purchase Order", "Quality Inspection", "Project"]}, + { + "label": _("Reference"), + "items": ["Material Request", "Purchase Order", "Quality Inspection", "Project"], + }, {"label": _("Returns"), "items": ["Purchase Receipt"]}, {"label": _("Subscription"), "items": ["Auto Repeat"]}, ], 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..474ee92e26 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, @@ -918,6 +919,7 @@ }, { "collapsible": 1, + "collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount", "fieldname": "discount_and_margin_section", "fieldtype": "Section Break", "label": "Discount and Margin" @@ -999,7 +1001,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2022-07-28 19:27:54.880781", + "modified": "2022-10-26 16:06:02.524435", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt Item", diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.json b/erpnext/stock/doctype/quality_inspection/quality_inspection.json index edfe7e98b2..db9322f326 100644 --- a/erpnext/stock/doctype/quality_inspection/quality_inspection.json +++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.json @@ -10,6 +10,7 @@ "naming_series", "report_date", "status", + "manual_inspection", "column_break_4", "inspection_type", "reference_type", @@ -231,6 +232,12 @@ "label": "Status", "options": "\nAccepted\nRejected", "reqd": 1 + }, + { + "default": "0", + "fieldname": "manual_inspection", + "fieldtype": "Check", + "label": "Manual Inspection" } ], "icon": "fa fa-search", @@ -238,10 +245,11 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2020-12-18 19:59:55.710300", + "modified": "2022-10-04 22:00:13.995221", "modified_by": "Administrator", "module": "Stock", "name": "Quality Inspection", + "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ { @@ -262,5 +270,6 @@ "search_fields": "item_code, report_date, reference_name", "show_name_in_global_search": 1, "sort_field": "modified", - "sort_order": "ASC" + "sort_order": "ASC", + "states": [] } \ No newline at end of file diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.py b/erpnext/stock/doctype/quality_inspection/quality_inspection.py index 13abfad455..8ffd3f2ad1 100644 --- a/erpnext/stock/doctype/quality_inspection/quality_inspection.py +++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.py @@ -30,6 +30,9 @@ class QualityInspection(Document): if self.readings: self.inspect_and_set_status() + def before_submit(self): + self.validate_readings_status_mandatory() + @frappe.whitelist() def get_item_specification_details(self): if not self.quality_inspection_template: @@ -65,6 +68,11 @@ class QualityInspection(Document): def on_cancel(self): self.update_qc_reference() + def validate_readings_status_mandatory(self): + for reading in self.readings: + if not reading.status: + frappe.throw(_("Row #{0}: Status is mandatory").format(reading.idx)) + def update_qc_reference(self): quality_inspection = self.name if self.docstatus == 1 else "" @@ -124,6 +132,16 @@ class QualityInspection(Document): # if not formula based check acceptance values set self.set_status_based_on_acceptance_values(reading) + if not self.manual_inspection: + self.status = "Accepted" + for reading in self.readings: + if reading.status == "Rejected": + self.status = "Rejected" + frappe.msgprint( + _("Status set to rejected as there are one or more rejected readings."), alert=True + ) + break + def set_status_based_on_acceptance_values(self, reading): if not cint(reading.numeric): result = reading.get("reading_value") == reading.get("value") diff --git a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py index 144f13880b..4f19643ad5 100644 --- a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py +++ b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py @@ -160,7 +160,7 @@ class TestQualityInspection(FrappeTestCase): ) readings = [ - {"specification": "Iron Content", "min_value": 0.1, "max_value": 0.9, "reading_1": "0.4"} + {"specification": "Iron Content", "min_value": 0.1, "max_value": 0.9, "reading_1": "1.0"} ] qa = create_quality_inspection( @@ -184,6 +184,38 @@ class TestQualityInspection(FrappeTestCase): se.cancel() frappe.db.set_value("Stock Settings", None, "action_if_quality_inspection_is_rejected", "Stop") + def test_qi_status(self): + make_stock_entry( + item_code="_Test Item with QA", target="_Test Warehouse - _TC", qty=1, basic_rate=100 + ) + dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True) + qa = create_quality_inspection( + reference_type="Delivery Note", reference_name=dn.name, status="Accepted", do_not_save=True + ) + qa.readings[0].manual_inspection = 1 + qa.save() + + # Case - 1: When there are one or more readings with rejected status and parent manual inspection is unchecked, then parent status should be set to rejected. + qa.status = "Accepted" + qa.manual_inspection = 0 + qa.readings[0].status = "Rejected" + qa.save() + self.assertEqual(qa.status, "Rejected") + + # Case - 2: When all readings have accepted status and parent manual inspection is unchecked, then parent status should be set to accepted. + qa.status = "Rejected" + qa.manual_inspection = 0 + qa.readings[0].status = "Accepted" + qa.save() + self.assertEqual(qa.status, "Accepted") + + # Case - 3: When parent manual inspection is checked, then parent status should not be changed. + qa.status = "Accepted" + qa.manual_inspection = 1 + qa.readings[0].status = "Rejected" + qa.save() + self.assertEqual(qa.status, "Accepted") + def create_quality_inspection(**args): args = frappe._dict(args) diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py index c4705246b3..d6f9bae5da 100644 --- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py +++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py @@ -128,6 +128,9 @@ def repost(doc): if not frappe.db.exists("Repost Item Valuation", doc.name): return + # This is to avoid TooManyWritesError in case of large reposts + frappe.db.MAX_WRITES_PER_TRANSACTION *= 4 + doc.set_status("In Progress") if not frappe.flags.in_test: frappe.db.commit() 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_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json index abe98e2933..7e9420d503 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.json +++ b/erpnext/stock/doctype/stock_entry/stock_entry.json @@ -148,19 +148,19 @@ "search_index": 1 }, { - "depends_on": "eval:doc.purpose==\"Send to Subcontractor\"", - "fieldname": "purchase_order", - "fieldtype": "Link", - "label": "Purchase Order", - "options": "Purchase Order" + "depends_on": "eval:doc.purpose==\"Send to Subcontractor\"", + "fieldname": "purchase_order", + "fieldtype": "Link", + "label": "Purchase Order", + "options": "Purchase Order" }, { - "depends_on": "eval:doc.purpose==\"Send to Subcontractor\"", - "fieldname": "subcontracting_order", - "fieldtype": "Link", - "label": "Subcontracting Order", - "options": "Subcontracting Order" - }, + "depends_on": "eval:doc.purpose==\"Send to Subcontractor\"", + "fieldname": "subcontracting_order", + "fieldtype": "Link", + "label": "Subcontracting Order", + "options": "Subcontracting Order" + }, { "depends_on": "eval:doc.purpose==\"Sales Return\"", "fieldname": "delivery_note_no", @@ -616,6 +616,7 @@ "fieldname": "is_return", "fieldtype": "Check", "hidden": 1, + "in_list_view": 1, "label": "Is Return", "no_copy": 1, "print_hide": 1, @@ -627,7 +628,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2022-05-02 05:21:39.060501", + "modified": "2022-10-07 14:39:51.943770", "modified_by": "Administrator", "module": "Stock", "name": "Stock Entry", diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 8bcd772d90..b1167351c4 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -1212,13 +1212,19 @@ class StockEntry(StockController): def update_work_order(self): def _validate_work_order(pro_doc): + msg, title = "", "" if flt(pro_doc.docstatus) != 1: - frappe.throw(_("Work Order {0} must be submitted").format(self.work_order)) + msg = f"Work Order {self.work_order} must be submitted" if pro_doc.status == "Stopped": - frappe.throw( - _("Transaction not allowed against stopped Work Order {0}").format(self.work_order) - ) + msg = f"Transaction not allowed against stopped Work Order {self.work_order}" + + if self.is_return and pro_doc.status not in ["Completed", "Closed"]: + title = _("Stock Return") + msg = f"Work Order {self.work_order} must be completed or closed" + + if msg: + frappe.throw(_(msg), title=title) if self.job_card: job_doc = frappe.get_doc("Job Card", self.job_card) @@ -1754,10 +1760,12 @@ class StockEntry(StockController): for key, row in available_materials.items(): remaining_qty_to_produce = flt(wo_data.trans_qty) - flt(wo_data.produced_qty) - if remaining_qty_to_produce <= 0: + if remaining_qty_to_produce <= 0 and not self.is_return: continue - qty = (flt(row.qty) * flt(self.fg_completed_qty)) / remaining_qty_to_produce + qty = flt(row.qty) + if not self.is_return: + qty = (flt(row.qty) * flt(self.fg_completed_qty)) / remaining_qty_to_produce item = row.item_details if cint(frappe.get_cached_value("UOM", item.stock_uom, "must_be_whole_number")): @@ -1781,6 +1789,9 @@ class StockEntry(StockController): self.update_item_in_stock_entry_detail(row, item, qty) def update_item_in_stock_entry_detail(self, row, item, qty) -> None: + if not qty: + return + ste_item_details = { "from_warehouse": item.warehouse, "to_warehouse": "", @@ -1794,6 +1805,9 @@ class StockEntry(StockController): "original_item": item.original_item, } + if self.is_return: + ste_item_details["to_warehouse"] = item.s_warehouse + if row.serial_nos: serial_nos = row.serial_nos if item.batch_no: diff --git a/erpnext/stock/doctype/stock_entry/stock_entry_list.js b/erpnext/stock/doctype/stock_entry/stock_entry_list.js index cbc3491eba..4eb0da11d2 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry_list.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry_list.js @@ -1,8 +1,13 @@ frappe.listview_settings['Stock Entry'] = { add_fields: ["`tabStock Entry`.`from_warehouse`", "`tabStock Entry`.`to_warehouse`", - "`tabStock Entry`.`purpose`", "`tabStock Entry`.`work_order`", "`tabStock Entry`.`bom_no`"], + "`tabStock Entry`.`purpose`", "`tabStock Entry`.`work_order`", "`tabStock Entry`.`bom_no`", + "`tabStock Entry`.`is_return`"], get_indicator: function (doc) { - if (doc.docstatus === 0) { + debugger + if(doc.is_return===1 && doc.purpose === "Material Transfer for Manufacture") { + return [__("Material Returned from WIP"), "orange", + "is_return,=,1|purpose,=,Material Transfer for Manufacture|docstatus,<,2"]; + } else if (doc.docstatus === 0) { return [__("Draft"), "red", "docstatus,=,0"]; } else if (doc.purpose === 'Send to Warehouse' && doc.per_transferred < 100) { 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/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py index f308e9e41f..a6fc049cbd 100644 --- a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py +++ b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py @@ -3,6 +3,7 @@ import frappe from frappe import _ +from frappe.query_builder.functions import Abs, Sum from frappe.utils import flt, getdate @@ -11,8 +12,6 @@ def execute(filters=None): filters = {} float_precision = frappe.db.get_default("float_precision") - condition = get_condition(filters) - avg_daily_outgoing = 0 diff = ((getdate(filters.get("to_date")) - getdate(filters.get("from_date"))).days) + 1 if diff <= 0: @@ -20,8 +19,8 @@ def execute(filters=None): columns = get_columns() items = get_item_info(filters) - consumed_item_map = get_consumed_items(condition) - delivered_item_map = get_delivered_items(condition) + consumed_item_map = get_consumed_items(filters) + delivered_item_map = get_delivered_items(filters) data = [] for item in items: @@ -71,76 +70,86 @@ def get_columns(): def get_item_info(filters): from erpnext.stock.report.stock_ledger.stock_ledger import get_item_group_condition - conditions = [get_item_group_condition(filters.get("item_group"))] - if filters.get("brand"): - conditions.append("item.brand=%(brand)s") - conditions.append("is_stock_item = 1") - - return frappe.db.sql( - """select name, item_name, description, brand, item_group, - safety_stock, lead_time_days from `tabItem` item where {}""".format( - " and ".join(conditions) - ), - filters, - as_dict=1, + item = frappe.qb.DocType("Item") + query = ( + frappe.qb.from_(item) + .select( + item.name, + item.item_name, + item.description, + item.brand, + item.item_group, + item.safety_stock, + item.lead_time_days, + ) + .where(item.is_stock_item == 1) ) + if brand := filters.get("brand"): + query = query.where(item.brand == brand) -def get_consumed_items(condition): + if conditions := get_item_group_condition(filters.get("item_group"), item): + query = query.where(conditions) + + return query.run(as_dict=True) + + +def get_consumed_items(filters): purpose_to_exclude = [ "Material Transfer for Manufacture", "Material Transfer", "Send to Subcontractor", ] - condition += """ - and ( - purpose is NULL - or purpose not in ({}) + se = frappe.qb.DocType("Stock Entry") + sle = frappe.qb.DocType("Stock Ledger Entry") + query = ( + frappe.qb.from_(sle) + .left_join(se) + .on(sle.voucher_no == se.name) + .select(sle.item_code, Abs(Sum(sle.actual_qty)).as_("consumed_qty")) + .where( + (sle.actual_qty < 0) + & (sle.is_cancelled == 0) + & (sle.voucher_type.notin(["Delivery Note", "Sales Invoice"])) + & ((se.purpose.isnull()) | (se.purpose.notin(purpose_to_exclude))) ) - """.format( - ", ".join(f"'{p}'" for p in purpose_to_exclude) + .groupby(sle.item_code) ) - condition = condition.replace("posting_date", "sle.posting_date") + query = get_filtered_query(filters, sle, query) - consumed_items = frappe.db.sql( - """ - select item_code, abs(sum(actual_qty)) as consumed_qty - from `tabStock Ledger Entry` as sle left join `tabStock Entry` as se - on sle.voucher_no = se.name - where - actual_qty < 0 - and is_cancelled = 0 - and voucher_type not in ('Delivery Note', 'Sales Invoice') - %s - group by item_code""" - % condition, - as_dict=1, - ) + consumed_items = query.run(as_dict=True) consumed_items_map = {item.item_code: item.consumed_qty for item in consumed_items} return consumed_items_map -def get_delivered_items(condition): - dn_items = frappe.db.sql( - """select dn_item.item_code, sum(dn_item.stock_qty) as dn_qty - from `tabDelivery Note` dn, `tabDelivery Note Item` dn_item - where dn.name = dn_item.parent and dn.docstatus = 1 %s - group by dn_item.item_code""" - % (condition), - as_dict=1, +def get_delivered_items(filters): + parent = frappe.qb.DocType("Delivery Note") + child = frappe.qb.DocType("Delivery Note Item") + query = ( + frappe.qb.from_(parent) + .from_(child) + .select(child.item_code, Sum(child.stock_qty).as_("dn_qty")) + .where((parent.name == child.parent) & (parent.docstatus == 1)) + .groupby(child.item_code) ) + query = get_filtered_query(filters, parent, query) - si_items = frappe.db.sql( - """select si_item.item_code, sum(si_item.stock_qty) as si_qty - from `tabSales Invoice` si, `tabSales Invoice Item` si_item - where si.name = si_item.parent and si.docstatus = 1 and - si.update_stock = 1 %s - group by si_item.item_code""" - % (condition), - as_dict=1, + dn_items = query.run(as_dict=True) + + parent = frappe.qb.DocType("Sales Invoice") + child = frappe.qb.DocType("Sales Invoice Item") + query = ( + frappe.qb.from_(parent) + .from_(child) + .select(child.item_code, Sum(child.stock_qty).as_("si_qty")) + .where((parent.name == child.parent) & (parent.docstatus == 1) & (parent.update_stock == 1)) + .groupby(child.item_code) ) + query = get_filtered_query(filters, parent, query) + + si_items = query.run(as_dict=True) dn_item_map = {} for item in dn_items: @@ -152,13 +161,10 @@ def get_delivered_items(condition): return dn_item_map -def get_condition(filters): - conditions = "" +def get_filtered_query(filters, table, query): if filters.get("from_date") and filters.get("to_date"): - conditions += " and posting_date between '%s' and '%s'" % ( - filters["from_date"], - filters["to_date"], - ) + query = query.where(table.posting_date.between(filters["from_date"], filters["to_date"])) else: - frappe.throw(_("From and To dates required")) - return conditions + frappe.throw(_("From and To dates are required")) + + return query diff --git a/erpnext/stock/report/product_bundle_balance/product_bundle_balance.py b/erpnext/stock/report/product_bundle_balance/product_bundle_balance.py index 854875a053..9e75201bd1 100644 --- a/erpnext/stock/report/product_bundle_balance/product_bundle_balance.py +++ b/erpnext/stock/report/product_bundle_balance/product_bundle_balance.py @@ -4,7 +4,9 @@ import frappe from frappe import _ +from frappe.query_builder.functions import IfNull from frappe.utils import flt +from pypika.terms import ExistsCriterion from erpnext.stock.report.stock_ledger.stock_ledger import get_item_group_condition @@ -123,43 +125,65 @@ def get_items(filters): pb_details = frappe._dict() item_details = frappe._dict() - conditions = get_parent_item_conditions(filters) - parent_item_details = frappe.db.sql( - """ - select item.name as item_code, item.item_name, pb.description, item.item_group, item.brand, item.stock_uom - from `tabItem` item - inner join `tabProduct Bundle` pb on pb.new_item_code = item.name - where ifnull(item.disabled, 0) = 0 {0} - """.format( - conditions - ), - filters, - as_dict=1, - ) # nosec + item = frappe.qb.DocType("Item") + pb = frappe.qb.DocType("Product Bundle") + + query = ( + frappe.qb.from_(item) + .inner_join(pb) + .on(pb.new_item_code == item.name) + .select( + item.name.as_("item_code"), + item.item_name, + pb.description, + item.item_group, + item.brand, + item.stock_uom, + ) + .where(IfNull(item.disabled, 0) == 0) + ) + + if item_code := filters.get("item_code"): + query = query.where(item.item_code == item_code) + else: + if brand := filters.get("brand"): + query = query.where(item.brand == brand) + if item_group := filters.get("item_group"): + if conditions := get_item_group_condition(item_group, item): + query = query.where(conditions) + + parent_item_details = query.run(as_dict=True) parent_items = [] for d in parent_item_details: parent_items.append(d.item_code) item_details[d.item_code] = d + child_item_details = [] if parent_items: - child_item_details = frappe.db.sql( - """ - select - pb.new_item_code as parent_item, pbi.item_code, item.item_name, pbi.description, item.item_group, item.brand, - item.stock_uom, pbi.uom, pbi.qty - from `tabProduct Bundle Item` pbi - inner join `tabProduct Bundle` pb on pb.name = pbi.parent - inner join `tabItem` item on item.name = pbi.item_code - where pb.new_item_code in ({0}) - """.format( - ", ".join(["%s"] * len(parent_items)) - ), - parent_items, - as_dict=1, - ) # nosec - else: - child_item_details = [] + item = frappe.qb.DocType("Item") + pb = frappe.qb.DocType("Product Bundle") + pbi = frappe.qb.DocType("Product Bundle Item") + + child_item_details = ( + frappe.qb.from_(pbi) + .inner_join(pb) + .on(pb.name == pbi.parent) + .inner_join(item) + .on(item.name == pbi.item_code) + .select( + pb.new_item_code.as_("parent_item"), + pbi.item_code, + item.item_name, + pbi.description, + item.item_group, + item.brand, + item.stock_uom, + pbi.uom, + pbi.qty, + ) + .where(pb.new_item_code.isin(parent_items)) + ).run(as_dict=1) child_items = set() for d in child_item_details: @@ -184,58 +208,42 @@ def get_stock_ledger_entries(filters, items): if not items: return [] - item_conditions_sql = " and sle.item_code in ({})".format( - ", ".join(frappe.db.escape(i) for i in items) + sle = frappe.qb.DocType("Stock Ledger Entry") + sle2 = frappe.qb.DocType("Stock Ledger Entry") + + query = ( + frappe.qb.from_(sle) + .force_index("posting_sort_index") + .left_join(sle2) + .on( + (sle.item_code == sle2.item_code) + & (sle.warehouse == sle2.warehouse) + & (sle.posting_date < sle2.posting_date) + & (sle.posting_time < sle2.posting_time) + & (sle.name < sle2.name) + ) + .select(sle.item_code, sle.warehouse, sle.qty_after_transaction, sle.company) + .where((sle2.name.isnull()) & (sle.docstatus < 2) & (sle.item_code.isin(items))) ) - conditions = get_sle_conditions(filters) - - return frappe.db.sql( - """ - select - sle.item_code, sle.warehouse, sle.qty_after_transaction, sle.company - from - `tabStock Ledger Entry` sle force index (posting_sort_index) - left join `tabStock Ledger Entry` sle2 on - sle.item_code = sle2.item_code and sle.warehouse = sle2.warehouse - and (sle.posting_date, sle.posting_time, sle.name) < (sle2.posting_date, sle2.posting_time, sle2.name) - where sle2.name is null and sle.docstatus < 2 %s %s""" - % (item_conditions_sql, conditions), - as_dict=1, - ) # nosec - - -def get_parent_item_conditions(filters): - conditions = [] - - if filters.get("item_code"): - conditions.append("item.item_code = %(item_code)s") + if date := filters.get("date"): + query = query.where(sle.posting_date <= date) else: - if filters.get("brand"): - conditions.append("item.brand=%(brand)s") - if filters.get("item_group"): - conditions.append(get_item_group_condition(filters.get("item_group"))) - - conditions = " and ".join(conditions) - return "and {0}".format(conditions) if conditions else "" - - -def get_sle_conditions(filters): - conditions = "" - if not filters.get("date"): frappe.throw(_("'Date' is required")) - conditions += " and sle.posting_date <= %s" % frappe.db.escape(filters.get("date")) - if filters.get("warehouse"): warehouse_details = frappe.db.get_value( "Warehouse", filters.get("warehouse"), ["lft", "rgt"], as_dict=1 ) - if warehouse_details: - conditions += ( - " and exists (select name from `tabWarehouse` wh \ - where wh.lft >= %s and wh.rgt <= %s and sle.warehouse = wh.name)" - % (warehouse_details.lft, warehouse_details.rgt) - ) # nosec - return conditions + if warehouse_details: + 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)) + ) + ) + + return query.run(as_dict=True) 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..af7f20f3cc 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) @@ -318,20 +305,25 @@ def get_inventory_dimension_fields(): def get_items(filters): + item = frappe.qb.DocType("Item") + query = frappe.qb.from_(item).select(item.name) conditions = [] - if filters.get("item_code"): - conditions.append("item.name=%(item_code)s") + + if item_code := filters.get("item_code"): + conditions.append(item.name == item_code) else: - if filters.get("brand"): - conditions.append("item.brand=%(brand)s") - if filters.get("item_group"): - conditions.append(get_item_group_condition(filters.get("item_group"))) + if brand := filters.get("brand"): + conditions.append(item.brand == brand) + if item_group := filters.get("item_group"): + if condition := get_item_group_condition(item_group, item): + conditions.append(condition) items = [] if conditions: - items = frappe.db.sql_list( - """select name from `tabItem` item where {}""".format(" and ".join(conditions)), filters - ) + for condition in conditions: + query = query.where(condition) + items = [r[0] for r in query.run()] + return items @@ -343,29 +335,22 @@ def get_item_details(items, sl_entries, include_uom): if not items: return item_details - cf_field = cf_join = "" + item = frappe.qb.DocType("Item") + query = ( + frappe.qb.from_(item) + .select(item.name, item.item_name, item.description, item.item_group, item.brand, item.stock_uom) + .where(item.name.isin(items)) + ) + if include_uom: - cf_field = ", ucd.conversion_factor" - cf_join = ( - "left join `tabUOM Conversion Detail` ucd on ucd.parent=item.name and ucd.uom=%s" - % frappe.db.escape(include_uom) + ucd = frappe.qb.DocType("UOM Conversion Detail") + query = ( + query.left_join(ucd) + .on((ucd.parent == item.name) & (ucd.uom == include_uom)) + .select(ucd.conversion_factor) ) - res = 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.name in ({item_codes}) - """.format( - cf_field=cf_field, cf_join=cf_join, item_codes=",".join(["%s"] * len(items)) - ), - items, - as_dict=1, - ) + res = query.run(as_dict=True) for item in res: item_details.setdefault(item.name, item) @@ -440,16 +425,28 @@ def get_warehouse_condition(warehouse): return "" -def get_item_group_condition(item_group): +def get_item_group_condition(item_group, item_table=None): item_group_details = frappe.db.get_value("Item Group", item_group, ["lft", "rgt"], as_dict=1) if item_group_details: - return ( - "item.item_group in (select ig.name from `tabItem Group` ig \ - where ig.lft >= %s and ig.rgt <= %s and item.item_group = ig.name)" - % (item_group_details.lft, item_group_details.rgt) - ) - - return "" + if item_table: + ig = frappe.qb.DocType("Item Group") + return item_table.item_group.isin( + ( + frappe.qb.from_(ig) + .select(ig.name) + .where( + (ig.lft >= item_group_details.lft) + & (ig.rgt <= item_group_details.rgt) + & (item_table.item_group == ig.name) + ) + ) + ) + else: + return ( + "item.item_group in (select ig.name from `tabItem Group` ig \ + where ig.lft >= %s and ig.rgt <= %s and item.item_group = ig.name)" + % (item_group_details.lft, item_group_details.rgt) + ) def check_inventory_dimension_filters_applied(filters) -> bool: 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 50309647de..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 @@ -1053,7 +1045,7 @@ class update_entries_after(object): updated_values = {"actual_qty": data.qty_after_transaction, "stock_value": data.stock_value} if data.valuation_rate is not None: updated_values["valuation_rate"] = data.valuation_rate - frappe.db.set_value("Bin", bin_name, updated_values) + frappe.db.set_value("Bin", bin_name, updated_values, update_modified=True) def get_previous_sle_of_current_voucher(args, exclude_current_voucher=False): @@ -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/stock/utils.py b/erpnext/stock/utils.py index 9fb3be5188..b8c5187b2c 100644 --- a/erpnext/stock/utils.py +++ b/erpnext/stock/utils.py @@ -13,6 +13,8 @@ from frappe.utils import cstr, flt, get_link_to_form, nowdate, nowtime import erpnext from erpnext.stock.valuation import FIFOValuation, LIFOValuation +BarcodeScanResult = Dict[str, Optional[str]] + class InvalidWarehouseCompany(frappe.ValidationError): pass @@ -552,7 +554,16 @@ def check_pending_reposting(posting_date: str, throw_error: bool = True) -> bool @frappe.whitelist() -def scan_barcode(search_value: str) -> Dict[str, Optional[str]]: +def scan_barcode(search_value: str) -> BarcodeScanResult: + def set_cache(data: BarcodeScanResult): + frappe.cache().set_value(f"erpnext:barcode_scan:{search_value}", data, expires_in_sec=120) + + def get_cache() -> Optional[BarcodeScanResult]: + if data := frappe.cache().get_value(f"erpnext:barcode_scan:{search_value}"): + return data + + if scan_data := get_cache(): + return scan_data # search barcode no barcode_data = frappe.db.get_value( @@ -562,7 +573,9 @@ def scan_barcode(search_value: str) -> Dict[str, Optional[str]]: as_dict=True, ) if barcode_data: - return _update_item_info(barcode_data) + _update_item_info(barcode_data) + set_cache(barcode_data) + return barcode_data # search serial no serial_no_data = frappe.db.get_value( @@ -572,7 +585,9 @@ def scan_barcode(search_value: str) -> Dict[str, Optional[str]]: as_dict=True, ) if serial_no_data: - return _update_item_info(serial_no_data) + _update_item_info(serial_no_data) + set_cache(serial_no_data) + return serial_no_data # search batch no batch_no_data = frappe.db.get_value( @@ -582,7 +597,9 @@ def scan_barcode(search_value: str) -> Dict[str, Optional[str]]: as_dict=True, ) if batch_no_data: - return _update_item_info(batch_no_data) + _update_item_info(batch_no_data) + set_cache(batch_no_data) + return batch_no_data return {} 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/templates/includes/footer/footer_extension.html b/erpnext/templates/includes/footer/footer_extension.html index c7f0d06dff..0072dc280c 100644 --- a/erpnext/templates/includes/footer/footer_extension.html +++ b/erpnext/templates/includes/footer/footer_extension.html @@ -6,7 +6,7 @@ aria-label="{{ _('Your email address...') }}" aria-describedby="footer-subscribe-button">
-
diff --git a/erpnext/templates/includes/macros.html b/erpnext/templates/includes/macros.html index f56dc3a454..dc9ee234d9 100644 --- a/erpnext/templates/includes/macros.html +++ b/erpnext/templates/includes/macros.html @@ -1,5 +1,5 @@ {% macro product_image_square(website_image, css_class="") %} -
-
+
{% if d.thumbnail or d.image %} {{ product_image(d.thumbnail or d.image, no_border=True) }} {% else %} @@ -18,6 +18,9 @@
{{ html2text(d.description) | truncate(140) }}
+ + {{ _("Qty ") }}({{ d.get_formatted("qty") }}) +
{% endmacro %} diff --git a/erpnext/templates/includes/order/order_taxes.html b/erpnext/templates/includes/order/order_taxes.html index b821e6253d..0060ab39cc 100644 --- a/erpnext/templates/includes/order/order_taxes.html +++ b/erpnext/templates/includes/order/order_taxes.html @@ -1,84 +1,111 @@ {% if doc.taxes %} - - - {{ _("Net Total") }} - - - {{ doc.get_formatted("net_total") }} - - +
+
+
+ {{ _("Net Total") }} +
+
+ {{ doc.get_formatted("net_total") }} +
+
+
{% endif %} {% for d in doc.taxes %} {% if d.base_tax_amount %} - - - {{ d.description }} - - - {{ d.get_formatted("base_tax_amount") }} - - +
+
+
+ {{ d.description }} +
+
+ {{ doc.get_formatted("net_total") }} +
+
+
{% endif %} {% endfor %} {% if doc.doctype == 'Quotation' %} {% if doc.coupon_code %} - - - {{ _("Savings") }} - - - {% set tot_quotation_discount = [] %} - {%- for item in doc.items -%} - {% if tot_quotation_discount.append((((item.price_list_rate * item.qty) - * item.discount_percentage) / 100)) %} - {% endif %} - {% endfor %} - {{ frappe.utils.fmt_money((tot_quotation_discount | sum),currency=doc.currency) }} - - +
+
+
+ {{ _("Savings") }} +
+
+ {% set tot_quotation_discount = [] %} + {%- for item in doc.items -%} + {% if tot_quotation_discount.append((((item.price_list_rate * item.qty) + * item.discount_percentage) / 100)) %} + {% endif %} + {% endfor %} + {{ frappe.utils.fmt_money((tot_quotation_discount | sum),currency=doc.currency) }}
+
+
{% endif %} {% endif %} {% if doc.doctype == 'Sales Order' %} {% if doc.coupon_code %} - - - {{ _("Applied Coupon Code") }} - - - - {%- for row in frappe.get_all(doctype="Coupon Code", - fields=["coupon_code"], filters={ "name":doc.coupon_code}) -%} - {{ row.coupon_code }} - {% endfor %} - - - - - - {{ _("Savings") }} - - - - {% set tot_SO_discount = [] %} - {%- for item in doc.items -%} - {% if tot_SO_discount.append((((item.price_list_rate * item.qty) - * item.discount_percentage) / 100)) %}{% endif %} - {% endfor %} - {{ frappe.utils.fmt_money((tot_SO_discount | sum),currency=doc.currency) }} - - - +
+
+
+ {{ _("Total Amount") }} +
+
+ + {% set total_amount = [] %} + {%- for item in doc.items -%} + {% if total_amount.append((item.price_list_rate * item.qty)) %}{% endif %} + {% endfor %} + {{ frappe.utils.fmt_money((total_amount | sum),currency=doc.currency) }} + +
+
+
+
+
+
+ {{ _("Applied Coupon Code") }} +
+
+ + {%- for row in frappe.get_all(doctype="Coupon Code", + fields=["coupon_code"], filters={ "name":doc.coupon_code}) -%} + {{ row.coupon_code }} + {% endfor %} + +
+
+
+
+
+
+ {{ _("Savings") }} +
+
+ + {% set tot_SO_discount = [] %} + {%- for item in doc.items -%} + {% if tot_SO_discount.append((((item.price_list_rate * item.qty) + * item.discount_percentage) / 100)) %}{% endif %} + {% endfor %} + {{ frappe.utils.fmt_money((tot_SO_discount | sum),currency=doc.currency) }} + +
+
+
{% endif %} {% endif %} - - - {{ _("Grand Total") }} - - - {{ doc.get_formatted("grand_total") }} - - +
+
+
+ {{ _("Grand Total") }} +
+
+ {{ doc.get_formatted("grand_total") }} +
+
+
diff --git a/erpnext/templates/includes/transaction_row.html b/erpnext/templates/includes/transaction_row.html index 3cfb8d8440..72d498c998 100644 --- a/erpnext/templates/includes/transaction_row.html +++ b/erpnext/templates/includes/transaction_row.html @@ -1,20 +1,22 @@
-
+
- - {{ doc.name }} + {{ doc.name }}
{{ frappe.utils.global_date_format(doc.modified) }}
-
+
+ {{doc.status}} +
+
{{ doc.items_preview }}
{% if doc.get('grand_total') %} -
+
{{ doc.get_formatted("grand_total") }}
{% endif %} diff --git a/erpnext/templates/pages/demo.html b/erpnext/templates/pages/demo.html deleted file mode 100644 index f9934a33f3..0000000000 --- a/erpnext/templates/pages/demo.html +++ /dev/null @@ -1,77 +0,0 @@ -{% extends "templates/web.html" %} - -{% block script %} - -{% endblock %} - -{% block style %} - -{% endblock %} - -{% block title %} -{{ _("ERPNext Demo") }} -{% endblock %} - -{% block page_content %} -
- -
- - {{ _("ERPNext Demo") }} -
- -

Some functionality is disabled for the demo and the data will be cleared regularly.

-
-
- - -

Start a free 14-day trial -

- -{% endblock %} diff --git a/erpnext/templates/pages/order.html b/erpnext/templates/pages/order.html index ec1d49788b..6b354b2fab 100644 --- a/erpnext/templates/pages/order.html +++ b/erpnext/templates/pages/order.html @@ -5,149 +5,159 @@ {% include "templates/includes/breadcrumbs.html" %} {% endblock %} -{% block title %}{{ doc.name }}{% endblock %} +{% block title %} + {{ doc.name }} +{% endblock %} {% block header %} -

{{ doc.name }}

+

{{ doc.name }}

{% endblock %} {% block header_actions %} - {% endif %} -
{% if doc.terms %}
-

{{ doc.terms }}

+
+

{{ doc.terms }}

{% endif %} {% endblock %} {% block script %} - + -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/erpnext/translations/fr.csv b/erpnext/translations/fr.csv index b2074618a6..3ba5ade629 100644 --- a/erpnext/translations/fr.csv +++ b/erpnext/translations/fr.csv @@ -785,7 +785,7 @@ Default BOM for {0} not found,Nomenclature par défaut {0} introuvable, Default BOM not found for Item {0} and Project {1},La nomenclature par défaut n'a pas été trouvée pour l'Article {0} et le Projet {1}, Default Letter Head,En-Tête de Courrier par Défaut, Default Tax Template,Modèle de Taxes par Défaut, -Default Unit of Measure for Item {0} cannot be changed directly because you have already made some transaction(s) with another UOM. You will need to create a new Item to use a different Default UOM.,L’Unité de Mesure par Défaut pour l’Article {0} ne peut pas être modifiée directement parce que vous avez déjà fait une (des) transaction (s) avec une autre unité de mesure. Vous devez créer un nouvel article pour utiliser une UDM par défaut différente., +Default Unit of Measure for Item {0} cannot be changed directly because you have already made some transaction(s) with another UOM. You will need to create a new Item to use a different Default UOM.,L’Unité de Mesure par Défaut pour l’Article {0} ne peut pas être modifiée directement parce que vous avez déjà fait une (des) transaction (s) avec une autre unité de mesure. Vous devez créer un nouvel article pour utiliser une UdM par défaut différente., Default Unit of Measure for Variant '{0}' must be same as in Template '{1}',L’Unité de mesure par défaut pour la variante '{0}' doit être la même que dans le Modèle '{1}', Default settings for buying transactions.,Paramètres par défaut pour les transactions d'achat., Default settings for selling transactions.,Paramètres par défaut pour les transactions de vente., @@ -838,7 +838,7 @@ Difference Account,Compte d’Écart, "Difference Account must be a Asset/Liability type account, since this Stock Reconciliation is an Opening Entry","Le Compte d’Écart doit être un compte de type Actif / Passif, puisque cette Réconciliation de Stock est une écriture d'à-nouveau", Difference Amount,Écart de Montant, Difference Amount must be zero,L’Écart de Montant doit être égal à zéro, -Different UOM for items will lead to incorrect (Total) Net Weight value. Make sure that Net Weight of each item is in the same UOM.,Différentes UDM pour les articles conduira à un Poids Net (Total) incorrect . Assurez-vous que le Poids Net de chaque article a la même unité de mesure ., +Different UOM for items will lead to incorrect (Total) Net Weight value. Make sure that Net Weight of each item is in the same UOM.,Différentes UdM pour les articles conduira à un Poids Net (Total) incorrect . Assurez-vous que le Poids Net de chaque article a la même unité de mesure ., Direct Expenses,Charges Directes, Direct Income,Revenu direct, Disable,Désactiver, @@ -1409,7 +1409,7 @@ Lab Test,Test de laboratoire, Lab Test Report,Rapport de test de laboratoire, Lab Test Sample,Échantillon de test de laboratoire, Lab Test Template,Modèle de test de laboratoire, -Lab Test UOM,UDM de test de laboratoire, +Lab Test UOM,UdM de test de laboratoire, Lab Tests and Vital Signs,Tests de laboratoire et signes vitaux, Lab result datetime cannot be before testing datetime,La date et l'heure du résultat de laboratoire ne peuvent pas être avant la date et l'heure du test, Lab testing datetime cannot be before collection datetime,La date et l'heure du test de laboratoire ne peuvent pas être avant la date et l'heure de collecte, @@ -2806,7 +2806,7 @@ Stock Received But Not Billed,Stock Reçus Mais Non Facturés, Stock Reports,Rapports de stock, Stock Summary,Résumé du Stock, Stock Transactions,Transactions du Stock, -Stock UOM,UDM du Stock, +Stock UOM,UdM du Stock, Stock Value,Valeur du Stock, Stock balance in Batch {0} will become negative {1} for Item {2} at Warehouse {3},Solde du stock dans le Lot {0} deviendra négatif {1} pour l'Article {2} à l'Entrepôt {3}, Stock cannot be updated against Delivery Note {0},Stock ne peut pas être mis à jour pour le Bon de Livraison {0}, @@ -3161,9 +3161,9 @@ Trial Period End Date Cannot be before Trial Period Start Date,La date de fin de Trialling,Essai, Type of Business,Type de commerce, Types of activities for Time Logs,Types d'activités pour Journaux de Temps, -UOM,UDM, -UOM Conversion factor is required in row {0},Facteur de conversion de l'UDM est obligatoire dans la ligne {0}, -UOM coversion factor required for UOM: {0} in Item: {1},Facteur de coversion UDM requis pour l'UDM : {0} dans l'Article : {1}, +UOM,UdM, +UOM Conversion factor is required in row {0},Facteur de conversion de l'UdM est obligatoire dans la ligne {0}, +UOM coversion factor required for UOM: {0} in Item: {1},Facteur de coversion UdM requis pour l'UdM : {0} dans l'Article : {1}, URL,URL, Unable to find DocType {0},Impossible de trouver le DocType {0}, Unable to find exchange rate for {0} to {1} for key date {2}. Please create a Currency Exchange record manually,Impossible de trouver le taux de change pour {0} à {1} pour la date clé {2}. Veuillez créer une entrée de taux de change manuellement, @@ -3294,7 +3294,7 @@ Wednesday,Mercredi, Week,Semaine, Weekdays,Jours de la semaine, Weekly,Hebdomadaire, -"Weight is mentioned,\nPlease mention ""Weight UOM"" too","Poids est mentionné,\nVeuillez aussi mentionner ""UDM de Poids""", +"Weight is mentioned,\nPlease mention ""Weight UOM"" too","Poids est mentionné,\nVeuillez aussi mentionner ""UdM de Poids""", Welcome email sent,Email de bienvenue envoyé, Welcome to ERPNext,Bienvenue sur ERPNext, What do you need help with?,Avec quoi avez vous besoin d'aide ?, @@ -4938,12 +4938,15 @@ Is Cumulative,Est cumulatif, Coupon Code Based,Code de coupon basé, Discount on Other Item,Remise sur un autre article, Apply Rule On Other,Appliquer la règle sur autre, -Party Information,Informations sur la fête, +Party Information,Informations sur le tier, Quantity and Amount,Quantité et montant, Min Qty,Qté Min, Max Qty,Qté Max, -Min Amt,Min Amt, -Max Amt,Max Amt, +Min Amt,Montant Min, +Max Amt,Montant Max, +"If rate is zero them item will be treated as ""Free Item""",Si le prix est à 0 alors l'article sera traité comme article gratuit +Is Recursive,Est récursif +"Discounts to be applied in sequential ranges like buy 1 get 1, buy 2 get 2, buy 3 get 3 and so on","La remise sera appliquée séquentiellement telque : acheter 1 => recupérer 1, acheter 2 => recupérer 2, acheter 3 => recupérer 3, etc..." Period Settings,Paramètres de période, Margin,Marge, Margin Type,Type de Marge, @@ -5053,7 +5056,7 @@ Quantity and Rate,Quantité et Prix, Received Qty,Qté Reçue, Accepted Qty,Quantité acceptée, Rejected Qty,Qté Rejetée, -UOM Conversion Factor,Facteur de Conversion de l'UDM, +UOM Conversion Factor,Facteur de Conversion de l'UdM, Discount on Price List Rate (%),Remise sur la Liste des Prix (%), Price List Rate (Company Currency),Taux de la Liste de Prix (Devise Société), Rate (Company Currency),Prix (Devise Société), @@ -5085,7 +5088,7 @@ Purchase Receipt Detail,Détail du reçu d'achat, Item Weight Details,Détails du poids de l'article, Weight Per Unit,Poids par unité, Total Weight,Poids total, -Weight UOM,UDM de Poids, +Weight UOM,UdM de Poids, Page Break,Saut de Page, Consider Tax or Charge for,Tenir Compte de la Taxe et des Frais pour, Valuation and Total,Valorisation et Total, @@ -5153,7 +5156,7 @@ Advance amount,Montant de l'Avance, Sales Invoice Item,Article de la Facture de Vente, Customer's Item Code,Code de l'Article du Client, Brand Name,Nom de la Marque, -Qty as per Stock UOM,Qté par UDM du Stock, +Qty as per Stock UOM,Qté par UdM du Stock, Discount and Margin,Remise et Marge, Rate With Margin,Prix Avec Marge, Discount (%) on Price List Rate with Margin,Remise (%) sur le prix de la Liste de Prix avec la Marge, @@ -5501,7 +5504,7 @@ Blanket Order Rate,Prix unitaire de commande avec limites, Returned Qty,Qté Retournée, Purchase Order Item Supplied,Article Fourni depuis la Commande d'Achat, BOM Detail No,N° de Détail de la nomenclature, -Stock Uom,UDM du Stock, +Stock Uom,UdM du Stock, Raw Material Item Code,Code d’Article de Matière Première, Supplied Qty,Qté Fournie, Purchase Receipt Item Supplied,Articles Fournis du Reçus d’Achat, @@ -6149,7 +6152,7 @@ Drug Name / Description,Nom / description du médicament, Dosage,Dosage, Dosage by Time Interval,Dosage par intervalle de temps, Interval,Intervalle, -Interval UOM,UDM d'Intervalle, +Interval UOM,UdM d'Intervalle, Hour,Heure, Update Schedule,Mettre à Jour le Calendrier, Exercise,Exercice, @@ -7023,7 +7026,7 @@ Petrol,Essence, Diesel,Diesel, Natural Gas,Gaz Naturel, Electric,Électrique, -Fuel UOM,UDM Carburant, +Fuel UOM,UdM Carburant, Last Carbon Check,Dernière Vérification Carbone, Wheels,Roues, Doors,Portes, @@ -7182,7 +7185,7 @@ Item to be manufactured or repacked,Article à produire ou à réemballer, Quantity of item obtained after manufacturing / repacking from given quantities of raw materials,Quantité d'article obtenue après production / reconditionnement des quantités données de matières premières, Set rate of sub-assembly item based on BOM,Définir le prix des articles de sous-assemblage en fonction de la nomenclature, Allow Alternative Item,Autoriser un article alternatif, -Item UOM,UDM de l'Article, +Item UOM,UdM de l'Article, Conversion Rate,Taux de Conversion, Rate Of Materials Based On,Prix des Matériaux Basé sur, With Operations,Avec des Opérations, @@ -7926,7 +7929,7 @@ Territory Manager,Responsable Régional, For reference,Pour référence, Territory Targets,Objectifs Régionaux, Set Item Group-wise budgets on this Territory. You can also include seasonality by setting the Distribution.,Définir des budgets par Groupes d'Articles sur ce Territoire. Vous pouvez également inclure de la saisonnalité en définissant la Répartition., -UOM Name,Nom UDM, +UOM Name,Nom UdM, Check this to disallow fractions. (for Nos),Cochez cette case pour interdire les fractions. (Pour les numéros), Website Item Group,Groupe d'Articles du Site Web, Cross Listing of Item in multiple groups,Liste Croisée d'Articles dans plusieurs groupes, @@ -8198,10 +8201,10 @@ To Package No.,Au N° de Paquet, If more than one package of the same type (for print),Si plus d'un paquet du même type (pour l'impression), Package Weight Details,Détails du Poids du Paquet, The net weight of this package. (calculated automatically as sum of net weight of items),Le poids net de ce paquet. (Calculé automatiquement comme la somme du poids net des articles), -Net Weight UOM,UDM Poids Net, +Net Weight UOM,UdM Poids Net, Gross Weight,Poids Brut, The gross weight of the package. Usually net weight + packaging material weight. (for print),Le poids brut du colis. Habituellement poids net + poids du matériau d'emballage. (Pour l'impression), -Gross Weight UOM,UDM du Poids Brut, +Gross Weight UOM,UdM du Poids Brut, Packing Slip Item,Article Emballé, DN Detail,Détail du Bon de Livraison, STO-PICK-.YYYY.-,STO-PICK-.YYYY.-, @@ -8215,7 +8218,7 @@ Pick List Item,Élément de la liste de choix, Picked Qty,Quantité choisie, Price List Master,Données de Base des Listes de Prix, Price List Name,Nom de la Liste de Prix, -Price Not UOM Dependent,Prix non dépendant de l'UOM, +Price Not UOM Dependent,Prix non dépendant de l'UdM, Applicable for Countries,Applicable pour les Pays, Price List Country,Pays de la Liste des Prix, MAT-PRE-.YYYY.-,MAT-PRE-YYYY.-, @@ -8294,7 +8297,7 @@ Purchase Receipt No,N° du Reçu d'Achat, Inspection Required,Inspection obligatoire, From BOM,Depuis la nomenclature, For Quantity,Pour la Quantité, -As per Stock UOM,Selon UDM du Stock, +As per Stock UOM,Selon UdM du Stock, Including items for sub assemblies,Incluant les articles pour des sous-ensembles, Default Source Warehouse,Entrepôt Source par Défaut, Source Warehouse Address,Adresse de l'entrepôt source, @@ -8309,7 +8312,7 @@ Total Additional Costs,Total des Coûts Additionnels, Customer or Supplier Details,Détails du Client ou du Fournisseur, Per Transferred,Par transféré, Stock Entry Detail,Détails de l'Écriture de Stock, -Basic Rate (as per Stock UOM),Prix de base (comme l’UDM du Stock), +Basic Rate (as per Stock UOM),Prix de base (comme l’UdM du Stock), Basic Amount,Montant de Base, Additional Cost,Frais Supplémentaire, Serial No / Batch,N° de Série / Lot, @@ -8339,7 +8342,7 @@ Quantity Difference,Différence de Quantité, Amount Difference,Différence de Montant, Item Naming By,Nomenclature d'Article Par, Default Item Group,Groupe d'Éléments par Défaut, -Default Stock UOM,UDM par Défaut des Articles, +Default Stock UOM,UdM par Défaut des Articles, Sample Retention Warehouse,Entrepôt de stockage des échantillons, Default Valuation Method,Méthode de Valorisation par Défaut, Show Barcode Field,Afficher Champ Code Barre, @@ -8353,8 +8356,8 @@ Stock Frozen Upto,Stock Gelé Jusqu'au, Batch Identification,Identification par lots, Use Naming Series,Utiliser la série de noms, Naming Series Prefix,Préfix du nom de série, -UOM Category,Catégorie d'unité de mesure (UDM), -UOM Conversion Detail,Détails de Conversion de l'UDM, +UOM Category,Catégorie d'unité de mesure (UdM), +UOM Conversion Detail,Détails de Conversion de l'UdM, Variant Field,Champ de Variante, A logical Warehouse against which stock entries are made.,Un Entrepôt logique dans lequel les entrées en stock sont faites., Warehouse Detail,Détail de l'Entrepôt, @@ -9869,8 +9872,8 @@ Allowed Items,Articles autorisés Party Specific Item,Restriction d'article disponible Restrict Items Based On,Type de critére de restriction Based On Value,critére de restriction -Unit of Measure (UOM),Unité de mesure (UDM), -Unit Of Measure (UOM),Unité de mesure (UDM), +Unit of Measure (UOM),Unité de mesure (UdM), +Unit Of Measure (UOM),Unité de mesure (UdM), CRM Settings,Paramètres CRM Do Not Explode,Ne pas décomposer Quick Access, Accés rapides diff --git a/erpnext/translations/zh-TW.csv b/erpnext/translations/zh-TW.csv index de1d7632e7..c30dd7231c 100644 --- a/erpnext/translations/zh-TW.csv +++ b/erpnext/translations/zh-TW.csv @@ -10,20 +10,20 @@ DocType: Supplier Scorecard,Notify Supplier,通知供應商 apps/erpnext/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js +52,Please select Party Type first,請選擇黨第一型 DocType: Item,Customer Items,客戶項目 DocType: Project,Costing and Billing,成本核算和計費 -apps/erpnext/erpnext/hr/doctype/employee_advance/employee_advance.py +43,Advance account currency should be same as company currency {0},預付帳戶貨幣應與公司貨幣{0}相同 +apps/erpnext/erpnext/hr/doctype/employee_advance/employee_advance.py +43,Advance account currency should be same as company currency {0},預付科目貨幣應與公司貨幣{0}相同 DocType: QuickBooks Migrator,Token Endpoint,令牌端點 -apps/erpnext/erpnext/accounts/doctype/account/account.py +55,Account {0}: Parent account {1} can not be a ledger,帳戶{0}:父帳戶{1}不能是總帳 +apps/erpnext/erpnext/accounts/doctype/account/account.py +55,Account {0}: Parent account {1} can not be a ledger,科目{0}:上層科目{1}不能是總帳 DocType: Item,Publish Item to hub.erpnext.com,發布項目hub.erpnext.com apps/erpnext/erpnext/hr/doctype/leave_application/leave_application.py +270,Cannot find active Leave Period,找不到有效的休假期 apps/erpnext/erpnext/hr/doctype/employee/employee_dashboard.py +22,Evaluation,評估 DocType: Item,Default Unit of Measure,預設的計量單位 DocType: SMS Center,All Sales Partner Contact,所有的銷售合作夥伴聯絡 DocType: Department,Leave Approvers,休假審批人 -DocType: Employee,Bio / Cover Letter,生物/求職信 +DocType: Employee,Bio / Cover Letter,自傳/求職信 DocType: Patient Encounter,Investigations,調查 DocType: Restaurant Order Entry,Click Enter To Add,點擊輸入要添加 apps/erpnext/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py +29,"Missing value for Password, API Key or Shopify URL",缺少密碼,API密鑰或Shopify網址的值 -apps/erpnext/erpnext/public/js/setup_wizard.js +243,All Accounts,所有帳戶 +apps/erpnext/erpnext/public/js/setup_wizard.js +243,All Accounts,所有科目 apps/erpnext/erpnext/hr/doctype/employee_transfer/employee_transfer.py +15,Cannot transfer Employee with status Left,無法轉移狀態為左的員工 apps/erpnext/erpnext/manufacturing/doctype/production_order/production_order.py +216,"Stopped Production Order cannot be cancelled, Unstop it first to cancel",停止生產訂單無法取消,首先Unstop它取消 apps/erpnext/erpnext/assets/doctype/asset/asset.js +338,Do you really want to scrap this asset?,難道你真的想放棄這項資產? @@ -48,12 +48,12 @@ DocType: Allowed To Transact With,Allowed To Transact With,允許與 DocType: Bank Guarantee,Customer,客戶 DocType: Purchase Receipt Item,Required By,需求來自 DocType: Delivery Note,Return Against Delivery Note,射向送貨單 -DocType: Asset Category,Finance Book Detail,財務圖書細節 +DocType: Asset Category,Finance Book Detail,財務帳簿細節 DocType: Purchase Order,% Billed,%已開立帳單 apps/erpnext/erpnext/controllers/sales_and_purchase_return.py +41,Exchange Rate must be same as {0} {1} ({2}),匯率必須一致{0} {1}({2}) DocType: Sales Invoice,Customer Name,客戶名稱 DocType: Vehicle,Natural Gas,天然氣 -apps/erpnext/erpnext/setup/setup_wizard/operations/company_setup.py +63,Bank account cannot be named as {0},銀行賬戶不能命名為{0} +apps/erpnext/erpnext/setup/setup_wizard/operations/company_setup.py +63,Bank account cannot be named as {0},銀行科目不能命名為{0} DocType: Employee Tax Exemption Declaration,HRA as per Salary Structure,HRA根據薪資結構 DocType: Account,Heads (or groups) against which Accounting Entries are made and balances are maintained.,頭(或組)針對其會計分錄是由和平衡得以維持。 apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py +197,Outstanding for {0} cannot be less than zero ({1}),傑出的{0}不能小於零( {1} ) @@ -142,11 +142,11 @@ apps/erpnext/erpnext/manufacturing/doctype/production_plan/production_plan_dashb apps/erpnext/erpnext/hr/doctype/attendance/attendance.py +46,Attendance date can not be less than employee's joining date,考勤日期不得少於員工的加盟日期 DocType: Grading Scale,Grading Scale Name,分級標準名稱 apps/erpnext/erpnext/public/js/hub/marketplace.js +147,Add Users to Marketplace,將用戶添加到市場 -apps/erpnext/erpnext/accounts/doctype/account/account.js +37,This is a root account and cannot be edited.,這是一個 root 帳戶,不能被編輯。 -DocType: BOM,Operations,作業 +apps/erpnext/erpnext/accounts/doctype/account/account.js +37,This is a root account and cannot be edited.,這是一個 root 科目,不能被編輯。 +DocType: BOM,Operations,操作 apps/erpnext/erpnext/setup/doctype/authorization_rule/authorization_rule.py +38,Cannot set authorization on basis of Discount for {0},不能在折扣的基礎上設置授權{0} DocType: Subscription,Subscription Start Date,訂閱開始日期 -DocType: Healthcare Settings,Default receivable accounts to be used if not set in Patient to book Appointment charges.,如果未在患者中設置預約費用,則使用默認應收帳戶。 +DocType: Healthcare Settings,Default receivable accounts to be used if not set in Patient to book Appointment charges.,如果未在患者中設置預約費用,則使用默認應收科目。 DocType: Rename Tool,"Attach .csv file with two columns, one for the old name and one for the new name",附加.csv文件有兩列,一為舊名稱,一個用於新名稱 apps/erpnext/erpnext/regional/report/eway_bill/eway_bill.py +195,From Address 2,來自地址2 apps/erpnext/erpnext/accounts/utils.py +74,{0} {1} not in any active Fiscal Year.,{0} {1} 不在任何有效的會計年度 @@ -216,14 +216,14 @@ apps/erpnext/erpnext/stock/doctype/stock_entry/stock_entry.py +36,From {0} to {1 apps/erpnext/erpnext/setup/setup_wizard/setup_wizard.py +51,Failed to setup taxes,無法設置稅收 DocType: Item,Copy From Item Group,從項目群組複製 DocType: Journal Entry,Opening Entry,開放報名 -apps/erpnext/erpnext/accounts/doctype/cheque_print_template/cheque_print_template.js +25,Account Pay Only,賬戶只需支付 +apps/erpnext/erpnext/accounts/doctype/cheque_print_template/cheque_print_template.js +25,Account Pay Only,科目只需支付 DocType: Loan,Repay Over Number of Periods,償還期的超過數 DocType: Stock Entry,Additional Costs,額外費用 -apps/erpnext/erpnext/accounts/doctype/account/account.py +145,Account with existing transaction can not be converted to group.,帳戶與現有的交易不能被轉換到群組。 +apps/erpnext/erpnext/accounts/doctype/account/account.py +145,Account with existing transaction can not be converted to group.,科目與現有的交易不能被轉換到群組。 DocType: Lead,Product Enquiry,產品查詢 DocType: Education Settings,Validate Batch for Students in Student Group,驗證學生組學生的批次 apps/erpnext/erpnext/hr/doctype/attendance/attendance.py +38,No leave record found for employee {0} for {1},未找到員工的假期記錄{0} {1} -DocType: Company,Unrealized Exchange Gain/Loss Account,未實現的匯兌收益/損失賬戶 +DocType: Company,Unrealized Exchange Gain/Loss Account,未實現的匯兌收益/損失科目 apps/erpnext/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js +23,Please enter company first,請先輸入公司 apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.js +626,Please select Company first,請首先選擇公司 DocType: Employee Education,Under Graduate,根據研究生 @@ -236,7 +236,7 @@ DocType: Fee Schedule,Send Payment Request Email,發送付款請求電子郵件 apps/erpnext/erpnext/manufacturing/doctype/bom/bom.py +282,Item {0} does not exist in the system or has expired,項目{0}不存在於系統中或已過期 DocType: Supplier,Leave blank if the Supplier is blocked indefinitely,如果供應商被無限期封鎖,請留空 apps/erpnext/erpnext/setup/setup_wizard/data/industry_type.py +44,Real Estate,房地產 -apps/erpnext/erpnext/accounts/report/general_ledger/general_ledger.html +1,Statement of Account,帳戶狀態 +apps/erpnext/erpnext/accounts/report/general_ledger/general_ledger.html +1,Statement of Account,科目狀態 apps/erpnext/erpnext/setup/setup_wizard/data/industry_type.py +41,Pharmaceuticals,製藥 DocType: Purchase Invoice Item,Is Fixed Asset,是固定的資產 apps/erpnext/erpnext/stock/doctype/stock_entry/stock_entry.py +355,"Available qty is {0}, you need {1}",可用數量是{0},則需要{1} @@ -284,7 +284,7 @@ DocType: Production Plan,Material Request Detail,材料請求詳情 DocType: Selling Settings,Default Quotation Validity Days,默認報價有效天數 apps/erpnext/erpnext/controllers/accounts_controller.py +886,"To include tax in row {0} in Item rate, taxes in rows {1} must also be included",要包括稅款,行{0}項率,稅收行{1}也必須包括在內 DocType: Payroll Entry,Validate Attendance,驗證出席 -DocType: Sales Invoice,Change Amount,漲跌額 +DocType: Sales Invoice,Change Amount,變動金額 DocType: Party Tax Withholding Config,Certificate Received,已收到證書 DocType: GST Settings,Set Invoice Value for B2C. B2CL and B2CS calculated based on this invoice value.,設置B2C的發票值。 B2CL和B2CS根據此發票值計算。 DocType: BOM Update Tool,New BOM,新的物料清單 @@ -294,7 +294,7 @@ DocType: Supplier Group,Supplier Group Name,供應商集團名稱 DocType: Driver,Driving License Categories,駕駛執照類別 apps/erpnext/erpnext/selling/doctype/sales_order/sales_order.py +124,Please enter Delivery Date,請輸入交貨日期 DocType: Depreciation Schedule,Make Depreciation Entry,計提折舊進入 -DocType: Closed Document,Closed Document,封閉文件 +DocType: Closed Document,Closed Document,關閉文件 DocType: HR Settings,Leave Settings,保留設置 apps/erpnext/erpnext/hr/doctype/staffing_plan/staffing_plan.js +76,Number of positions cannot be less then current count of employees,職位數量不能少於當前員工人數 DocType: Lead,Request Type,請求類型 @@ -308,7 +308,7 @@ apps/erpnext/erpnext/setup/setup_wizard/operations/install_fixtures.py +144,Exec apps/erpnext/erpnext/config/manufacturing.py +62,Details of the operations carried out.,進行的作業細節。 DocType: Asset Maintenance Log,Maintenance Status,維修狀態 apps/erpnext/erpnext/non_profit/doctype/member/member_dashboard.py +10,Membership Details,會員資格 -apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py +56,{0} {1}: Supplier is required against Payable account {2},{0} {1}:需要對供應商應付賬款{2} +apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py +56,{0} {1}: Supplier is required against Payable account {2},{0} {1}:需要對供應商應付帳款{2} apps/erpnext/erpnext/config/selling.py +52,Items and Pricing,項目和定價 apps/erpnext/erpnext/projects/doctype/project/project_dashboard.html +2,Total hours: {0},總時間:{0} apps/erpnext/erpnext/accounts/report/trial_balance/trial_balance.py +43,From Date should be within the Fiscal Year. Assuming From Date = {0},從日期應該是在財政年度內。假設起始日期={0} @@ -369,12 +369,12 @@ DocType: Company,Default Payroll Payable Account,默認情況下,應付職工 apps/erpnext/erpnext/education/doctype/student_group/student_group.js +51,Update Email Group,更新電子郵件組 DocType: Sales Invoice,Is Opening Entry,是開放登錄 DocType: Lab Test Template,"If unchecked, the item wont be appear in Sales Invoice, but can be used in group test creation. ",如果取消選中,該項目不會出現在銷售發票中,但可用於創建組測試。 -DocType: Customer Group,Mention if non-standard receivable account applicable,何況,如果不規範應收賬款適用 +DocType: Customer Group,Mention if non-standard receivable account applicable,何況,如果不規範應收帳款適用 DocType: Course Schedule,Instructor Name,導師姓名 DocType: Company,Arrear Component,欠費組件 DocType: Supplier Scorecard,Criteria Setup,條件設置 apps/erpnext/erpnext/manufacturing/doctype/production_order/production_order.py +199,For Warehouse is required before Submit,對於倉庫之前,需要提交 -DocType: Codification Table,Medical Code,醫療法 +DocType: Codification Table,Medical Code,醫療代號 apps/erpnext/erpnext/config/integrations.py +37,Connect Amazon with ERPNext,將Amazon與ERPNext連接起來 apps/erpnext/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py +20,Please enter Company,請輸入公司名稱 DocType: Delivery Note Item,Against Sales Invoice Item,對銷售發票項目 @@ -406,9 +406,9 @@ DocType: Inpatient Record,Discharge Scheduled,出院預定 apps/erpnext/erpnext/hr/doctype/employee/employee.py +138,Relieving Date must be greater than Date of Joining,解除日期必須大於加入的日期 DocType: POS Closing Voucher,Cashier,出納員 apps/erpnext/erpnext/setup/setup_wizard/operations/install_fixtures.py +198,Leaves per Year,每年葉 -apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +162,Row {0}: Please check 'Is Advance' against Account {1} if this is an advance entry.,行{0}:請檢查'是推進'對帳戶{1},如果這是一個進步條目。 +apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +162,Row {0}: Please check 'Is Advance' against Account {1} if this is an advance entry.,行{0}:請檢查'是進階'對科目{1},如果這是一個進階條目。 apps/erpnext/erpnext/stock/utils.py +243,Warehouse {0} does not belong to company {1},倉庫{0}不屬於公司{1} -DocType: Email Digest,Profit & Loss,利潤損失 +DocType: Email Digest,Profit & Loss,收益與損失 DocType: Task,Total Costing Amount (via Time Sheet),總成本計算量(通過時間表) apps/erpnext/erpnext/education/doctype/fee_schedule/fee_schedule.py +76,Please setup Students under Student Groups,請設置學生組的學生 DocType: Item Website Specification,Item Website Specification,項目網站規格 @@ -479,7 +479,7 @@ apps/erpnext/erpnext/config/desktop.py +159,Learn,學習 DocType: Purchase Invoice Item,Enable Deferred Expense,啟用延期費用 DocType: Asset,Next Depreciation Date,接下來折舊日期 apps/erpnext/erpnext/projects/doctype/activity_type/activity_type.js +3,Activity Cost per Employee,每個員工活動費用 -DocType: Accounts Settings,Settings for Accounts,設置帳戶 +DocType: Accounts Settings,Settings for Accounts,會計設定 apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +800,Supplier Invoice No exists in Purchase Invoice {0},供應商發票不存在採購發票{0} apps/erpnext/erpnext/config/selling.py +118,Manage Sales Person Tree.,管理銷售人員樹。 apps/erpnext/erpnext/stock/doctype/delivery_trip/delivery_trip.py +105,"Cannot process route, since Google Maps Settings is disabled.",由於禁用了Google地圖設置,因此無法處理路線。 @@ -521,7 +521,7 @@ apps/erpnext/erpnext/setup/doctype/email_digest/templates/default.html +97,Upcom apps/erpnext/erpnext/public/js/templates/item_quick_entry.html +1,Variant Attributes,變量屬性 apps/erpnext/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py +114,Please select month and year,請選擇年份和月份 DocType: Employee,Company Email,企業郵箱 -DocType: GL Entry,Debit Amount in Account Currency,在賬戶幣種借記金額 +DocType: GL Entry,Debit Amount in Account Currency,在科目幣種借記金額 apps/erpnext/erpnext/crm/report/campaign_efficiency/campaign_efficiency.py +21,Order Value,訂單價值 apps/erpnext/erpnext/crm/report/campaign_efficiency/campaign_efficiency.py +21,Order Value,訂單價值 DocType: Certified Consultant,Certified Consultant,認證顧問 @@ -550,7 +550,7 @@ apps/erpnext/erpnext/accounts/doctype/cost_center/cost_center.js +101,Convert to DocType: Project Update,Good/Steady,好/穩定 DocType: Bank Statement Transaction Invoice Item,Invoice Date,發票日期 DocType: GL Entry,Debit Amount,借方金額 -apps/erpnext/erpnext/accounts/party.py +277,There can only be 1 Account per Company in {0} {1},只能有每公司1帳戶{0} {1} +apps/erpnext/erpnext/accounts/party.py +277,There can only be 1 Account per Company in {0} {1},只能有每公司1科目{0} {1} DocType: Support Search Source,Response Result Key Path,響應結果關鍵路徑 DocType: Journal Entry,Inter Company Journal Entry,Inter公司日記帳分錄 apps/erpnext/erpnext/stock/doctype/stock_entry/stock_entry.py +534,For quantity {0} should not be grater than work order quantity {1},數量{0}不應超過工單數量{1} @@ -562,7 +562,7 @@ apps/erpnext/erpnext/accounts/report/accounts_receivable/accounts_receivable.htm DocType: Setup Progress Action,Action Document,行動文件 DocType: Chapter Member,Website URL,網站網址 DocType: Delivery Note,Instructions,說明 -DocType: Quality Inspection,Inspected By,視察 +DocType: Quality Inspection,Inspected By,檢查 DocType: Asset Maintenance Log,Maintenance Type,維護類型 apps/erpnext/erpnext/education/doctype/student_group/student_group.py +45,{0} - {1} is not enrolled in the Course {2},{0} - {1} 未在課程中註冊 {2} apps/erpnext/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.html +225,Student Name: ,學生姓名: @@ -642,17 +642,17 @@ apps/erpnext/erpnext/stock/doctype/packing_slip/packing_slip.js +57,'To Case No. DocType: Certification Application,Non Profit,非營利 DocType: Production Plan,Not Started,未啟動 DocType: Lead,Channel Partner,渠道合作夥伴 -DocType: Account,Old Parent,老家長 +DocType: Account,Old Parent,舊上級 apps/erpnext/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py +24,Mandatory field - Academic Year,必修課 - 學年 apps/erpnext/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py +24,Mandatory field - Academic Year,必修課 - 學年 apps/erpnext/erpnext/accounts/doctype/payment_entry/payment_entry.py +221,{0} {1} is not associated with {2} {3},{0} {1} 未與 {2} {3} 關聯 DocType: Notification Control,Customize the introductory text that goes as a part of that email. Each transaction has a separate introductory text.,自定義去作為郵件的一部分的介紹文字。每筆交易都有一個單獨的介紹性文字。 apps/erpnext/erpnext/manufacturing/doctype/job_card/job_card.py +56,Row {0} : Operation is required against the raw material item {1},行{0}:對原材料項{1}需要操作 -apps/erpnext/erpnext/hr/doctype/expense_claim/expense_claim.py +180,Please set default payable account for the company {0},請為公司{0}設置預設應付賬款 +apps/erpnext/erpnext/hr/doctype/expense_claim/expense_claim.py +180,Please set default payable account for the company {0},請為公司{0}設置預設應付帳款 apps/erpnext/erpnext/stock/doctype/stock_entry/stock_entry.py +608,Transaction not allowed against stopped Work Order {0},不允許對停止的工單{0}進行交易 DocType: Setup Progress Action,Min Doc Count,最小文件計數 apps/erpnext/erpnext/config/manufacturing.py +84,Global settings for all manufacturing processes.,所有製造過程中的全域設定。 -DocType: Accounts Settings,Accounts Frozen Upto,帳戶被凍結到 +DocType: Accounts Settings,Accounts Frozen Upto,科目被凍結到 DocType: SMS Log,Sent On,發送於 apps/erpnext/erpnext/stock/doctype/item/item.py +778,Attribute {0} selected multiple times in Attributes Table,屬性{0}多次選擇在屬性表 DocType: HR Settings,Employee record is created using selected field. ,使用所選欄位創建員工記錄。 @@ -717,7 +717,7 @@ apps/erpnext/erpnext/education/doctype/student_group/student_group.py +22,Please DocType: Codification Table,Codification Table,編纂表 DocType: Timesheet Detail,Hrs,小時 apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.js +410,Please select Company,請選擇公司 -DocType: Stock Entry Detail,Difference Account,差異帳戶 +DocType: Stock Entry Detail,Difference Account,差異科目 DocType: Purchase Invoice,Supplier GSTIN,供應商GSTIN apps/erpnext/erpnext/projects/doctype/task/task.py +50,Cannot close task as its dependant task {0} is not closed.,不能因為其依賴的任務{0}沒有關閉關閉任務。 apps/erpnext/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py +435,Please enter Warehouse for which Material Request will be raised,請輸入物料需求欲增加的倉庫 @@ -759,7 +759,7 @@ apps/erpnext/erpnext/config/stock.py +337,Managing Subcontracting,管理轉包 DocType: Vital Signs,Body Temperature,體溫 DocType: Project,Project will be accessible on the website to these users,項目將在網站向這些用戶上訪問 apps/erpnext/erpnext/stock/doctype/serial_no/serial_no.py +292,Cannot cancel {0} {1} because Serial No {2} does not belong to the warehouse {3},無法取消{0} {1},因為序列號{2}不屬於倉庫{3} -DocType: Company,Default Deferred Expense Account,默認遞延費用帳戶 +DocType: Company,Default Deferred Expense Account,默認遞延費用科目 apps/erpnext/erpnext/config/projects.py +29,Define Project type.,定義項目類型。 DocType: Supplier Scorecard,Weighting Function,加權函數 DocType: Healthcare Practitioner,OP Consulting Charge,OP諮詢費 @@ -767,7 +767,7 @@ apps/erpnext/erpnext/utilities/user_progress.py +28,Setup your ,設置你的 DocType: Student Report Generation Tool,Show Marks,顯示標記 DocType: Support Settings,Get Latest Query,獲取最新查詢 DocType: Quotation,Rate at which Price list currency is converted to company's base currency,價目表貨幣被換算成公司基礎貨幣的匯率 -apps/erpnext/erpnext/setup/doctype/company/company.py +74,Account {0} does not belong to company: {1},帳戶{0}不屬於公司:{1} +apps/erpnext/erpnext/setup/doctype/company/company.py +74,Account {0} does not belong to company: {1},科目{0}不屬於公司:{1} apps/erpnext/erpnext/setup/doctype/company/company.py +56,Abbreviation already used for another company,另一家公司已使用此縮寫 DocType: Selling Settings,Default Customer Group,預設客戶群組 DocType: Employee,IFSC Code,IFSC代碼 @@ -792,20 +792,20 @@ apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +76,Total C DocType: Installation Note Item,Installation Note Item,安裝注意項 DocType: Production Plan Item,Pending Qty,待定數量 apps/erpnext/erpnext/accounts/party.py +429,{0} {1} is not active,{0} {1}是不活動 -DocType: Woocommerce Settings,Freight and Forwarding Account,貨運和轉運帳戶 +DocType: Woocommerce Settings,Freight and Forwarding Account,貨運和轉運科目 apps/erpnext/erpnext/config/accounts.py +240,Setup cheque dimensions for printing,設置檢查尺寸打印 apps/erpnext/erpnext/hr/doctype/payroll_entry/payroll_entry.js +33,Create Salary Slips,創建工資單 DocType: Vital Signs,Bloated,脹 DocType: Salary Slip,Salary Slip Timesheet,工資單時間表 apps/erpnext/erpnext/controllers/buying_controller.py +200,Supplier Warehouse mandatory for sub-contracted Purchase Receipt,對於轉包的採購入庫單,供應商倉庫是強制性輸入的。 DocType: Sales Invoice,Total Commission,佣金總計 -DocType: Tax Withholding Account,Tax Withholding Account,扣繳稅款賬戶 +DocType: Tax Withholding Account,Tax Withholding Account,扣繳稅款科目 DocType: Pricing Rule,Sales Partner,銷售合作夥伴 apps/erpnext/erpnext/config/buying.py +150,All Supplier scorecards.,所有供應商記分卡。 DocType: Buying Settings,Purchase Receipt Required,需要採購入庫單 DocType: Delivery Note,Rail,軌 apps/erpnext/erpnext/stock/doctype/stock_entry/stock_entry.py +267,Target warehouse in row {0} must be same as Work Order,行{0}中的目標倉庫必須與工單相同 -apps/erpnext/erpnext/stock/doctype/item/item.py +183,Valuation Rate is mandatory if Opening Stock entered,估價費用是強制性的,如果打開股票進入 +apps/erpnext/erpnext/stock/doctype/item/item.py +183,Valuation Rate is mandatory if Opening Stock entered,估價費用是強制性的,如果打開庫存進入 apps/erpnext/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py +143,No records found in the Invoice table,沒有在發票表中找到記錄 apps/erpnext/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js +36,Please select Company and Party Type first,請選擇公司和黨的第一型 apps/erpnext/erpnext/accounts/doctype/pos_profile/pos_profile.py +31,"Already set default in pos profile {0} for user {1}, kindly disabled default",已經在用戶{1}的pos配置文件{0}中設置了默認值,請禁用默認值 @@ -828,7 +828,7 @@ apps/erpnext/erpnext/hr/doctype/attendance_request/attendance_request.py +18,Hal apps/erpnext/erpnext/public/js/pos/pos.html +4,Item Cart,項目車 apps/erpnext/erpnext/accounts/doctype/fiscal_year/fiscal_year.py +38,Fiscal Year Start Date should not be greater than Fiscal Year End Date,會計年度開始日期應不大於財政年度結束日期 DocType: Issue,Resolution,決議 -DocType: Employee,Personal Bio,個人生物 +DocType: Employee,Personal Bio,個人自傳 apps/erpnext/erpnext/non_profit/report/expiring_memberships/expiring_memberships.py +15,Membership ID,會員ID apps/erpnext/erpnext/templates/pages/order.html +77,Delivered: {0},交貨:{0} DocType: QuickBooks Migrator,Connected to QuickBooks,連接到QuickBooks @@ -868,7 +868,7 @@ DocType: Loan Application,Total Payable Interest,合計應付利息 apps/erpnext/erpnext/education/doctype/fee_schedule/fee_schedule.js +58,Total Outstanding: {0},總計:{0} DocType: Sales Invoice Timesheet,Sales Invoice Timesheet,銷售發票時間表 apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +150,Reference No & Reference Date is required for {0},參考號與參考日期須為{0} -DocType: Payroll Entry,Select Payment Account to make Bank Entry,選擇付款賬戶,使銀行進入 +DocType: Payroll Entry,Select Payment Account to make Bank Entry,選擇付款科目,使銀行進入 DocType: Hotel Settings,Default Invoice Naming Series,默認發票命名系列 apps/erpnext/erpnext/utilities/activation.py +136,"Create Employee records to manage leaves, expense claims and payroll",建立員工檔案管理葉,報銷和工資 apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +712,An error occurred during the update process,更新過程中發生錯誤 @@ -898,7 +898,7 @@ DocType: Timesheet,Billed,計費 DocType: Batch,Batch Description,批次說明 apps/erpnext/erpnext/education/doctype/student_group_creation_tool/student_group_creation_tool.js +12,Creating student groups,創建學生組 apps/erpnext/erpnext/education/doctype/student_group_creation_tool/student_group_creation_tool.js +12,Creating student groups,創建學生組 -apps/erpnext/erpnext/accounts/utils.py +763,"Payment Gateway Account not created, please create one manually.",支付網關帳戶沒有創建,請手動創建一個。 +apps/erpnext/erpnext/accounts/utils.py +763,"Payment Gateway Account not created, please create one manually.",支付閘道科目沒有創建,請手動創建一個。 apps/erpnext/erpnext/education/doctype/student_applicant/student_applicant.py +51,Not eligible for the admission in this program as per DOB,按照DOB的規定,沒有資格參加本計劃 DocType: Sales Invoice,Sales Taxes and Charges,銷售稅金及費用 DocType: Student,Sibling Details,兄弟姐妹詳情 @@ -922,7 +922,7 @@ apps/erpnext/erpnext/education/report/student_and_guardian_contact_details/stude apps/erpnext/erpnext/setup/setup_wizard/operations/install_fixtures.py +87,Manager,經理 apps/erpnext/erpnext/accounts/report/budget_variance_report/budget_variance_report.js +8,From Fiscal Year,從財政年度開始 apps/erpnext/erpnext/selling/doctype/customer/customer.py +185,New credit limit is less than current outstanding amount for the customer. Credit limit has to be atleast {0},新的信用額度小於當前餘額為客戶著想。信用額度是ATLEAST {0} -apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +453,Please set account in Warehouse {0},請在倉庫{0}中設置帳戶 +apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +453,Please set account in Warehouse {0},請在倉庫{0}中設置會計科目 apps/erpnext/erpnext/controllers/trends.py +39,'Based On' and 'Group By' can not be same,“根據”和“分組依據”不能相同 DocType: Sales Person,Sales Person Targets,銷售人員目標 DocType: Work Order Operation,In minutes,在幾分鐘內 @@ -970,7 +970,7 @@ apps/erpnext/erpnext/config/accounts.py +293,To make recurring documents,複製 DocType: Loan,Total Interest Payable,合計應付利息 DocType: Landed Cost Taxes and Charges,Landed Cost Taxes and Charges,到岸成本稅費 DocType: Work Order Operation,Actual Start Time,實際開始時間 -DocType: Purchase Invoice Item,Deferred Expense Account,遞延費用帳戶 +DocType: Purchase Invoice Item,Deferred Expense Account,遞延費用科目 DocType: BOM Operation,Operation Time,操作時間 apps/erpnext/erpnext/manufacturing/doctype/work_order/work_order.js +466,Finish,完 apps/erpnext/erpnext/hr/doctype/salary_structure/salary_structure.js +441,Base,基礎 @@ -979,7 +979,7 @@ DocType: Travel Itinerary,Travel To,前往 apps/erpnext/erpnext/selling/page/point_of_sale/point_of_sale.js +1659,Write Off Amount,核銷金額 DocType: Leave Block List Allow,Allow User,允許用戶 DocType: Journal Entry,Bill No,帳單號碼 -DocType: Company,Gain/Loss Account on Asset Disposal,在資產處置收益/損失帳戶 +DocType: Company,Gain/Loss Account on Asset Disposal,在資產處置收益/損失科目 DocType: Vehicle Log,Service Details,服務細節 DocType: Vehicle Log,Service Details,服務細節 DocType: Lab Test Template,Grouped,分組 @@ -1013,7 +1013,7 @@ apps/erpnext/erpnext/hr/doctype/salary_structure/salary_structure.js +408,Previe apps/erpnext/erpnext/accounts/doctype/budget/budget.py +64,Account {0} has been entered multiple times,帳戶{0}已多次輸入 DocType: Account,Expenses Included In Valuation,支出計入估值 apps/erpnext/erpnext/non_profit/doctype/membership/membership.py +38,You can only renew if your membership expires within 30 days,如果您的會員資格在30天內到期,您只能續訂 -DocType: Shopping Cart Settings,Show Stock Availability,顯示股票可用性 +DocType: Shopping Cart Settings,Show Stock Availability,顯示庫存可用性 apps/erpnext/erpnext/assets/doctype/asset/asset.py +519,Set {0} in asset category {1} or company {2},在資產類別{1}或公司{2}中設置{0} DocType: Location,Longitude,經度 ,Absent Student Report,缺席學生報告 @@ -1038,7 +1038,7 @@ apps/erpnext/erpnext/education/doctype/student_group/student_group.py +24,Please DocType: Project,Estimated Cost,估計成本 DocType: Request for Quotation,Link to material requests,鏈接到材料請求 DocType: Journal Entry,Credit Card Entry,信用卡進入 -apps/erpnext/erpnext/config/accounts.py +35,Company and Accounts,公司與賬戶 +apps/erpnext/erpnext/config/accounts.py +35,Company and Accounts,公司與科目 apps/erpnext/erpnext/stock/report/stock_balance/stock_balance.py +85,In Value,在數值 DocType: Asset Settings,Depreciation Options,折舊選項 apps/erpnext/erpnext/assets/doctype/asset_movement/asset_movement.py +28,Either location or employee must be required,必須要求地點或員工 @@ -1055,7 +1055,7 @@ DocType: Purchase Order,Supply Raw Materials,供應原料 apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py +10,Current Assets,流動資產 apps/erpnext/erpnext/stock/doctype/stock_entry/stock_entry.py +161,{0} is not a stock Item,{0}不是庫存項目 apps/erpnext/erpnext/hr/notification/training_feedback/training_feedback.html +6,Please share your feedback to the training by clicking on 'Training Feedback' and then 'New',請通過點擊“培訓反饋”,然後點擊“新建” -DocType: Mode of Payment Account,Default Account,預設帳戶 +DocType: Mode of Payment Account,Default Account,預設科目 apps/erpnext/erpnext/stock/doctype/item/item.py +302,Please select Sample Retention Warehouse in Stock Settings first,請先在庫存設置中選擇樣品保留倉庫 apps/erpnext/erpnext/accounts/doctype/loyalty_program/loyalty_program.js +62,Please select the Multiple Tier Program type for more than one collection rules.,請為多個收集規則選擇多層程序類型。 DocType: Payment Entry,Received Amount (Company Currency),收到的款項(公司幣種) @@ -1069,7 +1069,7 @@ DocType: Work Order Operation,Planned End Time,計劃結束時間 apps/erpnext/erpnext/accounts/doctype/account/account.py +100,Account with existing transaction cannot be converted to ledger,帳戶與現有的交易不能被轉換為總賬 apps/erpnext/erpnext/config/non_profit.py +33,Memebership Type Details,Memebership類型詳細信息 DocType: Delivery Note,Customer's Purchase Order No,客戶的採購訂單編號 -DocType: Clinical Procedure,Consume Stock,消費股票 +DocType: Clinical Procedure,Consume Stock,消費庫存 DocType: Budget,Budget Against,反對財政預算案 apps/erpnext/erpnext/stock/reorder_item.py +194,Auto Material Requests Generated,汽車材料的要求生成 apps/erpnext/erpnext/buying/doctype/supplier_quotation/supplier_quotation_list.js +7,Lost,丟失 @@ -1084,7 +1084,7 @@ DocType: Special Test Items,Particulars,細節 apps/erpnext/erpnext/hr/doctype/leave_application/leave_application.py +23,{0}: From {0} of type {1},{0}:從{0}類型{1} apps/erpnext/erpnext/controllers/buying_controller.py +399,Row {0}: Conversion Factor is mandatory,列#{0}:轉換係數是強制性的 apps/erpnext/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +353,"Multiple Price Rules exists with same criteria, please resolve conflict by assigning priority. Price Rules: {0}",海報價格規則,同樣的標準存在,請通過分配優先解決衝突。價格規則:{0} -DocType: Exchange Rate Revaluation,Exchange Rate Revaluation Account,匯率重估賬戶 +DocType: Exchange Rate Revaluation,Exchange Rate Revaluation Account,匯率重估科目 apps/erpnext/erpnext/manufacturing/doctype/bom/bom.py +539,Cannot deactivate or cancel BOM as it is linked with other BOMs,無法關閉或取消BOM,因為它是與其他材料明細表鏈接 apps/erpnext/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.js +106,Please select Company and Posting Date to getting entries,請選擇公司和發布日期以獲取條目 DocType: Asset,Maintenance,維護 @@ -1146,9 +1146,9 @@ apps/erpnext/erpnext/regional/report/eway_bill/eway_bill.py +163,Doc Name,文件 DocType: Expense Claim Detail,Expense Claim Type,費用報銷型 DocType: Shopping Cart Settings,Default settings for Shopping Cart,對購物車的預設設定 apps/erpnext/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.js +27,Add Timeslots,添加時代 -apps/erpnext/erpnext/stock/__init__.py +57,Please set Account in Warehouse {0} or Default Inventory Account in Company {1},請在倉庫{0}中設置帳戶或在公司{1}中設置默認庫存帳戶 +apps/erpnext/erpnext/stock/__init__.py +57,Please set Account in Warehouse {0} or Default Inventory Account in Company {1},請在倉庫{0}中設科目或在公司{1}中設置默認庫存科目 apps/erpnext/erpnext/assets/doctype/asset/depreciation.py +143,Asset scrapped via Journal Entry {0},通過資產日記帳分錄報廢{0} -DocType: Loan,Interest Income Account,利息收入賬戶 +DocType: Loan,Interest Income Account,利息收入科目 apps/erpnext/erpnext/hr/doctype/salary_structure/salary_structure.py +61,Max benefits should be greater than zero to dispense benefits,最大的好處應該大於零來分配好處 apps/erpnext/erpnext/non_profit/doctype/grant_application/grant_application.py +58,Review Invitation Sent,審核邀請已發送 DocType: Shift Assignment,Shift Assignment,班次分配 @@ -1167,7 +1167,7 @@ DocType: Account,Liability,責任 apps/erpnext/erpnext/hr/doctype/expense_claim/expense_claim.py +228,Sanctioned Amount cannot be greater than Claim Amount in Row {0}.,制裁金額不能大於索賠額行{0}。 apps/erpnext/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.html +14,Academic Term: ,學術期限: DocType: Salary Component,Do not include in total,不包括在內 -DocType: Company,Default Cost of Goods Sold Account,銷貨帳戶的預設成本 +DocType: Company,Default Cost of Goods Sold Account,銷貨成本科目 apps/erpnext/erpnext/stock/doctype/stock_entry/stock_entry.py +1287,Sample quantity {0} cannot be more than received quantity {1},採樣數量{0}不能超過接收數量{1} apps/erpnext/erpnext/stock/get_item_details.py +523,Price List not selected,未選擇價格列表 DocType: Request for Quotation Supplier,Send Email,發送電子郵件 @@ -1176,7 +1176,7 @@ DocType: Item,Max Sample Quantity,最大樣品量 apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +810,No Permission,無權限 DocType: Contract Fulfilment Checklist,Contract Fulfilment Checklist,合同履行清單 DocType: Vital Signs,Heart Rate / Pulse,心率/脈搏 -DocType: Company,Default Bank Account,預設銀行帳戶 +DocType: Company,Default Bank Account,預設銀行會計科目 apps/erpnext/erpnext/accounts/report/general_ledger/general_ledger.py +76,"To filter based on Party, select Party Type first",要根據黨的篩選,選擇黨第一類型 apps/erpnext/erpnext/controllers/sales_and_purchase_return.py +46,'Update Stock' can not be checked because items are not delivered via {0},不能勾選`更新庫存',因為項目未交付{0} DocType: Vehicle,Acquisition Date,採集日期 @@ -1202,7 +1202,7 @@ DocType: Item,Website Warehouse,網站倉庫 DocType: Payment Reconciliation,Minimum Invoice Amount,最小發票金額 apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py +112,{0} {1}: Cost Center {2} does not belong to Company {3},{0} {1}:成本中心{2}不屬於公司{3} apps/erpnext/erpnext/utilities/user_progress.py +92,Upload your letter head (Keep it web friendly as 900px by 100px),上傳你的信頭(保持網頁友好,900px乘100px) -apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py +89,{0} {1}: Account {2} cannot be a Group,{0} {1}帳戶{2}不能是一個組 +apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py +89,{0} {1}: Account {2} cannot be a Group,{0} {1}科目{2}不能是一個群組科目 apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +367,Timesheet {0} is already completed or cancelled,時間表{0}已完成或取消 apps/erpnext/erpnext/templates/pages/projects.html +42,No tasks,沒有任務 apps/erpnext/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py +81,Sales Invoice {0} created as paid,銷售發票{0}已創建為已付款 @@ -1282,7 +1282,7 @@ apps/erpnext/erpnext/projects/report/project_wise_stock_tracking/project_wise_st apps/erpnext/erpnext/config/selling.py +332,Point-of-Sale,銷售點 DocType: Fee Schedule,Fee Creation Status,費用創建狀態 DocType: Vehicle Log,Odometer Reading,里程表讀數 -apps/erpnext/erpnext/accounts/doctype/account/account.py +123,"Account balance already in Credit, you are not allowed to set 'Balance Must Be' as 'Debit'",帳戶餘額已歸為信用帳戶,不允許設為借方帳戶 +apps/erpnext/erpnext/accounts/doctype/account/account.py +123,"Account balance already in Credit, you are not allowed to set 'Balance Must Be' as 'Debit'",科目餘額已歸為貸方,不允許設為借方 DocType: Account,Balance must be,餘額必須 DocType: Notification Control,Expense Claim Rejected Message,報銷回絕訊息 ,Available Qty,可用數量 @@ -1349,9 +1349,9 @@ apps/erpnext/erpnext/stock/report/item_prices/item_prices.py +40,Sales Price Lis DocType: Healthcare Settings,"If checked, a customer will be created, mapped to Patient. Patient Invoices will be created against this Customer. You can also select existing Customer while creating Patient.",如果選中,將創建一個客戶,映射到患者。將針對該客戶創建病人發票。您也可以在創建患者時選擇現有客戶。 apps/erpnext/erpnext/accounts/doctype/loyalty_program/loyalty_program.py +63,Customer isn't enrolled in any Loyalty Program,客戶未加入任何忠誠度計劃 -DocType: Bank Reconciliation,Account Currency,賬戶幣種 +DocType: Bank Reconciliation,Account Currency,科目幣種 DocType: Lab Test,Sample ID,樣品編號 -apps/erpnext/erpnext/accounts/general_ledger.py +178,Please mention Round Off Account in Company,請註明舍入賬戶的公司 +apps/erpnext/erpnext/accounts/general_ledger.py +178,Please mention Round Off Account in Company,請註明舍入科目的公司 DocType: Purchase Receipt,Range,範圍 DocType: Supplier,Default Payable Accounts,預設應付帳款 apps/erpnext/erpnext/hr/doctype/attendance/attendance.py +52,Employee {0} is not active or does not exist,員工{0}不活躍或不存在 @@ -1471,7 +1471,7 @@ DocType: Repayment Schedule,Balance Loan Amount,平衡貸款額 apps/erpnext/erpnext/hr/doctype/employee_promotion/employee_promotion.js +132,Added to details,添加到細節 apps/erpnext/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.js +14,Schedule Course,課程時間表 DocType: Budget,Applicable on Material Request,適用於材料請求 -apps/erpnext/erpnext/setup/setup_wizard/operations/install_fixtures.py +194,Stock Options,股票期權 +apps/erpnext/erpnext/setup/setup_wizard/operations/install_fixtures.py +194,Stock Options,庫存期權 apps/erpnext/erpnext/selling/page/point_of_sale/point_of_sale.js +628,No Items added to cart,沒有項目已添加到購物車 DocType: Journal Entry Account,Expense Claim,報銷 apps/erpnext/erpnext/assets/doctype/asset/asset.js +352,Do you really want to restore this scrapped asset?,難道你真的想恢復這個報廢的資產? @@ -1491,7 +1491,7 @@ DocType: Landed Cost Purchase Receipt,Landed Cost Purchase Receipt,到岸成本 DocType: Company,Default Terms,默認條款 DocType: Supplier Scorecard Period,Criteria,標準 DocType: Packing Slip Item,Packing Slip Item,包裝單項目 -DocType: Purchase Invoice,Cash/Bank Account,現金/銀行帳戶 +DocType: Purchase Invoice,Cash/Bank Account,現金/銀行會計科目 DocType: Travel Itinerary,Train,培養 apps/erpnext/erpnext/public/js/queries.js +96,Please specify a {0},請指定{0} apps/erpnext/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +74,Removed items with no change in quantity or value.,刪除的項目在數量或價值沒有變化。 @@ -1516,7 +1516,7 @@ DocType: Agriculture Task,Urgent,緊急 apps/erpnext/erpnext/accounts/doctype/payment_entry/payment_entry.js +187,Please specify a valid Row ID for row {0} in table {1},請指定行{0}在表中的有效行ID {1} apps/erpnext/erpnext/buying/doctype/supplier_scorecard_criteria/supplier_scorecard_criteria.py +84,Unable to find variable: ,無法找到變量: apps/erpnext/erpnext/selling/page/point_of_sale/point_of_sale.js +893,Please select a field to edit from numpad,請選擇要從數字鍵盤編輯的字段 -apps/erpnext/erpnext/stock/doctype/item/item.py +293,Cannot be a fixed asset item as Stock Ledger is created.,不能成為股票分類賬創建的固定資產項目。 +apps/erpnext/erpnext/stock/doctype/item/item.py +293,Cannot be a fixed asset item as Stock Ledger is created.,不能成為庫存分類賬創建的固定資產項目。 apps/erpnext/erpnext/healthcare/doctype/inpatient_record/inpatient_record.js +7,Admit,承認 apps/erpnext/erpnext/setup/page/welcome_to_erpnext/welcome_to_erpnext.html +23,Go to the Desktop and start using ERPNext,轉到桌面和開始使用ERPNext apps/erpnext/erpnext/templates/pages/order.js +31,Pay Remaining,支付剩餘 @@ -1563,7 +1563,7 @@ DocType: Buying Settings,Material Transferred for Subcontract,轉包材料轉讓 DocType: Email Digest,Purchase Orders Items Overdue,採購訂單項目逾期 apps/erpnext/erpnext/accounts/page/pos/pos.js +1638,ZIP Code,郵政編碼 apps/erpnext/erpnext/controllers/selling_controller.py +265,Sales Order {0} is {1},銷售訂單{0} {1} -apps/erpnext/erpnext/hr/doctype/payroll_entry/payroll_entry.py +260,Select interest income account in loan {0},選擇貸款{0}中的利息收入帳戶 +apps/erpnext/erpnext/hr/doctype/payroll_entry/payroll_entry.py +260,Select interest income account in loan {0},選擇貸款{0}中的利息收入科目 DocType: Opportunity,Contact Info,聯絡方式 apps/erpnext/erpnext/config/stock.py +322,Making Stock Entries,製作Stock條目 apps/erpnext/erpnext/hr/doctype/employee_promotion/employee_promotion.py +15,Cannot promote Employee with status Left,無法提升狀態為Left的員工 @@ -1681,10 +1681,10 @@ apps/erpnext/erpnext/accounts/page/pos/pos.js +2530,"Payment Mode is not configu apps/erpnext/erpnext/buying/utils.py +74,Same item cannot be entered multiple times.,同一項目不能輸入多次。 apps/erpnext/erpnext/accounts/doctype/account/account_tree.js +30,"Further accounts can be made under Groups, but entries can be made against non-Groups",進一步帳戶可以根據組進行,但條目可針對非組進行 DocType: Lead,Lead,潛在客戶 -DocType: Email Digest,Payables,應付賬款 +DocType: Email Digest,Payables,應付帳款 DocType: Course,Course Intro,課程介紹 DocType: Amazon MWS Settings,MWS Auth Token,MWS Auth Token -apps/erpnext/erpnext/stock/doctype/batch/batch.js +105,Stock Entry {0} created,股票輸入{0}創建 +apps/erpnext/erpnext/stock/doctype/batch/batch.js +105,Stock Entry {0} created,庫存輸入{0}創建 apps/erpnext/erpnext/accounts/doctype/loyalty_program/loyalty_program.py +110,You don't have enought Loyalty Points to redeem,您沒有獲得忠誠度積分兌換 apps/erpnext/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +23,Please set associated account in Tax Withholding Category {0} against Company {1},請在針對公司{1}的預扣稅分類{0}中設置關聯帳戶 apps/erpnext/erpnext/controllers/buying_controller.py +405,Row #{0}: Rejected Qty can not be entered in Purchase Return,行#{0}:駁回採購退貨數量不能進入 @@ -1764,11 +1764,11 @@ DocType: Work Order,Qty To Manufacture,製造數量 DocType: Buying Settings,Maintain same rate throughout purchase cycle,在整個採購週期價格保持一致 DocType: Opportunity Item,Opportunity Item,項目的機會 ,Student and Guardian Contact Details,學生和監護人聯繫方式 -apps/erpnext/erpnext/accounts/doctype/account/account.js +51,Merge Account,合併帳戶 +apps/erpnext/erpnext/accounts/doctype/account/account.js +51,Merge Account,合併科目 apps/erpnext/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py +53,Row {0}: For supplier {0} Email Address is required to send email,行{0}:對於供應商{0}的電郵地址發送電子郵件 apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py +76,Temporary Opening,臨時開通 ,Employee Leave Balance,員工休假餘額 -apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py +148,Balance for Account {0} must always be {1},帳戶{0}的餘額必須始終為{1} +apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py +148,Balance for Account {0} must always be {1},科目{0}的餘額必須始終為{1} DocType: Patient Appointment,More Info,更多訊息 apps/erpnext/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +181,Valuation Rate required for Item in row {0},行對項目所需的估值速率{0} DocType: Supplier Scorecard,Scorecard Actions,記分卡操作 @@ -1841,7 +1841,7 @@ DocType: Purchase Invoice Item,Item Tax Rate,項目稅率 apps/erpnext/erpnext/regional/report/eway_bill/eway_bill.py +176,From Party Name,來自黨名 DocType: Student Group Student,Group Roll Number,組卷編號 DocType: Student Group Student,Group Roll Number,組卷編號 -apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +177,"For {0}, only credit accounts can be linked against another debit entry",{0},只有貸方帳戶可以連接另一個借方分錄 +apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +177,"For {0}, only credit accounts can be linked against another debit entry",{0},只有貸方科目可以連接另一個借方分錄 apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +660,Delivery Note {0} is not submitted,送貨單{0}未提交 apps/erpnext/erpnext/stock/get_item_details.py +167,Item {0} must be a Sub-contracted Item,項{0}必須是一個小項目簽約 apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py +44,Capital Equipments,資本設備 @@ -1856,7 +1856,7 @@ DocType: Employee,Department and Grade,部門和年級 DocType: Sales Invoice Item,Edit Description,編輯說明 ,Team Updates,團隊更新 apps/erpnext/erpnext/accounts/doctype/payment_order/payment_order.js +39,For Supplier,對供應商 -DocType: Account,Setting Account Type helps in selecting this Account in transactions.,設置帳戶類型有助於在交易中選擇該帳戶。 +DocType: Account,Setting Account Type helps in selecting this Account in transactions.,設置會計科目類型有助於在交易中選擇該科目。 DocType: Purchase Invoice,Grand Total (Company Currency),總計(公司貨幣) apps/erpnext/erpnext/accounts/doctype/cheque_print_template/cheque_print_template.js +9,Create Print Format,創建打印格式 apps/erpnext/erpnext/education/doctype/fee_schedule/fee_schedule_list.js +5,Fee Created,創建費用 @@ -1914,7 +1914,7 @@ DocType: Stock Settings,Naming Series Prefix,命名系列前綴 DocType: Appraisal Template Goal,Appraisal Template Goal,考核目標模板 DocType: Salary Component,Earning,盈利 DocType: Supplier Scorecard,Scoring Criteria,評分標準 -DocType: Purchase Invoice,Party Account Currency,黨的賬戶幣種 +DocType: Purchase Invoice,Party Account Currency,黨的科目幣種 DocType: Delivery Trip,Total Estimated Distance,總估計距離 ,BOM Browser,BOM瀏覽器 apps/erpnext/erpnext/templates/emails/training_event.html +13,Please update your status for this training event,請更新此培訓活動的狀態 @@ -1929,7 +1929,7 @@ DocType: Inpatient Occupancy,Check In,報到 DocType: Maintenance Schedule Item,No of Visits,沒有訪問量的 apps/erpnext/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py +165,Maintenance Schedule {0} exists against {1},針對{1}存在維護計劃{0} apps/erpnext/erpnext/education/doctype/student_applicant/student_applicant.js +36,Enrolling student,招生學生 -apps/erpnext/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py +33,Currency of the Closing Account must be {0},在關閉帳戶的貨幣必須是{0} +apps/erpnext/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py +33,Currency of the Closing Account must be {0},關閉科目的貨幣必須是{0} apps/erpnext/erpnext/hr/doctype/appraisal_template/appraisal_template.py +21,Sum of points for all goals should be 100. It is {0},對所有目標點的總和應該是100。{0} DocType: Project,Start and End Dates,開始和結束日期 DocType: Contract Template Fulfilment Terms,Contract Template Fulfilment Terms,合同模板履行條款 @@ -2027,7 +2027,7 @@ DocType: Job Opening,"Job profile, qualifications required etc.",所需的工作 DocType: Journal Entry Account,Account Balance,帳戶餘額 apps/erpnext/erpnext/config/accounts.py +179,Tax Rule for transactions.,稅收規則進行的交易。 DocType: Rename Tool,Type of document to rename.,的文件類型進行重命名。 -apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py +53,{0} {1}: Customer is required against Receivable account {2},{0} {1}:需要客戶對應收賬款{2} +apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py +53,{0} {1}: Customer is required against Receivable account {2},{0} {1}:需要客戶對應收帳款{2} DocType: Purchase Invoice,Total Taxes and Charges (Company Currency),總稅費和費用(公司貨幣) DocType: Weather,Weather Parameter,天氣參數 apps/erpnext/erpnext/accounts/report/trial_balance/trial_balance.js +76,Show unclosed fiscal year's P&L balances,顯示未關閉的會計年度的盈虧平衡 @@ -2036,8 +2036,8 @@ apps/erpnext/erpnext/regional/india/utils.py +179,House rented dates should be a DocType: Clinical Procedure Template,Collection Details,收集細節 DocType: POS Profile,Allow Print Before Pay,付款前允許打印 DocType: Linked Soil Texture,Linked Soil Texture,連接的土壤紋理 -DocType: Shipping Rule,Shipping Account,送貨帳戶 -apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py +93,{0} {1}: Account {2} is inactive,{0} {1}帳戶{2}無效 +DocType: Shipping Rule,Shipping Account,送貨科目 +apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py +93,{0} {1}: Account {2} is inactive,{0} {1}科目{2}無效 apps/erpnext/erpnext/utilities/activation.py +82,Make Sales Orders to help you plan your work and deliver on-time,製作銷售訂單,以幫助你計劃你的工作和按時交付 DocType: Bank Statement Transaction Entry,Bank Transaction Entries,銀行交易分錄 DocType: Quality Inspection,Readings,閱讀 @@ -2130,7 +2130,7 @@ DocType: Timesheet Detail,Expected Hrs,預計的小時數 apps/erpnext/erpnext/config/non_profit.py +28,Memebership Details,Memebership細節 DocType: Leave Block List,Block Holidays on important days.,重要的日子中封鎖假期。 apps/erpnext/erpnext/healthcare/doctype/lab_test/lab_test.js +194,Please input all required Result Value(s),請輸入所有必需的結果值(s) -apps/erpnext/erpnext/accounts/report/accounts_receivable/accounts_receivable.js +142,Accounts Receivable Summary,應收賬款匯總 +apps/erpnext/erpnext/accounts/report/accounts_receivable/accounts_receivable.js +142,Accounts Receivable Summary,應收帳款匯總 DocType: POS Closing Voucher,Linked Invoices,鏈接的發票 DocType: Loan,Monthly Repayment Amount,每月還款額 apps/erpnext/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool_dashboard.html +9,Opening Invoices,打開發票 @@ -2257,11 +2257,11 @@ DocType: Loan,Applicant Type,申請人類型 DocType: Purchase Invoice,03-Deficiency in services,03-服務不足 DocType: Healthcare Settings,Default Medical Code Standard,默認醫療代碼標準 apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +267,Purchase Receipt {0} is not submitted,採購入庫單{0}未提交 -DocType: Company,Default Payable Account,預設應付賬款 +DocType: Company,Default Payable Account,預設應付帳款科目 apps/erpnext/erpnext/config/website.py +17,"Settings for online shopping cart such as shipping rules, price list etc.",設定線上購物車,如航運規則,價格表等 apps/erpnext/erpnext/controllers/website_list_for_contact.py +113,{0}% Billed,{0}%已開立帳單 apps/erpnext/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py +73,Reserved Qty,保留數量 -DocType: Party Account,Party Account,黨的帳戶 +DocType: Party Account,Party Account,參與者科目 apps/erpnext/erpnext/hr/doctype/staffing_plan/staffing_plan.py +142,Please select Company and Designation,請選擇公司和指定 apps/erpnext/erpnext/config/setup.py +116,Human Resources,人力資源 apps/erpnext/erpnext/education/doctype/student_applicant/student_applicant.js +17,Reject,拒絕 @@ -2283,7 +2283,7 @@ DocType: Customer,Default Price List,預設價格表 apps/erpnext/erpnext/assets/doctype/asset/asset.py +492,Asset Movement record {0} created,資產運動記錄{0}創建 apps/erpnext/erpnext/utilities/page/leaderboard/leaderboard.js +175,No items found.,未找到任何項目。 apps/erpnext/erpnext/accounts/doctype/fiscal_year/fiscal_year.py +51,You cannot delete Fiscal Year {0}. Fiscal Year {0} is set as default in Global Settings,您不能刪除會計年度{0}。會計年度{0}設置為默認的全局設置 -DocType: Share Transfer,Equity/Liability Account,股票/負債賬戶 +DocType: Share Transfer,Equity/Liability Account,庫存/負債科目 apps/erpnext/erpnext/setup/doctype/customer_group/customer_group.py +20,A customer with the same name already exists,一個同名的客戶已經存在 DocType: Contract,Inactive,待用 apps/erpnext/erpnext/hr/doctype/payroll_entry/payroll_entry.js +224,This will submit Salary Slips and create accrual Journal Entry. Do you want to proceed?,這將提交工資單,並創建權責發生製日記賬分錄。你想繼續嗎? @@ -2292,7 +2292,7 @@ DocType: Purchase Order,Order Confirmation No,訂單確認號 DocType: Purchase Invoice,Eligibility For ITC,適用於ITC的資格 DocType: Journal Entry,Entry Type,條目類型 ,Customer Credit Balance,客戶信用平衡 -apps/erpnext/erpnext/accounts/report/cash_flow/cash_flow.py +82,Net Change in Accounts Payable,應付賬款淨額變化 +apps/erpnext/erpnext/accounts/report/cash_flow/cash_flow.py +82,Net Change in Accounts Payable,應付帳款淨額變化 apps/erpnext/erpnext/selling/doctype/customer/customer.py +257,Credit limit has been crossed for customer {0} ({1}/{2}),客戶{0}({1} / {2})的信用額度已超過 apps/erpnext/erpnext/setup/doctype/authorization_rule/authorization_rule.py +42,Customer required for 'Customerwise Discount',需要' Customerwise折扣“客戶 apps/erpnext/erpnext/config/accounts.py +136,Update bank payment dates with journals.,更新與日記帳之銀行付款日期。 @@ -2313,7 +2313,7 @@ DocType: Special Test Template,Result Component,結果組件 apps/erpnext/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js +46,Warranty Claim,保修索賠 ,Lead Details,潛在客戶詳情 DocType: Salary Slip,Loan repayment,償還借款 -DocType: Share Transfer,Asset Account,資產賬戶 +DocType: Share Transfer,Asset Account,資產科目 DocType: Purchase Invoice,End date of current invoice's period,當前發票的期限的最後一天 DocType: Pricing Rule,Applicable For,適用 DocType: Lab Test,Technician Name,技術員姓名 @@ -2347,7 +2347,7 @@ DocType: Leave Type,Earned Leave,獲得休假 DocType: Employee,Salary Details,薪資明細 DocType: Territory,Territory Manager,區域經理 DocType: Packed Item,To Warehouse (Optional),倉庫(可選) -DocType: GST Settings,GST Accounts,GST賬戶 +DocType: GST Settings,GST Accounts,GST科目 DocType: Payment Entry,Paid Amount (Company Currency),支付的金額(公司貨幣) DocType: Purchase Invoice,Additional Discount,更多優惠 DocType: Selling Settings,Selling Settings,銷售設置 @@ -2382,12 +2382,12 @@ DocType: Material Request,Transferred,轉入 DocType: Vehicle,Doors,門 apps/erpnext/erpnext/setup/setup_wizard/operations/defaults_setup.py +118,ERPNext Setup Complete!,ERPNext設定完成! DocType: Healthcare Settings,Collect Fee for Patient Registration,收取病人登記費 -apps/erpnext/erpnext/stock/doctype/item/item.py +737,Cannot change Attributes after stock transaction. Make a new Item and transfer stock to the new Item,股票交易後不能更改屬性。創建一個新項目並將庫存轉移到新項目 +apps/erpnext/erpnext/stock/doctype/item/item.py +737,Cannot change Attributes after stock transaction. Make a new Item and transfer stock to the new Item,庫存交易後不能更改屬性。創建一個新項目並將庫存轉移到新項目 DocType: Course Assessment Criteria,Weightage,權重 DocType: Purchase Invoice,Tax Breakup,稅收分解 DocType: Employee,Joining Details,加入詳情 DocType: Member,Non Profit Member,非盈利會員 -apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py +67,{0} {1}: Cost Center is required for 'Profit and Loss' account {2}. Please set up a default Cost Center for the Company.,{0} {1}:需要的損益“賬戶成本中心{2}。請設置為公司默認的成本中心。 +apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py +67,{0} {1}: Cost Center is required for 'Profit and Loss' account {2}. Please set up a default Cost Center for the Company.,{0} {1}:需要的損益“科目成本中心{2}。請設置為公司默認的成本中心。 apps/erpnext/erpnext/selling/doctype/customer/customer.py +175,A Customer Group exists with same name please change the Customer name or rename the Customer Group,客戶群組存在相同名稱,請更改客戶名稱或重新命名客戶群組 DocType: Location,Area,區 apps/erpnext/erpnext/public/js/templates/contact_list.html +37,New Contact,新建聯絡人 @@ -2474,11 +2474,11 @@ apps/erpnext/erpnext/selling/page/point_of_sale/point_of_sale.js +901,Discount a apps/erpnext/erpnext/accounts/doctype/cost_center/cost_center_tree.js +26,"Number of new Cost Center, it will be included in the cost center name as a prefix",新成本中心的數量,它將作為前綴包含在成本中心名稱中 DocType: Sales Order,To Deliver and Bill,準備交貨及開立發票 DocType: Student Group,Instructors,教師 -DocType: GL Entry,Credit Amount in Account Currency,在賬戶幣金額 +DocType: GL Entry,Credit Amount in Account Currency,在科目幣金額 apps/erpnext/erpnext/manufacturing/doctype/bom/bom.py +631,BOM {0} must be submitted,BOM {0}必須提交 DocType: Authorization Control,Authorization Control,授權控制 apps/erpnext/erpnext/controllers/buying_controller.py +416,Row #{0}: Rejected Warehouse is mandatory against rejected Item {1},行#{0}:拒絕倉庫是強制性的反對否決項{1} -apps/erpnext/erpnext/controllers/stock_controller.py +96,"Warehouse {0} is not linked to any account, please mention the account in the warehouse record or set default inventory account in company {1}.",倉庫{0}未與任何帳戶關聯,請在倉庫記錄中提及該帳戶,或在公司{1}中設置默認庫存帳戶。 +apps/erpnext/erpnext/controllers/stock_controller.py +96,"Warehouse {0} is not linked to any account, please mention the account in the warehouse record or set default inventory account in company {1}.",倉庫{0}未與任何科目關聯,請在倉庫記錄中設定科目,或在公司{1}中設置默認庫存科目。 apps/erpnext/erpnext/utilities/activation.py +81,Manage your orders,管理您的訂單 DocType: Work Order Operation,Actual Time and Cost,實際時間和成本 apps/erpnext/erpnext/stock/doctype/material_request/material_request.py +57,Material Request of maximum {0} can be made for Item {1} against Sales Order {2},針對銷售訂單{2}的項目{1},最多可以有 {0} 被完成。 @@ -2514,14 +2514,14 @@ DocType: SMS Center,Create Receiver List,創建接收器列表 apps/erpnext/erpnext/assets/doctype/asset/asset.py +98,Available-for-use Date should be after purchase date,可供使用的日期應在購買日期之後 DocType: Vehicle,Wheels,車輪 DocType: Packing Slip,To Package No.,以包號 -DocType: Sales Invoice Item,Deferred Revenue Account,遞延收入帳戶 +DocType: Sales Invoice Item,Deferred Revenue Account,遞延收入科目 DocType: Production Plan,Material Requests,材料要求 DocType: Warranty Claim,Issue Date,發行日期 DocType: Activity Cost,Activity Cost,項目成本 DocType: Sales Invoice Timesheet,Timesheet Detail,詳細時間表 DocType: Purchase Receipt Item Supplied,Consumed Qty,消耗的數量 apps/erpnext/erpnext/setup/setup_wizard/data/industry_type.py +52,Telecommunications,電信 -apps/erpnext/erpnext/accounts/party.py +292,Billing currency must be equal to either default company's currency or party account currency,帳單貨幣必須等於默認公司的貨幣或帳戶幣種 +apps/erpnext/erpnext/accounts/party.py +292,Billing currency must be equal to either default company's currency or party account currency,帳單貨幣必須等於默認公司的貨幣或科目幣種 DocType: Packing Slip,Indicates that the package is a part of this delivery (Only Draft),表示該包是這個交付的一部分(僅草案) apps/erpnext/erpnext/controllers/accounts_controller.py +786,Row {0}: Due Date cannot be before posting date,行{0}:到期日期不能在發布日期之前 apps/erpnext/erpnext/accounts/doctype/payment_request/payment_request.js +37,Make Payment Entry,製作付款分錄 @@ -2535,7 +2535,7 @@ apps/erpnext/erpnext/config/accounts.py +209,Tree of financial Cost Centers.,財 apps/erpnext/erpnext/regional/report/eway_bill/eway_bill.py +151,Sub Type,子類型 DocType: Serial No,Delivery Document No,交貨證明文件號碼 DocType: Sales Order Item,Ensure Delivery Based on Produced Serial No,確保基於生產的序列號的交貨 -apps/erpnext/erpnext/assets/doctype/asset/depreciation.py +197,Please set 'Gain/Loss Account on Asset Disposal' in Company {0},請公司制定“關於資產處置收益/損失帳戶”{0} +apps/erpnext/erpnext/assets/doctype/asset/depreciation.py +197,Please set 'Gain/Loss Account on Asset Disposal' in Company {0},請公司制定“關於資產處置收益/損失科目”{0} DocType: Landed Cost Voucher,Get Items From Purchase Receipts,從採購入庫單取得項目 DocType: Serial No,Creation Date,創建日期 apps/erpnext/erpnext/assets/doctype/asset_movement/asset_movement.py +55,Target Location is required for the asset {0},目標位置是資產{0}所必需的 @@ -2569,7 +2569,7 @@ DocType: Bank Guarantee,Margin Money,保證金 DocType: Budget,Budget,預算 apps/erpnext/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js +83,Set Open,設置打開 apps/erpnext/erpnext/stock/doctype/item/item.py +287,Fixed Asset Item must be a non-stock item.,固定資產項目必須是一個非庫存項目。 -apps/erpnext/erpnext/accounts/doctype/budget/budget.py +60,"Budget cannot be assigned against {0}, as it's not an Income or Expense account",財政預算案不能對{0}指定的,因為它不是一個收入或支出帳戶 +apps/erpnext/erpnext/accounts/doctype/budget/budget.py +60,"Budget cannot be assigned against {0}, as it's not an Income or Expense account",財政預算案不能對{0}指定的,因為它不是一個收入或支出科目 apps/erpnext/erpnext/hr/utils.py +228,Max exemption amount for {0} is {1},{0}的最大免除金額為{1} apps/erpnext/erpnext/selling/report/sales_person_target_variance_item_group_wise/sales_person_target_variance_item_group_wise.py +51,Achieved,已實現 DocType: Student Admission,Application Form Route,申請表路線 @@ -2644,15 +2644,15 @@ DocType: Loan Application,Total Payable Amount,合計應付額 DocType: Task,Expected Time (in hours),預期時間(以小時計) DocType: Item Reorder,Check in (group),檢查(組) ,Qty to Order,訂購數量 -DocType: Period Closing Voucher,"The account head under Liability or Equity, in which Profit/Loss will be booked",負債或權益下的帳戶頭,其中利潤/虧損將被黃牌警告 -apps/erpnext/erpnext/accounts/doctype/budget/budget.py +44,Another Budget record '{0}' already exists against {1} '{2}' and account '{3}' for fiscal year {4},對於財務年度{4},{1}'{2}'和帳戶“{3}”已存在另一個預算記錄“{0}” +DocType: Period Closing Voucher,"The account head under Liability or Equity, in which Profit/Loss will be booked",負債或權益下的科目頭,其中利潤/虧損將被黃牌警告 +apps/erpnext/erpnext/accounts/doctype/budget/budget.py +44,Another Budget record '{0}' already exists against {1} '{2}' and account '{3}' for fiscal year {4},對於財務年度{4},{1}'{2}'和科目“{3}”已存在另一個預算記錄“{0}” apps/erpnext/erpnext/config/projects.py +36,Gantt chart of all tasks.,所有任務的甘特圖。 DocType: Opportunity,Mins to First Response,分鐘為第一個反應 DocType: Pricing Rule,Margin Type,保證金類型 apps/erpnext/erpnext/projects/doctype/project/project_dashboard.html +15,{0} hours,{0}小時 DocType: Course,Default Grading Scale,默認等級規模 DocType: Appraisal,For Employee Name,對於員工姓名 -DocType: Woocommerce Settings,Tax Account,稅收帳戶 +DocType: Woocommerce Settings,Tax Account,稅收科目 DocType: C-Form Invoice Detail,Invoice No,發票號碼 DocType: Room,Room Name,房間名稱 DocType: Prescription Duration,Prescription Duration,處方時間 @@ -2704,7 +2704,7 @@ apps/erpnext/erpnext/accounts/doctype/payment_entry/payment_entry.py +389,Amount ,Quotation Trends,報價趨勢 apps/erpnext/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +166,Item Group not mentioned in item master for item {0},項目{0}之項目主檔未提及之項目群組 DocType: GoCardless Mandate,GoCardless Mandate,GoCardless任務 -apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +440,Debit To account must be a Receivable account,借方帳戶必須是應收帳款帳戶 +apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +440,Debit To account must be a Receivable account,借方科目必須是應收帳款科目 DocType: Shipping Rule,Shipping Amount,航運量 DocType: Supplier Scorecard Period,Period Score,期間得分 apps/erpnext/erpnext/public/js/event.js +19,Add Customers,添加客戶 @@ -2777,7 +2777,7 @@ apps/erpnext/erpnext/accounts/doctype/fiscal_year/fiscal_year.py +22,{0} is now apps/erpnext/erpnext/projects/doctype/task/task.js +45,Expense Claims,報銷 DocType: Employee Tax Exemption Declaration,Total Exemption Amount,免稅總額 ,BOM Search,BOM搜索 -DocType: Project,Total Consumed Material Cost (via Stock Entry),總消耗材料成本(通過股票輸入) +DocType: Project,Total Consumed Material Cost (via Stock Entry),總消耗材料成本(通過庫存輸入) DocType: Subscription,Subscription Period,訂閱期 apps/erpnext/erpnext/hr/doctype/leave_application/leave_application.js +169,To Date cannot be less than From Date,迄今不能少於起始日期 DocType: Item,"Publish ""In Stock"" or ""Not in Stock"" on Hub based on stock available in this warehouse.",基於倉庫中的庫存,在Hub上發布“庫存”或“庫存”。 @@ -2786,7 +2786,7 @@ apps/erpnext/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_ DocType: Workstation,Wages per hour,時薪 apps/erpnext/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +47,Stock balance in Batch {0} will become negative {1} for Item {2} at Warehouse {3},在批量庫存餘額{0}將成為負{1}的在倉庫項目{2} {3} apps/erpnext/erpnext/templates/emails/reorder_item.html +1,Following Material Requests have been raised automatically based on Item's re-order level,下列資料的要求已自動根據項目的重新排序水平的提高 -apps/erpnext/erpnext/controllers/accounts_controller.py +376,Account {0} is invalid. Account Currency must be {1},帳戶{0}是無效的。帳戶貨幣必須是{1} +apps/erpnext/erpnext/controllers/accounts_controller.py +376,Account {0} is invalid. Account Currency must be {1},科目{0}是無效的。科目貨幣必須是{1} apps/erpnext/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.py +31,From Date {0} cannot be after employee's relieving Date {1},起始日期{0}不能在員工解除日期之後{1} DocType: Supplier,Is Internal Supplier,是內部供應商 DocType: Employee,Create User Permission,創建用戶權限 @@ -2813,7 +2813,7 @@ apps/erpnext/erpnext/setup/doctype/email_digest/email_digest.js +64,disabled use apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +970,Quotation,報價 apps/erpnext/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js +1041,Cannot set a received RFQ to No Quote,無法將收到的詢價單設置為無報價 DocType: Salary Slip,Total Deduction,扣除總額 -apps/erpnext/erpnext/accounts/report/general_ledger/general_ledger.py +22,Select an account to print in account currency,選擇一個賬戶以賬戶貨幣進行打印 +apps/erpnext/erpnext/accounts/report/general_ledger/general_ledger.py +22,Select an account to print in account currency,選擇一個科目以科目貨幣進行打印 ,Production Analytics,生產Analytics(分析) apps/erpnext/erpnext/healthcare/doctype/patient/patient_dashboard.py +6,This is based on transactions against this Patient. See timeline below for details,這是基於對這個病人的交易。有關詳情,請參閱下面的時間表 apps/erpnext/erpnext/controllers/sales_and_purchase_return.py +136,Item {0} has already been returned,項{0}已被退回 @@ -2852,7 +2852,7 @@ DocType: BOM,Scrap Material Cost,廢料成本 apps/erpnext/erpnext/stock/doctype/serial_no/serial_no.py +243,Serial No {0} does not belong to any Warehouse,序列號{0}不屬於任何倉庫 DocType: Grant Application,Email Notification Sent,電子郵件通知已發送 DocType: Purchase Invoice,In Words (Company Currency),大寫(Company Currency) -apps/erpnext/erpnext/accounts/doctype/bank_account/bank_account.py +24,Company is manadatory for company account,公司是公司賬戶的管理者 +apps/erpnext/erpnext/accounts/doctype/bank_account/bank_account.py +24,Company is manadatory for company account,公司是公司科目的管理者 apps/erpnext/erpnext/buying/doctype/purchase_order/purchase_order.js +1092,"Item Code, warehouse, quantity are required on row",在行上需要項目代碼,倉庫,數量 DocType: Bank Guarantee,Supplier,供應商 apps/erpnext/erpnext/hr/doctype/department/department.js +9,This is a root department and cannot be edited.,這是根部門,無法編輯。 @@ -2861,7 +2861,7 @@ apps/erpnext/erpnext/crm/report/lead_conversion_time/lead_conversion_time.py +53 apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py +113,Miscellaneous Expenses,雜項開支 DocType: Global Defaults,Default Company,預設公司 DocType: Company,Transactions Annual History,交易年曆 -apps/erpnext/erpnext/controllers/stock_controller.py +231,Expense or Difference account is mandatory for Item {0} as it impacts overall stock value,對項目{0}而言, 費用或差異帳戶是強制必填的,因為它影響整個庫存總值。 +apps/erpnext/erpnext/controllers/stock_controller.py +231,Expense or Difference account is mandatory for Item {0} as it impacts overall stock value,對項目{0}而言, 費用或差異科目是強制必填的,因為它影響整個庫存總值。 DocType: Bank,Bank Name,銀行名稱 apps/erpnext/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py +78,-Above,-以上 apps/erpnext/erpnext/selling/doctype/sales_order/sales_order.js +1301,Leave the field empty to make purchase orders for all suppliers,將該字段留空以為所有供應商下達採購訂單 @@ -2891,7 +2891,7 @@ DocType: Payment Entry,Unallocated Amount,未分配金額 apps/erpnext/erpnext/accounts/doctype/budget/budget.py +77,Please enable Applicable on Purchase Order and Applicable on Booking Actual Expenses,請啟用適用於採購訂單並適用於預訂實際費用 apps/erpnext/erpnext/templates/includes/product_page.js +101,Cannot find a matching Item. Please select some other value for {0}.,無法找到匹配的項目。請選擇其他值{0}。 DocType: POS Profile,Taxes and Charges,稅收和收費 -DocType: Item,"A Product or a Service that is bought, sold or kept in stock.",產品或服務已購買,出售或持有的股票。 +DocType: Item,"A Product or a Service that is bought, sold or kept in stock.",產品或服務已購買,出售或持有的庫存。 apps/erpnext/erpnext/hr/page/team_updates/team_updates.js +44,No more updates,沒有更多的更新 apps/erpnext/erpnext/accounts/doctype/payment_entry/payment_entry.js +184,Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row,不能選擇充電式為'在上一行量'或'在上一行總'的第一行 apps/erpnext/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard_dashboard.py +6,This covers all scorecards tied to this Setup,這涵蓋了與此安裝程序相關的所有記分卡 @@ -2929,7 +2929,7 @@ apps/erpnext/erpnext/education/doctype/student_group_creation_tool/student_group apps/erpnext/erpnext/education/doctype/student_group_creation_tool/student_group_creation_tool.py +77,{0} Student Groups created.,{0}創建學生組。 DocType: Sales Invoice,Total Billing Amount,總結算金額 apps/erpnext/erpnext/education/doctype/fee_schedule/fee_schedule.py +50,Program in the Fee Structure and Student Group {0} are different.,費用結構和學生組{0}中的課程是不同的。 -DocType: Bank Statement Transaction Entry,Receivable Account,應收賬款 +DocType: Bank Statement Transaction Entry,Receivable Account,應收帳款 apps/erpnext/erpnext/stock/doctype/item_price/item_price.py +31,Valid From Date must be lesser than Valid Upto Date.,有效起始日期必須小於有效起始日期。 apps/erpnext/erpnext/controllers/accounts_controller.py +689,Row #{0}: Asset {1} is already {2},行#{0}:資產{1}已經是{2} DocType: Quotation Item,Stock Balance,庫存餘額 @@ -2939,13 +2939,13 @@ DocType: Expense Claim Detail,Expense Claim Detail,報銷詳情 DocType: Purchase Invoice,TRIPLICATE FOR SUPPLIER,供應商提供服務 DocType: Exchange Rate Revaluation Account,New Balance In Base Currency,基礎貨幣的新平衡 DocType: Crop Cycle,This will be day 1 of the crop cycle,這將是作物週期的第一天 -apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +915,Please select correct account,請選擇正確的帳戶 +apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +915,Please select correct account,請選擇正確的科目 DocType: Salary Structure Assignment,Salary Structure Assignment,薪酬結構分配 DocType: Purchase Invoice Item,Weight UOM,重量計量單位 apps/erpnext/erpnext/config/accounts.py +435,List of available Shareholders with folio numbers,包含folio號碼的可用股東名單 DocType: Salary Structure Employee,Salary Structure Employee,薪資結構員工 apps/erpnext/erpnext/stock/report/stock_balance/stock_balance.js +62,Show Variant Attributes,顯示變體屬性 -apps/erpnext/erpnext/accounts/doctype/payment_request/payment_request.py +48,The payment gateway account in plan {0} is different from the payment gateway account in this payment request,計劃{0}中的支付網關帳戶與此付款請求中的支付網關帳戶不同 +apps/erpnext/erpnext/accounts/doctype/payment_request/payment_request.py +48,The payment gateway account in plan {0} is different from the payment gateway account in this payment request,計劃{0}中的支付閘道科目與此付款請求中的支付閘道科目不同 DocType: Course,Course Name,課程名 apps/erpnext/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +50,No Tax Withholding data found for the current Fiscal Year.,未找到當前財年的預扣稅數據。 DocType: Employee Leave Approver,Users who can approve a specific employee's leave applications,用戶可以批准特定員工的休假申請 @@ -2989,14 +2989,14 @@ apps/erpnext/erpnext/templates/pages/product_search.html +3,Product Search,產 DocType: Cashier Closing,To Time,要時間 apps/erpnext/erpnext/hr/utils.py +202,) for {0},)為{0} DocType: Authorization Rule,Approving Role (above authorized value),批准角色(上述授權值) -apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +147,Credit To account must be a Payable account,信用帳戶必須是應付賬款 +apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +147,Credit To account must be a Payable account,信用科目必須是應付帳款 DocType: Loan,Total Amount Paid,總金額支付 DocType: Asset,Insurance End Date,保險終止日期 apps/erpnext/erpnext/education/doctype/student_applicant/student_applicant.py +43,Please select Student Admission which is mandatory for the paid student applicant,請選擇付費學生申請者必須入學的學生 apps/erpnext/erpnext/manufacturing/doctype/bom/bom.py +370,BOM recursion: {0} cannot be parent or child of {2},BOM遞歸: {0}不能父母或兒童{2} apps/erpnext/erpnext/accounts/doctype/cost_center/cost_center_tree.js +40,Budget List,預算清單 DocType: Work Order Operation,Completed Qty,完成數量 -apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +180,"For {0}, only debit accounts can be linked against another credit entry",{0},只有借方帳戶可以連接另一個貸方分錄 +apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +180,"For {0}, only debit accounts can be linked against another credit entry",{0},只有借方科目可以連接另一個貸方分錄 DocType: Manufacturing Settings,Allow Overtime,允許加班 apps/erpnext/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +149,"Serialized Item {0} cannot be updated using Stock Reconciliation, please use Stock Entry",序列化項目{0}無法使用庫存調節更新,請使用庫存條目 apps/erpnext/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +149,"Serialized Item {0} cannot be updated using Stock Reconciliation, please use Stock Entry",序列化項目{0}無法使用庫存調節更新,請使用庫存條目 @@ -3010,7 +3010,7 @@ apps/erpnext/erpnext/config/integrations.py +13,GoCardless payment gateway setti apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py +129,Exchange Gain/Loss,兌換收益/損失 DocType: Opportunity,Lost Reason,失落的原因 DocType: Amazon MWS Settings,Enable Amazon,啟用亞馬遜 -apps/erpnext/erpnext/controllers/accounts_controller.py +322,Row #{0}: Account {1} does not belong to company {2},行#{0}:帳戶{1}不屬於公司{2} +apps/erpnext/erpnext/controllers/accounts_controller.py +322,Row #{0}: Account {1} does not belong to company {2},行#{0}:科目{1}不屬於公司{2} apps/erpnext/erpnext/setup/doctype/naming_series/naming_series.py +30,Unable to find DocType {0},無法找到DocType {0} DocType: Quality Inspection,Sample Size,樣本大小 apps/erpnext/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +47,Please enter Receipt Document,請輸入收據憑證 @@ -3056,7 +3056,7 @@ DocType: Timesheet Detail,Costing Amount,成本核算金額 DocType: Student Admission Program,Application Fee,報名費 apps/erpnext/erpnext/hr/doctype/payroll_entry/payroll_entry.js +75,Submit Salary Slip,提交工資單 apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js +13,On Hold,等候接聽 -DocType: Account,Inter Company Account,Inter公司帳戶 +DocType: Account,Inter Company Account,公司內帳戶 apps/erpnext/erpnext/stock/doctype/item_price/item_price.js +17,Import in Bulk,進口散裝 DocType: Sales Partner,Address & Contacts,地址及聯絡方式 DocType: SMS Log,Sender Name,發件人名稱 @@ -3108,7 +3108,7 @@ DocType: BOM,"Specify the operations, operating cost and give a unique Operation DocType: Travel Request,Any other details,任何其他細節 apps/erpnext/erpnext/controllers/status_updater.py +207,This document is over limit by {0} {1} for item {4}. Are you making another {3} against the same {2}?,這份文件是超過限制,通過{0} {1}項{4}。你在做另一個{3}對同一{2}? apps/erpnext/erpnext/public/js/controllers/transaction.js +1288,Please set recurring after saving,請設置保存後復發 -apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +874,Select change amount account,選擇變化量賬戶 +apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +874,Select change amount account,選擇變化量科目 DocType: Purchase Invoice,Price List Currency,價格表之貨幣 DocType: Naming Series,User must always select,用戶必須始終選擇 DocType: Stock Settings,Allow Negative Stock,允許負庫存 @@ -3148,7 +3148,7 @@ apps/erpnext/erpnext/accounts/report/general_ledger/general_ledger.py +56,Group apps/erpnext/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js +391,Are you sure you want to cancel this appointment?,你確定要取消這個預約嗎? DocType: Hotel Room Pricing Package,Hotel Room Pricing Package,酒店房間價格套餐 apps/erpnext/erpnext/selling/page/sales_funnel/sales_funnel.js +42,Sales Pipeline,銷售渠道 -apps/erpnext/erpnext/hr/doctype/payroll_entry/payroll_entry.py +167,Please set default account in Salary Component {0},請薪酬部分設置默認帳戶{0} +apps/erpnext/erpnext/hr/doctype/payroll_entry/payroll_entry.py +167,Please set default account in Salary Component {0},請薪酬部分設置默認科目{0} apps/erpnext/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py +200,Please select BOM for Item in Row {0},請行選擇BOM為項目{0} apps/erpnext/erpnext/accounts/doctype/subscription/subscription.js +13,Fetch Subscription Updates,獲取訂閱更新 apps/erpnext/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py +28,Account {0} does not match with Company {1} in Mode of Account: {2},帳戶{0}與帳戶模式{2}中的公司{1}不符 @@ -3183,7 +3183,7 @@ apps/erpnext/erpnext/manufacturing/doctype/work_order/work_order.js +232,For Job apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +1556,Prescriptions,處方 DocType: Payment Gateway Account,Payment Account,付款帳號 apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +1112,Please specify Company to proceed,請註明公司以處理 -apps/erpnext/erpnext/accounts/report/cash_flow/cash_flow.py +81,Net Change in Accounts Receivable,應收賬款淨額變化 +apps/erpnext/erpnext/accounts/report/cash_flow/cash_flow.py +81,Net Change in Accounts Receivable,應收帳款淨額變化 apps/erpnext/erpnext/setup/setup_wizard/operations/install_fixtures.py +66,Compensatory Off,補假 DocType: Job Offer,Accepted,接受的 DocType: POS Closing Voucher,Sales Invoices Summary,銷售發票摘要 @@ -3225,7 +3225,7 @@ DocType: Support Search Source,Result Preview Field,結果預覽字段 DocType: Item Price,Packing Unit,包裝單位 DocType: Subscription,Trialling,試用 DocType: Sales Invoice Item,Deferred Revenue,遞延收入 -DocType: Shopify Settings,Cash Account will used for Sales Invoice creation,現金帳戶將用於創建銷售發票 +DocType: Shopify Settings,Cash Account will used for Sales Invoice creation,現金科目將用於創建銷售發票 DocType: Employee Tax Exemption Declaration Category,Exemption Sub Category,豁免子類別 DocType: Member,Membership Expiry Date,會員到期日 apps/erpnext/erpnext/controllers/sales_and_purchase_return.py +134,{0} must be negative in return document,{0}必須返回文檔中負 @@ -3355,17 +3355,17 @@ DocType: Employee Separation,Employee Separation,員工分離 DocType: BOM Item,Original Item,原始項目 DocType: Purchase Receipt Item,Recd Quantity,到貨數量 apps/erpnext/erpnext/education/doctype/program_enrollment/program_enrollment.py +64,Fee Records Created - {0},費紀錄創造 - {0} -DocType: Asset Category Account,Asset Category Account,資產類別的帳戶 +DocType: Asset Category Account,Asset Category Account,資產類別的科目 apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +1024,Row #{0} (Payment Table): Amount must be positive,行#{0}(付款表):金額必須為正值 apps/erpnext/erpnext/manufacturing/doctype/production_order/production_order.py +137,Cannot produce more Item {0} than Sales Order quantity {1},無法產生更多的項目{0}不是銷售訂單數量{1} apps/erpnext/erpnext/stock/doctype/item/item.js +446,Select Attribute Values,選擇屬性值 DocType: Purchase Invoice,Reason For Issuing document,簽發文件的原因 -apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +583,Stock Entry {0} is not submitted,股票輸入{0}不提交 -DocType: Payment Reconciliation,Bank / Cash Account,銀行/現金帳戶 +apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +583,Stock Entry {0} is not submitted,庫存輸入{0}不提交 +DocType: Payment Reconciliation,Bank / Cash Account,銀行/現金科目 apps/erpnext/erpnext/crm/doctype/lead/lead.py +47,Next Contact By cannot be same as the Lead Email Address,接著聯繫到不能相同鉛郵箱地址 DocType: Tax Rule,Billing City,結算城市 DocType: Asset,Manual,手冊 -DocType: Salary Component Account,Salary Component Account,薪金部分賬戶 +DocType: Salary Component Account,Salary Component Account,薪金部分科目 DocType: Global Defaults,Hide Currency Symbol,隱藏貨幣符號 apps/erpnext/erpnext/selling/page/sales_funnel/sales_funnel.js +281,Sales Opportunities by Source,來源的銷售機會 apps/erpnext/erpnext/config/accounts.py +287,"e.g. Bank, Cash, Credit Card",例如:銀行,現金,信用卡 @@ -3449,7 +3449,7 @@ DocType: Purchase Invoice Item,Received Qty,到貨數量 DocType: Stock Entry Detail,Serial No / Batch,序列號/批次 apps/erpnext/erpnext/selling/doctype/sales_order/sales_order.py +359,Not Paid and Not Delivered,沒有支付,未送達 DocType: Product Bundle,Parent Item,父項目 -DocType: Account,Account Type,帳戶類型 +DocType: Account,Account Type,科目類型 DocType: Shopify Settings,Webhooks Details,Webhooks詳細信息 apps/erpnext/erpnext/templates/pages/projects.html +58,No time sheets,沒有考勤表 DocType: GoCardless Mandate,GoCardless Customer,GoCardless客戶 @@ -3476,7 +3476,7 @@ apps/erpnext/erpnext/manufacturing/doctype/job_card/job_card.js +26,Start Job, apps/erpnext/erpnext/assets/doctype/asset_movement/asset_movement.py +32,Serial no is required for the asset {0},資產{0}需要序列號 apps/erpnext/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py +43,Disabled template must not be default template,殘疾人模板必須不能默認模板 apps/erpnext/erpnext/manufacturing/doctype/production_plan/production_plan.py +542,For row {0}: Enter planned qty,對於行{0}:輸入計劃的數量 -DocType: Account,Income Account,收入帳戶 +DocType: Account,Income Account,收入科目 DocType: Payment Request,Amount in customer's currency,量客戶的貨幣 apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +880,Delivery,交貨 DocType: Stock Reconciliation Item,Current Qty,目前數量 @@ -3488,7 +3488,7 @@ DocType: Appraisal Goal,Key Responsibility Area,關鍵責任區 DocType: Delivery Trip,Distance UOM,距離UOM apps/erpnext/erpnext/utilities/activation.py +127,"Student Batches help you track attendance, assessments and fees for students",學生批幫助您跟踪學生的出勤,評估和費用 DocType: Payment Entry,Total Allocated Amount,總撥款額 -apps/erpnext/erpnext/setup/doctype/company/company.py +163,Set default inventory account for perpetual inventory,設置永久庫存的默認庫存帳戶 +apps/erpnext/erpnext/setup/doctype/company/company.py +163,Set default inventory account for perpetual inventory,設置永久庫存的默認庫存科目 apps/erpnext/erpnext/stock/doctype/serial_no/serial_no.py +261,"Cannot deliver Serial No {0} of item {1} as it is reserved to \ fullfill Sales Order {2}",無法提供項目{1}的序列號{0},因為它保留在\ fullfill銷售訂單{2}中 DocType: Item Reorder,Material Request Type,材料需求類型 @@ -3532,7 +3532,7 @@ DocType: Task,% Progress,%進展 apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py +130,Gain/Loss on Asset Disposal,在資產處置收益/損失 apps/erpnext/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.js +24,"Only the Student Applicant with the status ""Approved"" will be selected in the table below.",下表中將只選擇狀態為“已批准”的學生申請人。 DocType: Tax Withholding Category,Rates,價格 -apps/erpnext/erpnext/regional/report/fichier_des_ecritures_comptables_[fec]/fichier_des_ecritures_comptables_[fec].py +121,Account number for account {0} is not available.
Please setup your Chart of Accounts correctly.,帳戶{0}的帳戶號碼不可用。
請正確設置您的會計科目表。 +apps/erpnext/erpnext/regional/report/fichier_des_ecritures_comptables_[fec]/fichier_des_ecritures_comptables_[fec].py +121,Account number for account {0} is not available.
Please setup your Chart of Accounts correctly.,科目{0}的科目號碼不可用。
請正確設置您的會計科目表。 DocType: Task,Depends on Tasks,取決於任務 apps/erpnext/erpnext/config/selling.py +36,Manage Customer Group Tree.,管理客戶群組樹。 DocType: Normal Test Items,Result Value,結果值 @@ -3657,7 +3657,7 @@ Examples: DocType: Issue,Issue Type,發行類型 DocType: Attendance,Leave Type,休假類型 DocType: Purchase Invoice,Supplier Invoice Details,供應商發票明細 -apps/erpnext/erpnext/controllers/stock_controller.py +237,Expense / Difference account ({0}) must be a 'Profit or Loss' account,費用/差異帳戶({0})必須是一個'溢利或虧損的帳戶 +apps/erpnext/erpnext/controllers/stock_controller.py +237,Expense / Difference account ({0}) must be a 'Profit or Loss' account,費用/差異科目({0})必須是一個'收益或損失'的科目 DocType: Project,Copied From,複製自 DocType: Project,Copied From,複製自 apps/erpnext/erpnext/projects/doctype/timesheet/timesheet.py +265,Invoice already created for all billing hours,發票已在所有結算時間創建 @@ -3701,7 +3701,7 @@ DocType: Asset,In Maintenance,在維護中 DocType: Amazon MWS Settings,Click this button to pull your Sales Order data from Amazon MWS.,單擊此按鈕可從亞馬遜MWS中提取銷售訂單數據。 DocType: Purchase Invoice,Overdue,過期的 DocType: Account,Stock Received But Not Billed,庫存接收,但不付款 -apps/erpnext/erpnext/accounts/doctype/account/account.py +91,Root Account must be a group,根帳戶必須是一組 +apps/erpnext/erpnext/accounts/doctype/account/account.py +91,Root Account must be a group,Root 科目必須是群組科目 DocType: Drug Prescription,Drug Prescription,藥物處方 DocType: Loan,Repaid/Closed,償還/關閉 DocType: Item,Total Projected Qty,預計總數量 @@ -3737,7 +3737,7 @@ apps/erpnext/erpnext/stock/doctype/item/item.py +578,Item {0} does not exist,項 DocType: Sales Invoice,Customer Address,客戶地址 DocType: Loan,Loan Details,貸款詳情 apps/erpnext/erpnext/setup/setup_wizard/setup_wizard.py +62,Failed to setup post company fixtures,未能設置公司固定裝置 -DocType: Company,Default Inventory Account,默認庫存帳戶 +DocType: Company,Default Inventory Account,默認庫存科目 apps/erpnext/erpnext/accounts/doctype/share_transfer/share_transfer.py +193,The folio numbers are not matching,作品集編號不匹配 apps/erpnext/erpnext/accounts/doctype/payment_request/payment_request.py +304,Payment Request for {0},付款申請{0} DocType: Item Barcode,Barcode Type,條碼類型 @@ -3786,7 +3786,7 @@ DocType: Antibiotic,Healthcare Administrator,醫療管理員 apps/erpnext/erpnext/utilities/user_progress.py +47,Set a Target,設定目標 DocType: Dosage Strength,Dosage Strength,劑量強度 DocType: Healthcare Practitioner,Inpatient Visit Charge,住院訪問費用 -DocType: Account,Expense Account,費用帳戶 +DocType: Account,Expense Account,費用科目 apps/erpnext/erpnext/setup/setup_wizard/data/industry_type.py +49,Software,軟件 apps/erpnext/erpnext/setup/setup_wizard/operations/install_fixtures.py +155,Colour,顏色 DocType: Assessment Plan Criteria,Assessment Plan Criteria,評估計劃標準 @@ -3860,7 +3860,7 @@ DocType: Contract,Fulfilment Terms,履行條款 DocType: Sales Invoice,Time Sheet List,時間表列表 DocType: Employee,You can enter any date manually,您可以手動輸入任何日期 DocType: Healthcare Settings,Result Printed,結果打印 -DocType: Asset Category Account,Depreciation Expense Account,折舊費用帳戶 +DocType: Asset Category Account,Depreciation Expense Account,折舊費用科目 apps/erpnext/erpnext/setup/setup_wizard/operations/install_fixtures.py +191,Probationary Period,試用期 DocType: Purchase Taxes and Charges Template,Is Inter State,是國際 apps/erpnext/erpnext/config/hr.py +269,Shift Management,班次管理 @@ -3900,7 +3900,7 @@ apps/erpnext/erpnext/hr/utils.py +154,Future dates not allowed,未來的日期 apps/erpnext/erpnext/support/page/support_analytics/support_analytics.js +30,Select Fiscal Year,選擇財政年度 apps/erpnext/erpnext/selling/doctype/sales_order/sales_order.py +119,Expected Delivery Date should be after Sales Order Date,預計交貨日期應在銷售訂單日期之後 apps/erpnext/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py +43,Reorder Level,重新排序級別 -DocType: Company,Chart Of Accounts Template,圖表帳戶模板 +DocType: Company,Chart Of Accounts Template,會計科目模板 apps/erpnext/erpnext/assets/doctype/asset/asset.py +80,Update stock must be enable for the purchase invoice {0},必須為購買發票{0}啟用更新庫存 apps/erpnext/erpnext/stock/get_item_details.py +405,Item Price updated for {0} in Price List {1},項目價格更新{0}價格表{1} DocType: Salary Structure,Salary breakup based on Earning and Deduction.,工資分手基於盈利和演繹。 @@ -3957,7 +3957,7 @@ apps/erpnext/erpnext/accounts/doctype/cost_center/cost_center.py +40,Cost Center DocType: QuickBooks Migrator,Authorization URL,授權URL apps/erpnext/erpnext/accounts/doctype/payment_entry/payment_entry.py +376,Amount {0} {1} {2} {3},金額{0} {1} {2} {3} DocType: Account,Depreciation,折舊 -apps/erpnext/erpnext/accounts/doctype/share_transfer/share_transfer.py +103,The number of shares and the share numbers are inconsistent,股份數量和股票數量不一致 +apps/erpnext/erpnext/accounts/doctype/share_transfer/share_transfer.py +103,The number of shares and the share numbers are inconsistent,股份數量和庫存數量不一致 apps/erpnext/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py +50,Supplier(s),供應商(S) DocType: Employee Attendance Tool,Employee Attendance Tool,員工考勤工具 DocType: Guardian Student,Guardian Student,學生監護人 @@ -3981,8 +3981,8 @@ apps/erpnext/erpnext/manufacturing/doctype/production_planning_tool/production_p DocType: Restaurant Reservation,No of People,沒有人 apps/erpnext/erpnext/config/selling.py +164,Template of terms or contract.,模板條款或合同。 DocType: Bank Account,Address and Contact,地址和聯絡方式 -DocType: Cheque Print Template,Is Account Payable,為應付賬款 -apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +306,Stock cannot be updated against Purchase Receipt {0},股票不能對外購入庫單進行更新{0} +DocType: Cheque Print Template,Is Account Payable,為應付帳款 +apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +306,Stock cannot be updated against Purchase Receipt {0},庫存不能對外購入庫單進行更新{0} DocType: Support Settings,Auto close Issue after 7 days,7天之後自動關閉問題 apps/erpnext/erpnext/hr/doctype/leave_allocation/leave_allocation.py +85,"Leave cannot be allocated before {0}, as leave balance has already been carry-forwarded in the future leave allocation record {1}",假,不是之前分配{0},因為休假餘額已經結轉轉發在未來的假期分配記錄{1} apps/erpnext/erpnext/accounts/party.py +350,Note: Due / Reference Date exceeds allowed customer credit days by {0} day(s),註:由於/參考日期由{0}天超過了允許客戶的信用天數(S) @@ -4035,7 +4035,7 @@ apps/erpnext/erpnext/accounts/report/trial_balance/trial_balance.py +271,Closing apps/erpnext/erpnext/stock/doctype/serial_no/serial_no.py +284,Serial No {0} not in stock,序列號{0}無貨 apps/erpnext/erpnext/config/selling.py +169,Tax template for selling transactions.,稅務模板賣出的交易。 DocType: Sales Invoice,Write Off Outstanding Amount,核銷額(億元) -apps/erpnext/erpnext/hr/doctype/expense_claim_type/expense_claim_type.py +27,Account {0} does not match with Company {1},帳戶{0}與公司{1}不符 +apps/erpnext/erpnext/hr/doctype/expense_claim_type/expense_claim_type.py +27,Account {0} does not match with Company {1},科目{0}與公司{1}不符 DocType: Education Settings,Current Academic Year,當前學年 DocType: Education Settings,Current Academic Year,當前學年 DocType: Stock Settings,Default Stock UOM,預設庫存計量單位 @@ -4055,13 +4055,13 @@ apps/erpnext/erpnext/crm/report/lead_conversion_time/lead_conversion_time.py +59 apps/erpnext/erpnext/controllers/accounts_controller.py +703,'Update Stock' cannot be checked for fixed asset sale,"""更新庫存"" 無法檢查固定資產銷售" DocType: Bank Reconciliation,Bank Reconciliation,銀行對帳 apps/erpnext/erpnext/templates/includes/footer/footer_extension.html +7,Get Updates,獲取更新 -apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py +97,{0} {1}: Account {2} does not belong to Company {3},{0} {1}帳戶{2}不屬於公司{3} +apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py +97,{0} {1}: Account {2} does not belong to Company {3},{0} {1}科目{2}不屬於公司{3} apps/erpnext/erpnext/stock/doctype/item/item.js +452,Select at least one value from each of the attributes.,從每個屬性中至少選擇一個值。 apps/erpnext/erpnext/buying/doctype/purchase_order/purchase_order.py +164,Material Request {0} is cancelled or stopped,材料需求{0}被取消或停止 apps/erpnext/erpnext/regional/report/eway_bill/eway_bill.py +219,Dispatch State,派遣國 apps/erpnext/erpnext/config/hr.py +399,Leave Management,離開管理 apps/erpnext/erpnext/stock/doctype/item/item_dashboard.py +17,Groups,組 -apps/erpnext/erpnext/accounts/report/general_ledger/general_ledger.py +51,Group by Account,以帳戶分群組 +apps/erpnext/erpnext/accounts/report/general_ledger/general_ledger.py +51,Group by Account,以科目分群組 DocType: Purchase Invoice,Hold Invoice,保留發票 apps/erpnext/erpnext/hr/doctype/employee_promotion/employee_promotion.js +37,Please select Employee,請選擇員工 apps/erpnext/erpnext/setup/setup_wizard/operations/install_fixtures.py +214,Lower Income,較低的收入 @@ -4069,7 +4069,7 @@ DocType: Restaurant Order Entry,Current Order,當前訂單 apps/erpnext/erpnext/assets/doctype/asset_movement/asset_movement.py +25,Number of serial nos and quantity must be the same,序列號和數量必須相同 apps/erpnext/erpnext/stock/doctype/stock_entry/stock_entry.py +275,Source and target warehouse cannot be same for row {0},列{0}的來源和目標倉庫不可相同 DocType: Account,Asset Received But Not Billed,已收到但未收費的資產 -apps/erpnext/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +244,"Difference Account must be a Asset/Liability type account, since this Stock Reconciliation is an Opening Entry",差異帳戶必須是資產/負債類型的帳戶,因為此庫存調整是一個開始分錄 +apps/erpnext/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +244,"Difference Account must be a Asset/Liability type account, since this Stock Reconciliation is an Opening Entry",差異科目必須是資產/負債類型的科目,因為此庫存調整是一個開帳分錄 apps/erpnext/erpnext/hr/doctype/loan/loan.py +116,Disbursed Amount cannot be greater than Loan Amount {0},支付額不能超過貸款金額較大的{0} apps/erpnext/erpnext/utilities/user_progress.py +176,Go to Programs,轉到程序 apps/erpnext/erpnext/hr/doctype/expense_claim/expense_claim.py +212,Row {0}# Allocated amount {1} cannot be greater than unclaimed amount {2},行{0}#分配的金額{1}不能大於無人認領的金額{2} @@ -4117,7 +4117,7 @@ apps/erpnext/erpnext/patches/v7_0/create_warehouse_nestedset.py +59,All Warehous apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +1303,No {0} found for Inter Company Transactions.,Inter公司沒有找到{0}。 DocType: Travel Itinerary,Rented Car,租車 apps/erpnext/erpnext/public/js/hub/components/profile_dialog.js +15,About your Company,關於貴公司 -apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +144,Credit To account must be a Balance Sheet account,信用帳戶必須是資產負債表科目 +apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +144,Credit To account must be a Balance Sheet account,貸方科目必須是資產負債表科目 DocType: Donor,Donor,捐贈者 DocType: Global Defaults,Disable In Words,禁用詞 apps/erpnext/erpnext/stock/doctype/item/item.py +74,Item Code is mandatory because Item is not automatically numbered,產品編號是強制性的,因為項目沒有自動編號 @@ -4136,7 +4136,7 @@ apps/erpnext/erpnext/accounts/doctype/payment_entry/payment_entry.py +95,Row #{0 apps/erpnext/erpnext/manufacturing/doctype/bom/bom.js +84,Browse BOM,瀏覽BOM apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py +165,Secured Loans,抵押貸款 DocType: Purchase Invoice,Edit Posting Date and Time,編輯投稿時間 -apps/erpnext/erpnext/assets/doctype/asset/depreciation.py +106,Please set Depreciation related Accounts in Asset Category {0} or Company {1},請設置在資產類別{0}或公司折舊相關帳戶{1} +apps/erpnext/erpnext/assets/doctype/asset/depreciation.py +106,Please set Depreciation related Accounts in Asset Category {0} or Company {1},請設置在資產類別{0}或公司折舊相關科目{1} DocType: Lab Test Groups,Normal Range,普通範圍 DocType: Academic Term,Academic Year,學年 apps/erpnext/erpnext/stock/report/item_variant_details/item_variant_details.py +79,Available Selling,可用銷售 @@ -4145,7 +4145,7 @@ apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standar DocType: Purchase Invoice,N,ñ apps/erpnext/erpnext/education/report/assessment_plan_status/assessment_plan_status.py +175,Remaining,剩餘 DocType: Appraisal,Appraisal,評價 -DocType: Loan,Loan Account,貸款帳戶 +DocType: Loan,Loan Account,貸款科目 DocType: Purchase Invoice,GST Details,消費稅細節 apps/erpnext/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner_dashboard.py +6,This is based on transactions against this Healthcare Practitioner.,這是基於針對此醫療保健從業者的交易。 apps/erpnext/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py +156,Email sent to supplier {0},電子郵件發送到供應商{0} @@ -4168,9 +4168,9 @@ apps/erpnext/erpnext/buying/doctype/request_for_quotation/request_for_quotation. apps/erpnext/erpnext/manufacturing/doctype/bom/bom.py +187,{0} not found for Item {1},找不到項目{1} {0} apps/erpnext/erpnext/utilities/user_progress.py +197,Go to Courses,去課程 DocType: Accounts Settings,Show Inclusive Tax In Print,在打印中顯示包含稅 -apps/erpnext/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py +17,"Bank Account, From Date and To Date are Mandatory",銀行賬戶,從日期到日期是強制性的 +apps/erpnext/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py +17,"Bank Account, From Date and To Date are Mandatory",銀行科目,從日期到日期是強制性的 apps/erpnext/erpnext/accounts/doctype/payment_request/payment_request.js +29,Message Sent,發送訊息 -apps/erpnext/erpnext/accounts/doctype/account/account.py +105,Account with child nodes cannot be set as ledger,帳戶與子節點不能被設置為分類帳 +apps/erpnext/erpnext/accounts/doctype/account/account.py +105,Account with child nodes cannot be set as ledger,科目與子節點不能被設置為分類帳 DocType: Sales Invoice,Rate at which Price list currency is converted to customer's base currency,價目表貨幣被換算成客戶基礎貨幣的匯率 DocType: Purchase Invoice Item,Net Amount (Company Currency),淨金額(公司貨幣) apps/erpnext/erpnext/hr/doctype/expense_claim/expense_claim.py +223,Total advance amount cannot be greater than total sanctioned amount,總預付金額不得超過全部認可金額 @@ -4178,7 +4178,7 @@ DocType: Salary Slip,Hour Rate,小時率 DocType: Stock Settings,Item Naming By,產品命名規則 apps/erpnext/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py +46,Another Period Closing Entry {0} has been made after {1},另一個期末錄入{0}作出後{1} DocType: Work Order,Material Transferred for Manufacturing,物料轉倉用於製造 -apps/erpnext/erpnext/accounts/report/general_ledger/general_ledger.py +49,Account {0} does not exists,帳戶{0}不存在 +apps/erpnext/erpnext/accounts/report/general_ledger/general_ledger.py +49,Account {0} does not exists,科目{0}不存在 apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +1608,Select Loyalty Program,選擇忠誠度計劃 DocType: Project,Project Type,專案類型 apps/erpnext/erpnext/projects/doctype/task/task.py +157,Child Task exists for this Task. You can not delete this Task.,子任務存在這個任務。你不能刪除這個任務。 @@ -4199,7 +4199,7 @@ apps/erpnext/erpnext/accounts/doctype/shipping_rule/shipping_rule.py +101,Shippi apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py +20,Cash In Hand,手頭現金 apps/erpnext/erpnext/selling/doctype/sales_order/sales_order.py +143,Delivery warehouse required for stock item {0},需要的庫存項目交割倉庫{0} DocType: Packing Slip,The gross weight of the package. Usually net weight + packaging material weight. (for print),包裹的總重量。通常為淨重+包裝材料的重量。 (用於列印) -DocType: Accounts Settings,Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,具有此角色的用戶可以設置凍結帳戶,並新增/修改對凍結帳戶的會計分錄 +DocType: Accounts Settings,Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,具有此角色的用戶可以設置凍結科目,並新增/修改對凍結科目的會計分錄 DocType: Vital Signs,Cuts,削減 DocType: Serial No,Is Cancelled,被註銷 DocType: Student Group,Group Based On,基於組 @@ -4218,7 +4218,7 @@ apps/erpnext/erpnext/education/doctype/student_attendance_tool/student_attendanc ,Issued Items Against Work Order,針對工單發布物品 ,BOM Stock Calculated,BOM庫存計算 DocType: Vehicle Log,Invoice Ref,發票編號 -DocType: Company,Default Income Account,預設之收入帳戶 +DocType: Company,Default Income Account,預設收入科目 apps/erpnext/erpnext/accounts/report/balance_sheet/balance_sheet.py +39,Unclosed Fiscal Years Profit / Loss (Credit),未關閉的財年利潤/損失(信用) DocType: Sales Invoice,Time Sheets,考勤表 DocType: Healthcare Service Unit Type,Change In Item,更改項目 @@ -4258,7 +4258,7 @@ DocType: Soil Texture,Silt Composition (%),粉塵成分(%) DocType: Journal Entry,Remark,備註 DocType: Healthcare Settings,Avoid Confirmation,避免確認 DocType: Purchase Receipt Item,Rate and Amount,率及金額 -apps/erpnext/erpnext/accounts/doctype/payment_entry/payment_entry.py +177,Account Type for {0} must be {1},帳戶類型為{0}必須{1} +apps/erpnext/erpnext/accounts/doctype/payment_entry/payment_entry.py +177,Account Type for {0} must be {1},科目類型為{0}必須{1} apps/erpnext/erpnext/config/hr.py +34,Leaves and Holiday,休假及假日 DocType: Education Settings,Current Academic Term,當前學術期限 DocType: Education Settings,Current Academic Term,當前學術期限 @@ -4272,7 +4272,7 @@ DocType: Purchase Invoice Item,Landed Cost Voucher Amount,到岸成本憑證金 apps/erpnext/erpnext/config/accounts.py +19,Bills raised by Suppliers.,由供應商提出的帳單。 DocType: POS Profile,Write Off Account,核銷帳戶 DocType: Patient Appointment,Get prescribed procedures,獲取規定的程序 -DocType: Sales Invoice,Redemption Account,贖回賬戶 +DocType: Sales Invoice,Redemption Account,贖回科目 DocType: Purchase Invoice Item,Discount Amount,折扣金額 DocType: Purchase Invoice,Return Against Purchase Invoice,回到對採購發票 DocType: Item,Warranty Period (in days),保修期限(天數) @@ -4372,7 +4372,7 @@ apps/erpnext/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py +3 apps/erpnext/erpnext/hr/report/salary_register/salary_register.py +47,Salary Slip ID,工資單編號 apps/erpnext/erpnext/hr/doctype/employee/employee.py +135,Date Of Retirement must be greater than Date of Joining,日期退休必須大於加入的日期 apps/erpnext/erpnext/stock/doctype/item/item.js +70,Multiple Variants,多種變體 -DocType: Sales Invoice,Against Income Account,對收入帳戶 +DocType: Sales Invoice,Against Income Account,對收入科目 DocType: Subscription,Trial Period Start Date,試用期開始日期 apps/erpnext/erpnext/buying/doctype/purchase_order/purchase_order.py +106,Item {0}: Ordered qty {1} cannot be less than minimum order qty {2} (defined in Item).,項目{0}:有序數量{1}不能低於最低訂貨量{2}(項中定義)。 DocType: Certification Application,Certified,認證 @@ -4402,7 +4402,7 @@ DocType: Asset,Journal Entry for Scrap,日記帳分錄報廢 apps/erpnext/erpnext/selling/doctype/installation_note/installation_note.py +83,Please pull items from Delivery Note,請送貨單拉項目 apps/erpnext/erpnext/manufacturing/doctype/work_order/work_order.py +242,Row {0}: select the workstation against the operation {1},行{0}:根據操作{1}選擇工作站 apps/erpnext/erpnext/accounts/utils.py +496,Journal Entries {0} are un-linked,日記條目{0}都是非聯 -apps/erpnext/erpnext/accounts/utils.py +825,{0} Number {1} already used in account {2},已在{2}帳戶中使用的{0}號碼{1} +apps/erpnext/erpnext/accounts/utils.py +825,{0} Number {1} already used in account {2},已在{2}科目中使用的{0}號碼{1} apps/erpnext/erpnext/config/crm.py +92,"Record of all communications of type email, phone, chat, visit, etc.",類型電子郵件,電話,聊天,訪問等所有通信記錄 DocType: Supplier Scorecard Scoring Standing,Supplier Scorecard Scoring Standing,供應商記分卡 DocType: Manufacturer,Manufacturers used in Items,在項目中使用製造商 @@ -4428,7 +4428,7 @@ DocType: Salary Component,"If selected, the value specified or calculated in thi DocType: Asset Settings,Number of Days in Fiscal Year,會計年度的天數 ,Stock Ledger,庫存總帳 apps/erpnext/erpnext/templates/includes/cart/cart_items.html +29,Rate: {0},價格:{0} -DocType: Company,Exchange Gain / Loss Account,兌換收益/損失帳戶 +DocType: Company,Exchange Gain / Loss Account,匯兌損益科目 DocType: Amazon MWS Settings,MWS Credentials,MWS憑證 apps/erpnext/erpnext/config/hr.py +7,Employee and Attendance,員工考勤 apps/erpnext/erpnext/stock/doctype/stock_entry/stock_entry.py +123,Purpose must be one of {0},目的必須是一個{0} @@ -4450,7 +4450,7 @@ DocType: Cash Flow Mapper,Section Name,部分名稱 apps/erpnext/erpnext/stock/report/stock_balance/stock_balance.py +92,Reorder Qty,再訂購數量 apps/erpnext/erpnext/assets/doctype/asset/asset.py +292,Depreciation Row {0}: Expected value after useful life must be greater than or equal to {1},折舊行{0}:使用壽命後的預期值必須大於或等於{1} apps/erpnext/erpnext/hr/doctype/job_opening/job_opening.py +55,Current Job Openings,當前職位空缺 -DocType: Company,Stock Adjustment Account,庫存調整帳戶 +DocType: Company,Stock Adjustment Account,庫存調整科目 apps/erpnext/erpnext/public/js/payment/pos_payment.html +17,Write Off,註銷項款 DocType: Healthcare Service Unit,Allow Overlap,允許重疊 DocType: Employee,"System User (login) ID. If set, it will become default for all HR forms.",系統用戶(登錄)的標識。如果設定,這將成為的所有人力資源的預設形式。 @@ -4497,7 +4497,7 @@ DocType: Purchase Order,Order Confirmation Date,訂單確認日期 apps/erpnext/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js +47,Make Maintenance Visit,使維護訪問 DocType: Employee Transfer,Employee Transfer Details,員工轉移詳情 apps/erpnext/erpnext/selling/doctype/customer/customer.py +263,Please contact to the user who have Sales Master Manager {0} role,請聯絡,誰擁有碩士學位的銷售經理{0}角色的用戶 -DocType: Company,Default Cash Account,預設的現金帳戶 +DocType: Company,Default Cash Account,預設的現金科目 apps/erpnext/erpnext/config/accounts.py +40,Company (not Customer or Supplier) master.,公司(不是客戶或供應商)的主人。 apps/erpnext/erpnext/education/doctype/student/student_dashboard.py +6,This is based on the attendance of this Student,這是基於這名學生出席 apps/erpnext/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.js +179,No Students in,沒有學生 @@ -4515,12 +4515,12 @@ DocType: Opportunity,Opportunity Type,機會型 DocType: Asset Movement,To Employee,給員工 DocType: Employee Transfer,New Company,新公司 apps/erpnext/erpnext/setup/doctype/company/delete_company_transactions.py +19,Transactions can only be deleted by the creator of the Company,交易只能由公司的創建者被刪除 -apps/erpnext/erpnext/accounts/general_ledger.py +21,Incorrect number of General Ledger Entries found. You might have selected a wrong Account in the transaction.,不正確的數字總帳條目中找到。你可能會在交易中選擇了錯誤的帳戶。 +apps/erpnext/erpnext/accounts/general_ledger.py +21,Incorrect number of General Ledger Entries found. You might have selected a wrong Account in the transaction.,不正確的數字總帳條目中找到。你可能會在交易中選擇了錯誤的科目。 DocType: Employee,Prefered Contact Email,首選聯繫郵箱 DocType: Cheque Print Template,Cheque Width,支票寬度 DocType: Selling Settings,Validate Selling Price for Item against Purchase Rate or Valuation Rate,驗證售價反對預訂價或估價RATE項目 DocType: Fee Schedule,Fee Schedule,收費表 -DocType: Company,Create Chart Of Accounts Based On,創建圖表的帳戶根據 +DocType: Company,Create Chart Of Accounts Based On,基於會計科目表創建 apps/erpnext/erpnext/hr/doctype/employee/employee.py +129,Date of Birth cannot be greater than today.,出生日期不能大於今天。 ,Stock Ageing,存貨帳齡分析表 DocType: Travel Request,"Partially Sponsored, Require Partial Funding",部分贊助,需要部分資金 @@ -4541,7 +4541,7 @@ DocType: Purchase Order,Customer Contact Email,客戶聯絡電子郵件 DocType: Warranty Claim,Item and Warranty Details,項目和保修細節 DocType: Chapter,Chapter Members,章節成員 DocType: Sales Team,Contribution (%),貢獻(%) -apps/erpnext/erpnext/controllers/accounts_controller.py +143,Note: Payment Entry will not be created since 'Cash or Bank Account' was not specified,注:付款項將不會被創建因為“現金或銀行帳戶”未指定 +apps/erpnext/erpnext/controllers/accounts_controller.py +143,Note: Payment Entry will not be created since 'Cash or Bank Account' was not specified,注:付款項將不會被創建因為“現金或銀行科目”未指定 apps/erpnext/erpnext/projects/doctype/project/project.py +79,Project {0} already exists,項目{0}已經存在 DocType: Clinical Procedure,Nursing User,護理用戶 DocType: Employee Benefit Application,Payroll Period,工資期 @@ -4549,7 +4549,7 @@ DocType: Plant Analysis,Plant Analysis Criterias,植物分析標準 apps/erpnext/erpnext/stock/doctype/serial_no/serial_no.py +239,Serial No {0} does not belong to Batch {1},序列號{0}不屬於批次{1} apps/erpnext/erpnext/setup/setup_wizard/operations/install_fixtures.py +197,Responsibilities,職責 apps/erpnext/erpnext/selling/doctype/quotation/quotation.py +125,Validity period of this quotation has ended.,此報價的有效期已經結束。 -DocType: Expense Claim Account,Expense Claim Account,報銷賬戶 +DocType: Expense Claim Account,Expense Claim Account,報銷科目 DocType: Account,Capital Work in Progress,資本工作正在進行中 DocType: Accounts Settings,Allow Stale Exchange Rates,允許陳舊的匯率 DocType: Sales Person,Sales Person Name,銷售人員的姓名 @@ -4565,7 +4565,7 @@ apps/erpnext/erpnext/hr/doctype/leave_application/leave_application_dashboard.ht apps/erpnext/erpnext/projects/doctype/task/task.py +57,Progress % for a task cannot be more than 100.,為任務進度百分比不能超過100個。 DocType: Stock Reconciliation Item,Before reconciliation,調整前 DocType: Purchase Invoice,Taxes and Charges Added (Company Currency),稅收和收費上架(公司貨幣) -apps/erpnext/erpnext/stock/doctype/item/item.py +507,Item Tax Row {0} must have account of type Tax or Income or Expense or Chargeable,商品稅行{0}必須有帳戶類型稅或收入或支出或課稅的 +apps/erpnext/erpnext/stock/doctype/item/item.py +507,Item Tax Row {0} must have account of type Tax or Income or Expense or Chargeable,商品稅行{0}必須有科目類型為"稅" 或 "收入" 或 "支出" 或 "課稅的" DocType: Sales Order,Partly Billed,天色帳單 apps/erpnext/erpnext/assets/doctype/asset/asset.py +54,Item {0} must be a Fixed Asset Item,項{0}必須是固定資產項目 apps/erpnext/erpnext/stock/doctype/item/item.js +427,Make Variants,變種 @@ -4577,13 +4577,13 @@ apps/erpnext/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_re apps/erpnext/erpnext/setup/doctype/company/company.js +109,Please re-type company name to confirm,請確認重新輸入公司名稱 apps/erpnext/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py +50,Total Outstanding Amt,總街貨量金額 DocType: Journal Entry,Printing Settings,列印設定 -DocType: Employee Advance,Advance Account,預付帳戶 +DocType: Employee Advance,Advance Account,預付款科目 DocType: Job Offer,Job Offer Terms,招聘條款 DocType: Sales Invoice,Include Payment (POS),包括支付(POS) apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +324,Total Debit must be equal to Total Credit. The difference is {0},借方總額必須等於貸方總額。差額為{0} apps/erpnext/erpnext/setup/setup_wizard/data/industry_type.py +11,Automotive,汽車 DocType: Vehicle,Insurance Company,保險公司 -DocType: Asset Category Account,Fixed Asset Account,固定資產帳戶 +DocType: Asset Category Account,Fixed Asset Account,固定資產科目 apps/erpnext/erpnext/hr/doctype/salary_structure/salary_structure.js +442,Variable,變量 apps/erpnext/erpnext/selling/doctype/installation_note/installation_note.js +47,From Delivery Note,從送貨單 DocType: Chapter,Members,會員 @@ -4595,14 +4595,14 @@ apps/erpnext/erpnext/public/js/pos/pos_bill_item.html +12,In Stock: ,有現貨 DocType: Notification Control,Custom Message,自定義訊息 apps/erpnext/erpnext/setup/setup_wizard/data/industry_type.py +33,Investment Banking,投資銀行業務 DocType: Purchase Invoice,input,輸入 -apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +107,Cash or Bank Account is mandatory for making payment entry,製作付款分錄時,現金或銀行帳戶是強制性輸入的欄位。 +apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +107,Cash or Bank Account is mandatory for making payment entry,製作付款分錄時,現金或銀行科目是強制性輸入的欄位。 DocType: Loyalty Program,Multiple Tier Program,多層計劃 apps/erpnext/erpnext/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py +54,Student Address,學生地址 apps/erpnext/erpnext/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py +54,Student Address,學生地址 DocType: Purchase Invoice,Price List Exchange Rate,價目表匯率 apps/erpnext/erpnext/patches/v11_0/rename_supplier_type_to_supplier_group.py +27,All Supplier Groups,所有供應商組織 DocType: Employee Boarding Activity,Required for Employee Creation,員工創建需要 -apps/erpnext/erpnext/accounts/doctype/account/account.py +214,Account Number {0} already used in account {1},已在帳戶{1}中使用的帳號{0} +apps/erpnext/erpnext/accounts/doctype/account/account.py +214,Account Number {0} already used in account {1},已在科目{1}中使用的帳號{0} DocType: Hotel Room Reservation,Booked,預訂 DocType: Detected Disease,Tasks Created,創建的任務 DocType: Purchase Invoice Item,Rate,單價 @@ -4840,7 +4840,7 @@ apps/erpnext/erpnext/setup/doctype/supplier_group/supplier_group.js +5,There is apps/erpnext/erpnext/selling/page/point_of_sale/point_of_sale.js +542,Form View,表單視圖 DocType: HR Settings,Expense Approver Mandatory In Expense Claim,費用審批人必須在費用索賠中 apps/erpnext/erpnext/setup/doctype/email_digest/email_digest.py +124,Summary for this month and pending activities,本月和待活動總結 -apps/erpnext/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py +91,Please set Unrealized Exchange Gain/Loss Account in Company {0},請在公司{0}中設置未實現的匯兌收益/損失帳戶 +apps/erpnext/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py +91,Please set Unrealized Exchange Gain/Loss Account in Company {0},請在公司{0}中設置未實現的匯兌收益/損失科目 apps/erpnext/erpnext/utilities/user_progress.py +248,"Add users to your organization, other than yourself.",將用戶添加到您的組織,而不是您自己。 DocType: Customer Group,Customer Group Name,客戶群組名稱 apps/erpnext/erpnext/public/js/pos/pos.html +109,No Customers yet!,還沒有客戶! @@ -4856,7 +4856,7 @@ DocType: Healthcare Practitioner,Phone (R),電話(R) apps/erpnext/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.js +104,Time slots added,添加時隙 DocType: Item,Attributes,屬性 apps/erpnext/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js +36,Enable Template,啟用模板 -apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +256,Please enter Write Off Account,請輸入核銷帳戶 +apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +256,Please enter Write Off Account,請輸入核銷科目 apps/erpnext/erpnext/selling/report/inactive_customers/inactive_customers.py +71,Last Order Date,最後訂購日期 DocType: Salary Component,Is Payable,應付 DocType: Inpatient Record,B Negative,B負面 @@ -4865,7 +4865,7 @@ DocType: Amazon MWS Settings,US,我們 DocType: Holiday List,Add Weekly Holidays,添加每週假期 DocType: Staffing Plan Detail,Vacancies,職位空缺 DocType: Hotel Room,Hotel Room,旅館房間 -apps/erpnext/erpnext/accounts/doctype/budget/budget.py +57,Account {0} does not belongs to company {1},帳戶{0}不屬於公司{1} +apps/erpnext/erpnext/accounts/doctype/budget/budget.py +57,Account {0} does not belongs to company {1},科目{0}不屬於公司{1} DocType: Leave Type,Rounding,四捨五入 apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +994,Serial Numbers in row {0} does not match with Delivery Note,行{0}中的序列號與交貨單不匹配 DocType: Employee Benefit Application,Dispensed Amount (Pro-rated),分配金額(按比例分配) @@ -4896,7 +4896,7 @@ DocType: Patient,Alcohol Current Use,酒精當前使用 DocType: Employee Tax Exemption Proof Submission,House Rent Payment Amount,房屋租金付款金額 DocType: Student Admission Program,Student Admission Program,學生入學計劃 DocType: Employee Tax Exemption Sub Category,Tax Exemption Category,免稅類別 -DocType: Payment Entry,Account Paid To,賬戶付至 +DocType: Payment Entry,Account Paid To,科目付至 DocType: Subscription Settings,Grace Period,寬限期 DocType: Item Alternative,Alternative Item Name,替代項目名稱 apps/erpnext/erpnext/selling/doctype/product_bundle/product_bundle.py +24,Parent Item {0} must not be a Stock Item,父項{0}不能是庫存產品 @@ -4905,7 +4905,7 @@ apps/erpnext/erpnext/config/selling.py +57,All Products or Services.,所有的 DocType: Email Digest,Open Quotations,打開報價單 DocType: Expense Claim,More Details,更多詳情 DocType: Supplier Quotation,Supplier Address,供應商地址 -apps/erpnext/erpnext/accounts/doctype/budget/budget.py +168,{0} Budget for Account {1} against {2} {3} is {4}. It will exceed by {5},{0}預算帳戶{1}對{2} {3}是{4}。這將超過{5} +apps/erpnext/erpnext/accounts/doctype/budget/budget.py +168,{0} Budget for Account {1} against {2} {3} is {4}. It will exceed by {5},{0}預算科目{1}對{2} {3}是{4}。這將超過{5} apps/erpnext/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py +37,Out Qty,輸出數量 apps/erpnext/erpnext/buying/doctype/supplier/supplier.py +49,Series is mandatory,系列是強制性的 apps/erpnext/erpnext/setup/setup_wizard/data/industry_type.py +28,Financial Services,金融服務 @@ -4991,7 +4991,7 @@ DocType: Job Offer,Awaiting Response,正在等待回應 DocType: Support Search Source,Link Options,鏈接選項 apps/erpnext/erpnext/selling/page/point_of_sale/point_of_sale.js +1557,Total Amount {0},總金額{0} apps/erpnext/erpnext/controllers/item_variant.py +323,Invalid attribute {0} {1},無效的屬性{0} {1} -DocType: Supplier,Mention if non-standard payable account,如果非標準應付賬款提到 +DocType: Supplier,Mention if non-standard payable account,如果非標準應付帳款提到 apps/erpnext/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.py +25,Please select the assessment group other than 'All Assessment Groups',請選擇“所有評估組”以外的評估組 apps/erpnext/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +67,Row {0}: Cost center is required for an item {1},行{0}:項目{1}需要費用中心 DocType: Training Event Employee,Optional,可選的 @@ -5047,7 +5047,7 @@ apps/erpnext/erpnext/selling/report/inactive_customers/inactive_customers.py +67 DocType: Item Group,HTML / Banner that will show on the top of product list.,HTML/橫幅,將顯示在產品列表的頂部。 DocType: Shipping Rule,Specify conditions to calculate shipping amount,指定條件來計算運費金額 DocType: Program Enrollment,Institute's Bus,學院的巴士 -DocType: Accounts Settings,Role Allowed to Set Frozen Accounts & Edit Frozen Entries,允許設定凍結帳戶和編輯凍結分錄的角色 +DocType: Accounts Settings,Role Allowed to Set Frozen Accounts & Edit Frozen Entries,允許設定凍結科目和編輯凍結分錄的角色 DocType: Supplier Scorecard Scoring Variable,Path,路徑 apps/erpnext/erpnext/accounts/doctype/cost_center/cost_center.py +30,Cannot convert Cost Center to ledger as it has child nodes,不能成本中心轉換為總賬,因為它有子節點 DocType: Production Plan,Total Planned Qty,總計劃數量 @@ -5055,7 +5055,7 @@ apps/erpnext/erpnext/stock/report/stock_balance/stock_balance.py +83,Opening Val DocType: Salary Component,Formula,式 apps/erpnext/erpnext/stock/report/stock_ledger/stock_ledger.py +59,Serial #,序列號 DocType: Lab Test Template,Lab Test Template,實驗室測試模板 -apps/erpnext/erpnext/setup/doctype/company/company.py +196,Sales Account,銷售帳戶 +apps/erpnext/erpnext/setup/doctype/company/company.py +196,Sales Account,銷售科目 DocType: Purchase Invoice Item,Total Weight,總重量 apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py +101,Commission on Sales,銷售佣金 DocType: Job Offer Term,Value / Description,值/說明 @@ -5078,7 +5078,7 @@ DocType: Cash Flow Mapping,Select Maximum Of 1,選擇最多1個 apps/erpnext/erpnext/stock/doctype/packing_slip/packing_slip.js +84,Invalid quantity specified for item {0}. Quantity should be greater than 0.,為項目指定了無效的數量{0} 。量應大於0 。 DocType: Company,Default Employee Advance Account,默認員工高級帳戶 apps/erpnext/erpnext/selling/page/point_of_sale/point_of_sale.js +1181,Search Item (Ctrl + i),搜索項目(Ctrl + i) -apps/erpnext/erpnext/accounts/doctype/account/account.py +171,Account with existing transaction can not be deleted,帳戶與現有的交易不能被刪除 +apps/erpnext/erpnext/accounts/doctype/account/account.py +171,Account with existing transaction can not be deleted,科目與現有的交易不能被刪除 DocType: Vehicle,Last Carbon Check,最後檢查炭 apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py +109,Legal Expenses,法律費用 apps/erpnext/erpnext/public/js/utils/serial_no_batch_selector.js +147,Please select quantity on row ,請選擇行數量 @@ -5100,7 +5100,7 @@ apps/erpnext/erpnext/controllers/accounts_controller.py +907,Account: {0} with c DocType: Bank Statement Transaction Settings Item,Bank Data,銀行數據 DocType: Purchase Receipt Item,Sample Quantity,樣品數量 DocType: Manufacturing Settings,"Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.",根據最新的估值/價格清單率/最近的原材料採購率,通過計劃程序自動更新BOM成本。 -apps/erpnext/erpnext/accounts/doctype/account/account.py +57,Account {0}: Parent account {1} does not belong to company: {2},帳戶{0}:父帳戶{1}不屬於公司:{2} +apps/erpnext/erpnext/accounts/doctype/account/account.py +57,Account {0}: Parent account {1} does not belong to company: {2},科目{0}:上層科目{1}不屬於公司:{2} apps/erpnext/erpnext/setup/doctype/company/company.js +126,Successfully deleted all transactions related to this company!,成功刪除與該公司相關的所有交易! apps/erpnext/erpnext/accounts/report/accounts_payable/accounts_payable.js +22,As on Date,隨著對日 DocType: Program Enrollment,Enrollment Date,報名日期 @@ -5126,7 +5126,7 @@ DocType: Academic Year,Academic Year Name,學年名稱 apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +1182,{0} not allowed to transact with {1}. Please change the Company.,不允許{0}與{1}進行交易。請更改公司。 DocType: Sales Partner,Contact Desc,聯絡倒序 DocType: Email Digest,Send regular summary reports via Email.,使用電子郵件發送定期匯總報告。 -apps/erpnext/erpnext/hr/doctype/expense_claim/expense_claim.py +289,Please set default account in Expense Claim Type {0},請報銷類型設置默認帳戶{0} +apps/erpnext/erpnext/hr/doctype/expense_claim/expense_claim.py +289,Please set default account in Expense Claim Type {0},請報銷類型設置默認科目{0} apps/erpnext/erpnext/hr/doctype/leave_application/leave_application_dashboard.html +11,Available Leaves,可用的葉子 DocType: Assessment Result,Student Name,學生姓名 DocType: Hub Tracked Item,Item Manager,項目經理 @@ -5169,17 +5169,17 @@ apps/erpnext/erpnext/accounts/doctype/budget/budget.py +155,Accumulated Monthly, apps/erpnext/erpnext/controllers/accounts_controller.py +864,{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2}.,{0}是強制性的。也許外幣兌換記錄為{1}到{2}尚未建立。 apps/erpnext/erpnext/hr/doctype/staffing_plan/staffing_plan.py +51,Staffing Plan {0} already exist for designation {1},已存在人員配置計劃{0}以用於指定{1} apps/erpnext/erpnext/accounts/doctype/tax_rule/tax_rule.py +46,Tax Template is mandatory.,稅務模板是強制性的。 -apps/erpnext/erpnext/accounts/doctype/account/account.py +51,Account {0}: Parent account {1} does not exist,帳戶{0}:父帳戶{1}不存在 +apps/erpnext/erpnext/accounts/doctype/account/account.py +51,Account {0}: Parent account {1} does not exist,科目{0}:上層科目{1}不存在 DocType: POS Closing Voucher,Period Start Date,期間開始日期 DocType: Purchase Invoice Item,Price List Rate (Company Currency),價格列表費率(公司貨幣) DocType: Products Settings,Products Settings,產品設置 -,Item Price Stock,項目價格股票 +,Item Price Stock,項目價格庫存 apps/erpnext/erpnext/config/accounts.py +550,To make Customer based incentive schemes.,制定基於客戶的激勵計劃。 DocType: Lab Prescription,Test Created,測試創建 DocType: Healthcare Settings,Custom Signature in Print,自定義簽名打印 DocType: Account,Temporary,臨時 apps/erpnext/erpnext/accounts/report/accounts_receivable/accounts_receivable.html +127,Customer LPO No.,客戶LPO號 -DocType: Amazon MWS Settings,Market Place Account Group,市場賬戶組 +DocType: Amazon MWS Settings,Market Place Account Group,市場科目組 apps/erpnext/erpnext/accounts/doctype/payment_order/payment_order.js +14,Make Payment Entries,付款條目 DocType: Program,Courses,培訓班 DocType: Monthly Distribution Percentage,Percentage Allocation,百分比分配 @@ -5215,7 +5215,7 @@ DocType: Selling Settings,Each Transaction,每筆交易 apps/erpnext/erpnext/stock/doctype/item/item.py +523,Barcode {0} already used in Item {1},條碼{0}已經用在項目{1} apps/erpnext/erpnext/config/selling.py +86,Rules for adding shipping costs.,增加運輸成本的規則。 apps/erpnext/erpnext/accounts/report/budget_variance_report/budget_variance_report.py +72,Varaiance ,Varaiance -DocType: Item,Opening Stock,打開股票 +DocType: Item,Opening Stock,打開庫存 apps/erpnext/erpnext/support/doctype/warranty_claim/warranty_claim.py +20,Customer is required,客戶是必需的 DocType: Lab Test,Result Date,結果日期 apps/erpnext/erpnext/accounts/report/accounts_receivable/accounts_receivable.html +129,PDC/LC Date,PDC / LC日期 @@ -5250,7 +5250,7 @@ apps/erpnext/erpnext/templates/includes/product_list.js +42,No products found., apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +396,{0} against Sales Invoice {1},{0}針對銷售發票{1} DocType: Antibiotic,Laboratory User,實驗室用戶 DocType: Request for Quotation Item,Project Name,專案名稱 -DocType: Customer,Mention if non-standard receivable account,提到如果不規範應收賬款 +DocType: Customer,Mention if non-standard receivable account,提到如果不規範應收帳款 apps/erpnext/erpnext/hr/doctype/employee_benefit_application/employee_benefit_application.py +63,Please add the remaining benefits {0} to any of the existing component,請將其餘好處{0}添加到任何現有組件 DocType: Journal Entry Account,If Income or Expense,如果收入或支出 DocType: Bank Statement Transaction Entry,Matching Invoices,匹配發票 @@ -5260,7 +5260,7 @@ apps/erpnext/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +6 apps/erpnext/erpnext/config/learn.py +229,Human Resource,人力資源 DocType: Payment Reconciliation Payment,Payment Reconciliation Payment,付款方式付款對賬 DocType: Disease,Treatment Task,治療任務 -DocType: Payment Order Reference,Bank Account Details,銀行賬戶明細 +DocType: Payment Order Reference,Bank Account Details,銀行科目明細 DocType: Purchase Order Item,Blanket Order,總訂單 apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py +39,Tax Assets,所得稅資產 apps/erpnext/erpnext/manufacturing/doctype/production_order/production_order.py +631,Production Order has been {0},生產訂單已經{0} @@ -5322,7 +5322,7 @@ apps/erpnext/erpnext/manufacturing/doctype/work_order/work_order_calendar.js +36 ,Employee Information,僱員資料 apps/erpnext/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py +242,Healthcare Practitioner not available on {0},醫療從業者在{0}上不可用 DocType: Stock Entry Detail,Additional Cost,額外費用 -apps/erpnext/erpnext/accounts/report/general_ledger/general_ledger.py +57,"Can not filter based on Voucher No, if grouped by Voucher",是冷凍的帳戶。要禁止該帳戶創建/編輯事務,你需要角色 +apps/erpnext/erpnext/accounts/report/general_ledger/general_ledger.py +57,"Can not filter based on Voucher No, if grouped by Voucher",是凍結的帳戶。要禁止該帳戶創建/編輯事務,你需要有指定的身份 apps/erpnext/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js +975,Make Supplier Quotation,讓供應商報價 DocType: Quality Inspection,Incoming,來 apps/erpnext/erpnext/setup/doctype/company/company.js +90,Default tax templates for sales and purchase are created.,銷售和採購的默認稅收模板被創建。 @@ -5340,7 +5340,7 @@ apps/erpnext/erpnext/setup/doctype/email_digest/email_digest.py +120,This Week's apps/erpnext/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py +24,In Stock Qty,庫存數量 ,Daily Work Summary Replies,日常工作總結回复 DocType: Delivery Trip,Calculate Estimated Arrival Times,計算預計到達時間 -apps/erpnext/erpnext/accounts/general_ledger.py +113,Account: {0} can only be updated via Stock Transactions,帳號:{0}只能通過股票的交易進行更新 +apps/erpnext/erpnext/accounts/general_ledger.py +113,Account: {0} can only be updated via Stock Transactions,帳號:{0}只能通過庫存的交易進行更新 DocType: Student Group Creation Tool,Get Courses,獲取課程 DocType: Shopify Settings,Webhooks,網絡掛接 DocType: Bank Account,Party,黨 @@ -5376,7 +5376,7 @@ apps/erpnext/erpnext/selling/doctype/sales_order/sales_order.py +87,Same item ha DocType: Department,Leave Block List,休假區塊清單 DocType: Purchase Invoice,Tax ID,稅號 apps/erpnext/erpnext/stock/doctype/serial_no/serial_no.py +198,Item {0} is not setup for Serial Nos. Column must be blank,項目{0}不是設定為序列號,此列必須為空白 -DocType: Accounts Settings,Accounts Settings,帳戶設定 +DocType: Accounts Settings,Accounts Settings,會計設定 DocType: Loyalty Program,Customer Territory,客戶地區 DocType: Email Digest,Sales Orders to Deliver,要交付的銷售訂單 apps/erpnext/erpnext/accounts/doctype/account/account_tree.js +28,"Number of new Account, it will be included in the account name as a prefix",新帳號的數量,將作為前綴包含在帳號名稱中 @@ -5388,7 +5388,7 @@ apps/erpnext/erpnext/hr/utils.py +152,To date can not be less than from date,迄 DocType: Opportunity,To Discuss,為了討論 apps/erpnext/erpnext/stock/stock_ledger.py +382,{0} units of {1} needed in {2} to complete this transaction.,{0}單位{1}在{2}完成此交易所需。 DocType: Support Settings,Forum URL,論壇URL -apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py +75,Temporary Accounts,臨時帳戶 +apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py +75,Temporary Accounts,臨時科目 apps/erpnext/erpnext/assets/doctype/asset_movement/asset_movement.py +40,Source Location is required for the asset {0},源位置對資產{0}是必需的 DocType: BOM Explosion Item,BOM Explosion Item,BOM展開項目 DocType: Shareholder,Contact List,聯繫人列表 @@ -5426,7 +5426,7 @@ apps/erpnext/erpnext/education/doctype/course/course.py +20,Total Weightage of a DocType: Purchase Order Item,Last Purchase Rate,最後預訂價 DocType: Account,Asset,財富 DocType: Project Task,Task ID,任務ID -apps/erpnext/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +84,Stock cannot exist for Item {0} since has variants,股票可以為項目不存在{0},因為有變種 +apps/erpnext/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +84,Stock cannot exist for Item {0} since has variants,庫存可以為項目不存在{0},因為有變種 DocType: Healthcare Practitioner,Mobile,移動 ,Sales Person-wise Transaction Summary,銷售人員相關的交易匯總 DocType: Training Event,Contact Number,聯繫電話 @@ -5444,7 +5444,7 @@ DocType: Employee,Reports to,隸屬於 DocType: Payment Entry,Paid Amount,支付的金額 apps/erpnext/erpnext/utilities/user_progress.py +158,Explore Sales Cycle,探索銷售週期 DocType: Assessment Plan,Supervisor,監 -apps/erpnext/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js +934,Retention Stock Entry,保留股票入場 +apps/erpnext/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js +934,Retention Stock Entry,保留庫存入場 ,Available Stock for Packing Items,可用庫存包裝項目 DocType: Item Variant,Item Variant,項目變 ,Work Order Stock Report,工單庫存報表 @@ -5454,7 +5454,7 @@ apps/erpnext/erpnext/education/doctype/instructor/instructor.js +45,As Superviso DocType: Leave Policy Detail,Leave Policy Detail,退出政策細節 DocType: BOM Scrap Item,BOM Scrap Item,BOM項目廢料 apps/erpnext/erpnext/accounts/page/pos/pos.js +906,Submitted orders can not be deleted,提交的訂單不能被刪除 -apps/erpnext/erpnext/accounts/doctype/account/account.py +121,"Account balance already in Debit, you are not allowed to set 'Balance Must Be' as 'Credit'",帳戶餘額已歸為借方帳戶,不允許設為信用帳戶 +apps/erpnext/erpnext/accounts/doctype/account/account.py +121,"Account balance already in Debit, you are not allowed to set 'Balance Must Be' as 'Credit'",科目餘額已歸為借方科目,不允許設為貸方 apps/erpnext/erpnext/setup/setup_wizard/operations/install_fixtures.py +391,Quality Management,品質管理 apps/erpnext/erpnext/assets/doctype/asset/asset.py +52,Item {0} has been disabled,項{0}已被禁用 DocType: Project,Total Billable Amount (via Timesheets),總計費用金額(通過時間表) @@ -5484,15 +5484,15 @@ apps/erpnext/erpnext/manufacturing/doctype/workstation/workstation.py +36,Row #{ DocType: Purchase Invoice Item,Allow Zero Valuation Rate,允許零估值 DocType: Purchase Invoice Item,Allow Zero Valuation Rate,允許零估值 DocType: Training Event Employee,Invited,邀請 -apps/erpnext/erpnext/config/accounts.py +276,Setup Gateway accounts.,設置網關帳戶。 +apps/erpnext/erpnext/config/accounts.py +276,Setup Gateway accounts.,設置閘道科目。 DocType: Employee,Employment Type,就業類型 apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py +43,Fixed Assets,固定資產 DocType: Payment Entry,Set Exchange Gain / Loss,設置兌換收益/損失 ,GST Purchase Register,消費稅購買登記冊 ,Cash Flow,現金周轉 apps/erpnext/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.py +25,Combined invoice portion must equal 100%,合併發票部分必須等於100% -DocType: Item Default,Default Expense Account,預設費用帳戶 -DocType: GST Account,CGST Account,CGST賬戶 +DocType: Item Default,Default Expense Account,預設費用科目 +DocType: GST Account,CGST Account,CGST科目 apps/erpnext/erpnext/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py +53,Student Email ID,學生的電子郵件ID DocType: POS Closing Voucher Invoices,POS Closing Voucher Invoices,POS關閉憑證發票 DocType: Tax Rule,Sales Tax Template,銷售稅模板 @@ -5523,7 +5523,7 @@ The package **Item** will have ""Is Stock Item"" as ""No"" and ""Is Sales Item"" For Example: If you are selling Laptops and Backpacks separately and have a special price if the customer buys both, then the Laptop + Backpack will be a new Product Bundle Item. -Note: BOM = Bill of Materials",聚合組** **項目到另一個項目** **的。如果你是捆綁了一定**項目你保持股票的包裝**項目的**,而不是聚集**項這是一個有用的**到一個包和**。包** **項目將有“是股票項目”為“否”和“是銷售項目”為“是”。例如:如果你是銷售筆記本電腦和背包分開,並有一個特殊的價格,如果客戶購買兩個,那麼筆記本電腦+背包將是一個新的產品包項目。注:物料BOM =比爾 +Note: BOM = Bill of Materials",聚合組** **項目到另一個項目** **的。如果你是捆綁了一定**項目你保持庫存的包裝**項目的**,而不是聚集**項這是一個有用的**到一個包和**。包** **項目將有“是庫存項目”為“否”和“是銷售項目”為“是”。例如:如果你是銷售筆記本電腦和背包分開,並有一個特殊的價格,如果客戶購買兩個,那麼筆記本電腦+背包將是一個新的產品包項目。注:物料BOM =比爾 apps/erpnext/erpnext/selling/doctype/installation_note/installation_note.py +42,Serial No is mandatory for Item {0},項目{0}的序列號是強制性的 DocType: Item Variant Attribute,Attribute,屬性 DocType: Staffing Plan Detail,Current Count,當前計數 @@ -5564,7 +5564,7 @@ apps/erpnext/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +75,Max disco apps/erpnext/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py +191,Net Asset value as on,淨資產值作為 DocType: Crop,Produce,生產 DocType: Hotel Settings,Default Taxes and Charges,默認稅費 -DocType: Account,Receivable,應收賬款 +DocType: Account,Receivable,應收帳款 apps/erpnext/erpnext/selling/doctype/sales_order/sales_order.py +325,Row #{0}: Not allowed to change Supplier as Purchase Order already exists,行#{0}:不能更改供應商的採購訂單已經存在 DocType: Stock Entry,Material Consumption for Manufacture,材料消耗製造 DocType: Item Alternative,Alternative Item Code,替代項目代碼 @@ -5603,7 +5603,7 @@ DocType: Asset,Booked Fixed Asset,預訂的固定資產 apps/erpnext/erpnext/accounts/report/trial_balance/trial_balance.py +49,To Date should be within the Fiscal Year. Assuming To Date = {0},日期應該是在財政年度內。假設終止日期= {0} DocType: Employee,"Here you can maintain height, weight, allergies, medical concerns etc",在這裡,你可以保持身高,體重,過敏,醫療問題等 DocType: Leave Block List,Applies to Company,適用於公司 -apps/erpnext/erpnext/manufacturing/doctype/production_order/production_order.py +222,Cannot cancel because submitted Stock Entry {0} exists,不能取消,因為提交股票輸入{0}存在 +apps/erpnext/erpnext/manufacturing/doctype/production_order/production_order.py +222,Cannot cancel because submitted Stock Entry {0} exists,不能取消,因為提交庫存輸入{0}存在 DocType: BOM Update Tool,Update latest price in all BOMs,更新所有BOM的最新價格 apps/erpnext/erpnext/healthcare/doctype/patient/patient.js +24,Medical Record,醫療記錄 DocType: Vehicle,Vehicle,車輛 @@ -5613,13 +5613,13 @@ apps/erpnext/erpnext/hr/doctype/training_result/training_result.py +15,{0} must DocType: POS Profile,Item Groups,項目組 DocType: Sales Order Item,For Production,對於生產 DocType: Payment Request,payment_url,payment_url -DocType: Exchange Rate Revaluation Account,Balance In Account Currency,賬戶貨幣餘額 -apps/erpnext/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py +188,Please add a Temporary Opening account in Chart of Accounts,請在會計科目表中添加一個臨時開戶賬戶 +DocType: Exchange Rate Revaluation Account,Balance In Account Currency,科目貨幣餘額 +apps/erpnext/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py +188,Please add a Temporary Opening account in Chart of Accounts,請在會計科目表中添加一個臨時開戶科目 DocType: Customer,Customer Primary Contact,客戶主要聯繫人 DocType: Project Task,View Task,查看任務 apps/erpnext/erpnext/crm/report/campaign_efficiency/campaign_efficiency.py +22,Opp/Lead %,Opp / Lead% apps/erpnext/erpnext/crm/report/campaign_efficiency/campaign_efficiency.py +22,Opp/Lead %,Opp / Lead% -DocType: Bank Guarantee,Bank Account Info,銀行賬戶信息 +DocType: Bank Guarantee,Bank Account Info,銀行科目信息 DocType: Bank Guarantee,Bank Guarantee Type,銀行擔保類型 DocType: Payment Schedule,Invoice Portion,發票部分 ,Asset Depreciations and Balances,資產折舊和平衡 @@ -5701,7 +5701,7 @@ DocType: Certification Application,Yet to appear,尚未出現 DocType: Delivery Stop,Email Sent To,電子郵件發送給 DocType: Job Card Item,Job Card Item,工作卡項目 DocType: Accounts Settings,Allow Cost Center In Entry of Balance Sheet Account,允許成本中心輸入資產負債表科目 -apps/erpnext/erpnext/accounts/doctype/account/account.js +102,Merge with Existing Account,與現有帳戶合併 +apps/erpnext/erpnext/accounts/doctype/account/account.js +102,Merge with Existing Account,與現有科目合併 apps/erpnext/erpnext/stock/doctype/stock_entry/stock_entry.py +992,All items have already been transferred for this Work Order.,所有項目已經為此工作單轉移。 DocType: Appraisal,"Any other remarks, noteworthy effort that should go in the records.",任何其他言論,值得一提的努力,應該在記錄中。 DocType: Asset Maintenance,Manufacturing User,製造業用戶 @@ -5739,14 +5739,14 @@ apps/erpnext/erpnext/manufacturing/doctype/work_order/work_order.py +203,{0} ({1 DocType: Certification Application,Name of Applicant,申請人名稱 apps/erpnext/erpnext/config/manufacturing.py +27,Time Sheet for manufacturing.,時間表製造。 apps/erpnext/erpnext/templates/pages/cart.html +37,Subtotal,小計 -apps/erpnext/erpnext/stock/doctype/item/item.py +731,Cannot change Variant properties after stock transaction. You will have to make a new Item to do this.,股票交易後不能更改Variant屬性。你將不得不做一個新的項目來做到這一點。 +apps/erpnext/erpnext/stock/doctype/item/item.py +731,Cannot change Variant properties after stock transaction. You will have to make a new Item to do this.,庫存交易後不能更改Variant屬性。你將不得不做一個新的項目來做到這一點。 apps/erpnext/erpnext/config/integrations.py +18,GoCardless SEPA Mandate,GoCardless SEPA授權 DocType: Healthcare Practitioner,Charges,收費 DocType: Production Plan,Get Items For Work Order,獲取工作訂單的物品 DocType: Salary Detail,Default Amount,預設數量 apps/erpnext/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +96,Warehouse not found in the system,倉庫系統中未找到 DocType: Quality Inspection Reading,Quality Inspection Reading,質量檢驗閱讀 -apps/erpnext/erpnext/stock/doctype/stock_settings/stock_settings.py +26,`Freeze Stocks Older Than` should be smaller than %d days.,`凍結股票早於`應該是少於%d天。 +apps/erpnext/erpnext/stock/doctype/stock_settings/stock_settings.py +26,`Freeze Stocks Older Than` should be smaller than %d days.,`凍結庫存早於`應該是少於%d天。 DocType: Tax Rule,Purchase Tax Template,購置稅模板 apps/erpnext/erpnext/utilities/user_progress.py +48,Set a sales goal you'd like to achieve for your company.,為您的公司設定您想要實現的銷售目標。 apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +1553,Healthcare Services,醫療服務 @@ -5781,7 +5781,7 @@ apps/erpnext/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js +5 DocType: Warranty Claim,Resolved By,議決 apps/erpnext/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js +32,Schedule Discharge,附表卸貨 apps/erpnext/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py +42,Cheques and Deposits incorrectly cleared,支票及存款不正確清除 -apps/erpnext/erpnext/accounts/doctype/account/account.py +53,Account {0}: You can not assign itself as parent account,帳戶{0}:你不能指定自己為父帳戶 +apps/erpnext/erpnext/accounts/doctype/account/account.py +53,Account {0}: You can not assign itself as parent account,科目{0}:你不能指定自己為上層科目 DocType: Purchase Invoice Item,Price List Rate,價格列表費率 apps/erpnext/erpnext/utilities/activation.py +72,Create customer quotes,創建客戶報價 apps/erpnext/erpnext/public/js/controllers/transaction.js +885,Service Stop Date cannot be after Service End Date,服務停止日期不能在服務結束日期之後 @@ -5817,7 +5817,7 @@ DocType: Daily Work Summary Settings,"Emails will be sent to all Active Employee DocType: Employee Leave Approver,Employee Leave Approver,員工請假審批 apps/erpnext/erpnext/stock/doctype/item/item.py +541,Row {0}: An Reorder entry already exists for this warehouse {1},行{0}:一個重新排序條目已存在這個倉庫{1} apps/erpnext/erpnext/crm/doctype/opportunity/opportunity.py +99,"Cannot declare as lost, because Quotation has been made.",不能聲明為丟失,因為報價已經取得進展。 -apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py +68,CWIP Account,CWIP賬戶 +apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py +68,CWIP Account,CWIP科目 apps/erpnext/erpnext/hr/doctype/training_event/training_event.js +16,Training Feedback,培訓反饋 apps/erpnext/erpnext/config/accounts.py +184,Tax Withholding rates to be applied on transactions.,稅收預扣稅率適用於交易。 DocType: Supplier Scorecard Criteria,Supplier Scorecard Criteria,供應商記分卡標準 @@ -5850,7 +5850,7 @@ DocType: Agriculture Analysis Criteria,Agriculture User,農業用戶 apps/erpnext/erpnext/stock/stock_ledger.py +386,{0} units of {1} needed in {2} on {3} {4} for {5} to complete this transaction.,{0} {1}在需要{2}在{3} {4}:{5}來完成這一交易單位。 DocType: Fee Schedule,Student Category,學生組 DocType: Announcement,Student,學生 -apps/erpnext/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js +98,Stock quantity to start procedure is not available in the warehouse. Do you want to record a Stock Transfer,倉庫中不提供開始操作的庫存數量。你想記錄股票轉移嗎? +apps/erpnext/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js +98,Stock quantity to start procedure is not available in the warehouse. Do you want to record a Stock Transfer,倉庫中不提供開始操作的庫存數量。你想記錄庫存轉移嗎? DocType: Shipping Rule,Shipping Rule Type,運輸規則類型 apps/erpnext/erpnext/utilities/user_progress.py +239,Go to Rooms,去房間 apps/erpnext/erpnext/hr/doctype/payroll_entry/payroll_entry.js +259,"Company, Payment Account, From Date and To Date is mandatory",公司,付款帳戶,從日期和日期是強制性的 @@ -5871,7 +5871,7 @@ DocType: Purchase Receipt Item,Received and Accepted,收貨及允收 DocType: Staffing Plan,Staffing Plan Details,人員配置計劃詳情 ,Serial No Service Contract Expiry,序號服務合同到期 DocType: Employee Health Insurance,Employee Health Insurance,員工健康保險 -apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +331,You cannot credit and debit same account at the same time,你無法將貸方與借方在同一時間記在同一帳戶 +apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +331,You cannot credit and debit same account at the same time,你無法將貸方與借方在同一時間記在同一科目 DocType: Vital Signs,Adults' pulse rate is anywhere between 50 and 80 beats per minute.,成年人的脈率在每分鐘50到80次之間。 DocType: Naming Series,Help HTML,HTML幫助 DocType: Student Group Creation Tool,Student Group Creation Tool,學生組創建工具 @@ -5954,7 +5954,7 @@ DocType: Shopping Cart Settings,Checkout Settings,結帳設定 DocType: Student Attendance,Present,現在 apps/erpnext/erpnext/stock/doctype/packing_slip/packing_slip.py +37,Delivery Note {0} must not be submitted,送貨單{0}不能提交 DocType: Notification Control,Sales Invoice Message,銷售發票訊息 -apps/erpnext/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py +27,Closing Account {0} must be of type Liability / Equity,關閉帳戶{0}的類型必須是負債/權益 +apps/erpnext/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py +27,Closing Account {0} must be of type Liability / Equity,關閉科目{0}的類型必須是負債/權益 apps/erpnext/erpnext/hr/doctype/salary_slip/salary_slip.py +407,Salary Slip of employee {0} already created for time sheet {1},員工的工資單{0}已為時間表創建{1} DocType: Production Plan Item,Ordered Qty,訂購數量 apps/erpnext/erpnext/stock/doctype/item/item.py +822,Item {0} is disabled,項目{0}無效 @@ -5997,11 +5997,11 @@ DocType: Subscription Plan,Subscription Plan,訂閱計劃 DocType: Employee External Work History,Salary,薪水 DocType: Serial No,Delivery Document Type,交付文件類型 DocType: Item Variant Settings,Do not update variants on save,不要在保存時更新變體 -DocType: Email Digest,Receivables,應收賬款 +DocType: Email Digest,Receivables,應收帳款 DocType: Lead Source,Lead Source,主導來源 DocType: Customer,Additional information regarding the customer.,對於客戶的其他訊息。 DocType: Quality Inspection Reading,Reading 5,閱讀5 -apps/erpnext/erpnext/accounts/doctype/payment_entry/payment_entry.py +237,"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} 與 {2} 關聯, 但當事方帳戶為 {3}" +apps/erpnext/erpnext/accounts/doctype/payment_entry/payment_entry.py +237,"{0} {1} is associated with {2}, but Party Account is {3}","{0} {1} 與 {2} 關聯, 但當事方科目為 {3}" DocType: Bank Statement Settings Item,Bank Header,銀行標題 apps/erpnext/erpnext/healthcare/doctype/sample_collection/sample_collection.js +7,View Lab Tests,查看實驗室測試 DocType: Hub Users,Hub Users,Hub用戶 @@ -6060,12 +6060,12 @@ apps/erpnext/erpnext/education/doctype/program_enrollment_tool/program_enrollmen DocType: Fees,Student Details,學生細節 DocType: Purchase Invoice Item,Stock Qty,庫存數量 DocType: Purchase Invoice Item,Stock Qty,庫存數量 -DocType: QuickBooks Migrator,Default Shipping Account,默認運輸帳戶 +DocType: QuickBooks Migrator,Default Shipping Account,默認運輸科目 DocType: Loan,Repayment Period in Months,在月還款期 apps/erpnext/erpnext/templates/includes/footer/footer_extension.html +26,Error: Not a valid id?,錯誤:沒有有效的身份證? DocType: Naming Series,Update Series Number,更新序列號 DocType: Account,Equity,公平 -apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py +79,{0} {1}: 'Profit and Loss' type account {2} not allowed in Opening Entry,{0} {1}:“損益”帳戶類型{2}不允許進入開 +apps/erpnext/erpnext/accounts/doctype/gl_entry/gl_entry.py +79,{0} {1}: 'Profit and Loss' type account {2} not allowed in Opening Entry,{0} {1}:“損益”科目類型{2}不允許進入開 DocType: Job Offer,Printing Details,印刷詳情 DocType: Task,Closing Date,截止日期 DocType: Sales Order Item,Produced Quantity,生產的產品數量 @@ -6075,14 +6075,14 @@ DocType: Employee Tax Exemption Category,Max Amount,最大金額 DocType: Journal Entry,Total Amount Currency,總金額幣種 apps/erpnext/erpnext/stock/report/bom_search/bom_search.js +38,Search Sub Assemblies,搜索子組件 apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +200,Item Code required at Row No {0},於列{0}需要產品編號 -DocType: GST Account,SGST Account,SGST賬戶 +DocType: GST Account,SGST Account,SGST科目 apps/erpnext/erpnext/utilities/user_progress.py +154,Go to Items,轉到項目 DocType: Sales Partner,Partner Type,合作夥伴類型 apps/erpnext/erpnext/accounts/report/budget_variance_report/budget_variance_report.py +72,Actual,實際 DocType: Restaurant Menu,Restaurant Manager,餐廳經理 DocType: Authorization Rule,Customerwise Discount,Customerwise折扣 apps/erpnext/erpnext/config/projects.py +46,Timesheet for tasks.,時間表的任務。 -DocType: Purchase Invoice,Against Expense Account,對費用帳戶 +DocType: Purchase Invoice,Against Expense Account,對費用科目 apps/erpnext/erpnext/stock/doctype/delivery_note/delivery_note.py +287,Installation Note {0} has already been submitted,安裝注意{0}已提交 DocType: Bank Reconciliation,Get Payment Entries,獲取付款項 DocType: Quotation Item,Against Docname,對Docname @@ -6098,7 +6098,7 @@ DocType: Training Event,Employee Emails,員工電子郵件 apps/erpnext/erpnext/setup/doctype/naming_series/naming_series.py +67,Series Updated,系列更新 apps/erpnext/erpnext/accounts/doctype/account/account.py +166,Report Type is mandatory,報告類型是強制性的 DocType: Item,Serial Number Series,序列號系列 -apps/erpnext/erpnext/buying/utils.py +68,Warehouse is mandatory for stock Item {0} in row {1},倉庫是強制性的股票項目{0}行{1} +apps/erpnext/erpnext/buying/utils.py +68,Warehouse is mandatory for stock Item {0} in row {1},倉庫是強制性的庫存項目{0}行{1} apps/erpnext/erpnext/setup/setup_wizard/data/industry_type.py +45,Retail & Wholesale,零售及批發 DocType: Issue,First Responded On,首先作出回應 DocType: Website Item Group,Cross Listing of Item in multiple groups,在多組項目的交叉上市 @@ -6146,7 +6146,7 @@ DocType: Restaurant Reservation,Waitlisted,輪候 DocType: Employee Tax Exemption Declaration Category,Exemption Category,豁免類別 apps/erpnext/erpnext/accounts/doctype/account/account.py +131,Currency can not be changed after making entries using some other currency,貨幣不能使用其他貨幣進行輸入後更改 DocType: Vehicle Service,Clutch Plate,離合器壓盤 -DocType: Company,Round Off Account,四捨五入賬戶 +DocType: Company,Round Off Account,四捨五入科目 apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py +100,Administrative Expenses,行政開支 apps/erpnext/erpnext/setup/setup_wizard/data/industry_type.py +18,Consulting,諮詢 DocType: Subscription Plan,Based on price list,基於價格表 @@ -6157,7 +6157,7 @@ DocType: Purchase Invoice,Contact Email,聯絡電郵 apps/erpnext/erpnext/education/doctype/fee_schedule/fee_schedule_list.js +11,Fee Creation Pending,費用創作待定 DocType: Appraisal Goal,Score Earned,得分 DocType: Asset Category,Asset Category Name,資產類別名稱 -apps/erpnext/erpnext/setup/doctype/territory/territory.js +13,This is a root territory and cannot be edited.,集團或Ledger ,借方或貸方,是特等帳戶 +apps/erpnext/erpnext/setup/doctype/territory/territory.js +13,This is a root territory and cannot be edited.,集團或Ledger ,借方或貸方,是特等科目 apps/erpnext/erpnext/setup/doctype/sales_person/sales_person_tree.js +5,New Sales Person Name,新銷售人員的姓名 DocType: Packing Slip,Gross Weight UOM,毛重計量單位 DocType: Employee Transfer,Create New Employee Id,創建新的員工ID @@ -6170,12 +6170,12 @@ DocType: Bin,Reserved Qty for Production,預留數量生產 DocType: Student Group Creation Tool,Leave unchecked if you don't want to consider batch while making course based groups. ,如果您不想在製作基於課程的組時考慮批量,請不要選中。 DocType: Student Group Creation Tool,Leave unchecked if you don't want to consider batch while making course based groups. ,如果您不想在製作基於課程的組時考慮批量,請不要選中。 DocType: Asset,Frequency of Depreciation (Months),折舊率(月) -apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.js +542,Credit Account,信用賬戶 +apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.js +542,Credit Account,信用科目 DocType: Landed Cost Item,Landed Cost Item,到岸成本項目 apps/erpnext/erpnext/accounts/report/profitability_analysis/profitability_analysis.js +58,Show zero values,顯示零值 DocType: BOM,Quantity of item obtained after manufacturing / repacking from given quantities of raw materials,製造/從原材料數量給予重新包裝後獲得的項目數量 DocType: Lab Test,Test Group,測試組 -DocType: Payment Reconciliation,Receivable / Payable Account,應收/應付賬款 +DocType: Payment Reconciliation,Receivable / Payable Account,應收/應付帳款 DocType: Delivery Note Item,Against Sales Order Item,對銷售訂單項目 DocType: Company,Company Logo,公司標誌 apps/erpnext/erpnext/stock/doctype/item/item.py +787,Please specify Attribute Value for attribute {0},請指定屬性值的屬性{0} @@ -6199,10 +6199,10 @@ apps/erpnext/erpnext/stock/doctype/item/item.js +29,Balance,餘額 apps/erpnext/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py +66,Please select the Company,請選擇公司 DocType: Room,Seating Capacity,座位數 DocType: Lab Test Groups,Lab Test Groups,實驗室測試組 -apps/erpnext/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py +151,Party Type and Party is mandatory for {0} account,{0}帳戶必須使用派對類型和派對 +apps/erpnext/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py +151,Party Type and Party is mandatory for {0} account,{0}科目的參與方以及類型為必填 DocType: Project,Total Expense Claim (via Expense Claims),總費用報銷(通過費用報銷) DocType: GST Settings,GST Summary,消費稅總結 -apps/erpnext/erpnext/hr/doctype/daily_work_summary_group/daily_work_summary_group.py +16,Please enable default incoming account before creating Daily Work Summary Group,請在創建日常工作摘要組之前啟用默認傳入帳戶 +apps/erpnext/erpnext/hr/doctype/daily_work_summary_group/daily_work_summary_group.py +16,Please enable default incoming account before creating Daily Work Summary Group,請在創建日常工作摘要組之前啟用默認傳入科目 DocType: Assessment Result,Total Score,總得分 DocType: Crop Cycle,ISO 8601 standard,ISO 8601標準 DocType: Journal Entry,Debit Note,繳費單 @@ -6222,7 +6222,7 @@ DocType: Manufacturing Settings,Default Finished Goods Warehouse,預設成品倉 apps/erpnext/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js +380,Please select Patient,請選擇患者 apps/erpnext/erpnext/accounts/report/gross_profit/gross_profit.py +74,Sales Person,銷售人員 DocType: Hotel Room Package,Amenities,設施 -DocType: QuickBooks Migrator,Undeposited Funds Account,未存入資金賬戶 +DocType: QuickBooks Migrator,Undeposited Funds Account,未存入資金科目 apps/erpnext/erpnext/config/accounts.py +201,Budget and Cost Center,預算和成本中心 apps/erpnext/erpnext/accounts/doctype/pos_profile/pos_profile.py +65,Multiple default mode of payment is not allowed,不允許多種默認付款方式 DocType: Sales Invoice,Loyalty Points Redemption,忠誠積分兌換 @@ -6230,7 +6230,7 @@ DocType: Sales Invoice,Loyalty Points Redemption,忠誠積分兌換 DocType: Lead,Blog Subscriber,網誌訂閱者 DocType: Guardian,Alternate Number,備用號碼 apps/erpnext/erpnext/config/setup.py +83,Create rules to restrict transactions based on values.,創建規則來限制基於價值的交易。 -DocType: Cash Flow Mapping Accounts,Cash Flow Mapping Accounts,現金流量映射賬戶 +DocType: Cash Flow Mapping Accounts,Cash Flow Mapping Accounts,現金流量映射科目 apps/erpnext/erpnext/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py +49, Group Roll No,組卷號 DocType: Batch,Manufacturing Date,生產日期 apps/erpnext/erpnext/education/doctype/fee_schedule/fee_schedule_list.js +9,Fee Creation Failed,費用創作失敗 @@ -6283,7 +6283,7 @@ DocType: Fiscal Year,Year Start Date,年結開始日期 DocType: Additional Salary,Employee Name,員工姓名 DocType: Restaurant Order Entry Item,Restaurant Order Entry Item,餐廳訂單錄入項目 DocType: Purchase Invoice,Rounded Total (Company Currency),整數總計(公司貨幣) -apps/erpnext/erpnext/accounts/doctype/account/account.py +103,Cannot covert to Group because Account Type is selected.,不能隱蔽到組,因為帳戶類型選擇的。 +apps/erpnext/erpnext/accounts/doctype/account/account.py +103,Cannot covert to Group because Account Type is selected.,不能轉換到群組科目,因為科目類型選擇的。 apps/erpnext/erpnext/selling/doctype/sales_order/sales_order.py +276,{0} {1} has been modified. Please refresh.,{0} {1} 已修改。請更新。 DocType: Leave Block List,Stop users from making Leave Applications on following days.,停止用戶在下面日期提出休假申請。 apps/erpnext/erpnext/accounts/doctype/loyalty_program/loyalty_program.js +24,"If unlimited expiry for the Loyalty Points, keep the Expiry Duration empty or 0.",如果忠誠度積分無限期到期,請將到期時間保持為空或0。 @@ -6312,7 +6312,7 @@ DocType: Company,Basic Component,基本組件 apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +578,Row No {0}: Amount cannot be greater than Pending Amount against Expense Claim {1}. Pending Amount is {2},行無{0}:金額不能大於金額之前對報銷{1}。待審核金額為{2} DocType: Patient Service Unit,Medical Administrator,醫療管理員 DocType: Assessment Plan,Schedule,時間表 -DocType: Account,Parent Account,父帳戶 +DocType: Account,Parent Account,上層科目 DocType: Quality Inspection Reading,Reading 3,閱讀3 DocType: Stock Entry,Source Warehouse Address,來源倉庫地址 DocType: GL Entry,Voucher Type,憑證類型 @@ -6356,7 +6356,7 @@ apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +249,Row {0 DocType: Employee Promotion,Employee Promotion,員工晉升 DocType: Maintenance Team Member,Maintenance Team Member,維護團隊成員 apps/erpnext/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.html +16,Course Code: ,課程編號: -apps/erpnext/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +241,Please enter Expense Account,請輸入您的費用帳戶 +apps/erpnext/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +241,Please enter Expense Account,請輸入您的費用科目 DocType: Account,Stock,庫存 apps/erpnext/erpnext/accounts/doctype/payment_entry/payment_entry.js +1128,"Row #{0}: Reference Document Type must be one of Purchase Order, Purchase Invoice or Journal Entry",行#{0}:參考文件類型必須是採購訂單之一,購買發票或日記帳分錄 DocType: Employee,Current Address,當前地址 @@ -6372,7 +6372,7 @@ DocType: Sales Order,Track this Sales Order against any Project,跟踪對任何 DocType: Bank Statement Transaction Entry,Bank Statement Transaction Entry,銀行對賬單交易分錄 DocType: Sales Invoice Item,Discount and Margin,折扣和保證金 DocType: Lab Test,Prescription,處方 -DocType: Company,Default Deferred Revenue Account,默認遞延收入賬戶 +DocType: Company,Default Deferred Revenue Account,默認遞延收入科目 DocType: Project,Second Email,第二封郵件 DocType: Budget,Action if Annual Budget Exceeded on Actual,年度預算超出實際的行動 DocType: Pricing Rule,Min Qty,最小數量 @@ -6394,7 +6394,7 @@ apps/erpnext/erpnext/config/manufacturing.py +18,Generate Material Requests (MRP apps/erpnext/erpnext/accounts/doctype/pos_profile/pos_profile.py +62,Set default mode of payment,設置默認付款方式 DocType: BOM,With Operations,加入作業 DocType: Support Search Source,Post Route Key List,發布路由密鑰列表 -apps/erpnext/erpnext/accounts/party.py +288,Accounting entries have already been made in currency {0} for company {1}. Please select a receivable or payable account with currency {0}.,會計分錄已取得貨幣{0}為公司{1}。請選擇一個應收或應付賬戶幣種{0}。 +apps/erpnext/erpnext/accounts/party.py +288,Accounting entries have already been made in currency {0} for company {1}. Please select a receivable or payable account with currency {0}.,會計分錄已取得貨幣{0}為公司{1}。請選擇一個應收或應付科目幣種{0}。 DocType: Asset,Is Existing Asset,是對現有資產 DocType: Salary Component,Statistical Component,統計組成部分 DocType: Salary Component,Statistical Component,統計組成部分 @@ -6482,7 +6482,7 @@ apps/erpnext/erpnext/public/js/hub/components/item_publish_dialog.js +3,Edit Pub DocType: Packing Slip,Package Weight Details,包裝重量詳情 DocType: Leave Type,Is Compensatory,是有補償的 DocType: Restaurant Reservation,Reservation Time,預訂時間 -DocType: Payment Gateway Account,Payment Gateway Account,網路支付閘道帳戶 +DocType: Payment Gateway Account,Payment Gateway Account,網路支付閘道科目 DocType: Shopping Cart Settings,After payment completion redirect user to selected page.,支付完成後重定向用戶選擇的頁面。 DocType: Company,Existing Company,現有的公司 DocType: Healthcare Settings,Result Emailed,電子郵件結果 @@ -6507,7 +6507,7 @@ DocType: Terms and Conditions,Terms and Conditions Help,條款和條件幫助 ,Item-wise Purchase Register,項目明智的購買登記 DocType: Loyalty Point Entry,Expiry Date,到期時間 DocType: Healthcare Settings,Employee name and designation in print,員工姓名和印刷品名稱 -,accounts-browser,賬戶瀏覽器 +,accounts-browser,科目瀏覽器 apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +381,Please select Category first,請先選擇分類 apps/erpnext/erpnext/config/projects.py +13,Project master.,專案主持。 apps/erpnext/erpnext/controllers/status_updater.py +215,"To allow over-billing or over-ordering, update ""Allowance"" in Stock Settings or the Item.",要允許對賬單或過度訂貨,庫存設置或更新項目“津貼”。 @@ -6526,11 +6526,11 @@ apps/erpnext/erpnext/patches/v11_0/add_default_dispatch_notification_template.py apps/erpnext/erpnext/controllers/accounts_controller.py +693,Row #{0}: Posting Date must be same as purchase date {1} of asset {2},行#{0}:過帳日期必須是相同的購買日期{1}資產的{2} DocType: Program Enrollment,Check this if the Student is residing at the Institute's Hostel.,如果學生住在學院的旅館,請檢查。 apps/erpnext/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py +125,Please enter Sales Orders in the above table,請在上表中輸入銷售訂單 -,Stock Summary,股票摘要 +,Stock Summary,庫存摘要 apps/erpnext/erpnext/config/assets.py +62,Transfer an asset from one warehouse to another,從一個倉庫轉移資產到另一 DocType: Employee Benefit Application,Remaining Benefits (Yearly),剩餘福利(每年) apps/erpnext/erpnext/stock/doctype/material_request/material_request.js +873,Bill of Materials,材料清單 -apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +137,Row {0}: Party Type and Party is required for Receivable / Payable account {1},行{0}:黨的類型和黨的需要應收/應付帳戶{1} +apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +137,Row {0}: Party Type and Party is required for Receivable / Payable account {1},行{0}:參與方類型和參與方需要應收/應付科目{1} DocType: Employee,Leave Policy,離開政策 apps/erpnext/erpnext/buying/doctype/purchase_order/purchase_order.js +865,Update Items,更新項目 apps/erpnext/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py +94,Ref Date,參考日期 @@ -6542,7 +6542,7 @@ DocType: GL Entry,Is Opening,是開幕 DocType: Department,Expense Approvers,費用審批人 apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +228,Row {0}: Debit entry can not be linked with a {1},行{0}:借方條目不能與{1}連接 DocType: Journal Entry,Subscription Section,認購科 -apps/erpnext/erpnext/accounts/doctype/account/account.py +238,Account {0} does not exist,帳戶{0}不存在 +apps/erpnext/erpnext/accounts/doctype/account/account.py +238,Account {0} does not exist,科目{0}不存在 DocType: Training Event,Training Program,培訓計劃 DocType: Account,Cash,現金 DocType: Employee,Short biography for website and other publications.,網站和其他出版物的短的傳記。 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)