Merge branch 'develop' of https://github.com/frappe/erpnext into loan_schedule_types
This commit is contained in:
		
						commit
						51d8e9dc5e
					
				
							
								
								
									
										2
									
								
								.github/workflows/server-tests-mariadb.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/server-tests-mariadb.yml
									
									
									
									
										vendored
									
									
								
							| @ -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 }} | ||||
|  | ||||
| @ -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" | ||||
|         } | ||||
|     } | ||||
| } | ||||
|      }    | ||||
|   } | ||||
|  | ||||
| @ -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 | ||||
| } | ||||
| @ -5,7 +5,6 @@ | ||||
| import frappe | ||||
| from frappe import _ | ||||
| from frappe.model.document import Document | ||||
| from frappe.model.naming import make_autoname | ||||
| from frappe.utils import add_months, flt, fmt_money, get_last_day, getdate | ||||
| 
 | ||||
| from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( | ||||
| @ -23,11 +22,6 @@ class DuplicateBudgetError(frappe.ValidationError): | ||||
| 
 | ||||
| 
 | ||||
| class Budget(Document): | ||||
| 	def autoname(self): | ||||
| 		self.name = make_autoname( | ||||
| 			self.get(frappe.scrub(self.budget_against)) + "/" + self.fiscal_year + "/.###" | ||||
| 		) | ||||
| 
 | ||||
| 	def validate(self): | ||||
| 		if not self.get(frappe.scrub(self.budget_against)): | ||||
| 			frappe.throw(_("{0} is mandatory").format(self.budget_against)) | ||||
| @ -109,6 +103,9 @@ class Budget(Document): | ||||
| 		): | ||||
| 			self.applicable_on_booking_actual_expenses = 1 | ||||
| 
 | ||||
| 	def before_naming(self): | ||||
| 		self.naming_series = f"{{{frappe.scrub(self.budget_against)}}}./.{self.fiscal_year}/.###" | ||||
| 
 | ||||
| 
 | ||||
| def validate_expense_against_budget(args): | ||||
| 	args = frappe._dict(args) | ||||
|  | ||||
| @ -202,6 +202,7 @@ | ||||
|    "fieldname": "reference_type", | ||||
|    "fieldtype": "Select", | ||||
|    "label": "Reference Type", | ||||
|    "no_copy": 1, | ||||
|    "options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation\nInvoice Discounting\nFees\nFull and Final Statement" | ||||
|   }, | ||||
|   { | ||||
| @ -209,13 +210,15 @@ | ||||
|    "fieldtype": "Dynamic Link", | ||||
|    "in_list_view": 1, | ||||
|    "label": "Reference Name", | ||||
|    "no_copy": 1, | ||||
|    "options": "reference_type" | ||||
|   }, | ||||
|   { | ||||
|    "depends_on": "eval:doc.reference_type&&!in_list(doc.reference_type, ['Expense Claim', 'Asset', 'Employee Loan', 'Employee Advance'])", | ||||
|    "fieldname": "reference_due_date", | ||||
|    "fieldtype": "Select", | ||||
|    "label": "Reference Due Date" | ||||
|    "label": "Reference Due Date", | ||||
|    "no_copy": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "project", | ||||
| @ -274,19 +277,22 @@ | ||||
|    "fieldname": "reference_detail_no", | ||||
|    "fieldtype": "Data", | ||||
|    "hidden": 1, | ||||
|    "label": "Reference Detail No" | ||||
|    "label": "Reference Detail No", | ||||
|    "no_copy": 1 | ||||
|   } | ||||
|  ], | ||||
|  "idx": 1, | ||||
|  "istable": 1, | ||||
|  "links": [], | ||||
|  "modified": "2021-08-30 21:27:32.200299", | ||||
|  "modified": "2022-10-13 17:07:17.999191", | ||||
|  "modified_by": "Administrator", | ||||
|  "module": "Accounts", | ||||
|  "name": "Journal Entry Account", | ||||
|  "naming_rule": "Random", | ||||
|  "owner": "Administrator", | ||||
|  "permissions": [], | ||||
|  "sort_field": "modified", | ||||
|  "sort_order": "DESC", | ||||
|  "states": [], | ||||
|  "track_changes": 1 | ||||
| } | ||||
| @ -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 | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -268,6 +268,18 @@ def get_serial_no_for_item(args): | ||||
| 	return item_details | ||||
| 
 | ||||
| 
 | ||||
| def update_pricing_rule_uom(pricing_rule, args): | ||||
| 	child_doc = {"Item Code": "items", "Item Group": "item_groups", "Brand": "brands"}.get( | ||||
| 		pricing_rule.apply_on | ||||
| 	) | ||||
| 
 | ||||
| 	apply_on_field = frappe.scrub(pricing_rule.apply_on) | ||||
| 
 | ||||
| 	for row in pricing_rule.get(child_doc): | ||||
| 		if row.get(apply_on_field) == args.get(apply_on_field): | ||||
| 			pricing_rule.uom = row.uom | ||||
| 
 | ||||
| 
 | ||||
| def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=False): | ||||
| 	from erpnext.accounts.doctype.pricing_rule.utils import ( | ||||
| 		get_applied_pricing_rules, | ||||
| @ -324,6 +336,7 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=Fa | ||||
| 
 | ||||
| 			if isinstance(pricing_rule, str): | ||||
| 				pricing_rule = frappe.get_cached_doc("Pricing Rule", pricing_rule) | ||||
| 				update_pricing_rule_uom(pricing_rule, args) | ||||
| 				pricing_rule.apply_rule_on_other_items = get_pricing_rule_items(pricing_rule) or [] | ||||
| 
 | ||||
| 			if pricing_rule.get("suggestion"): | ||||
| @ -440,12 +453,15 @@ def apply_price_discount_rule(pricing_rule, item_details, args): | ||||
| 		if pricing_rule.currency == args.currency: | ||||
| 			pricing_rule_rate = pricing_rule.rate | ||||
| 
 | ||||
| 		# TODO https://github.com/frappe/erpnext/pull/23636 solve this in some other way. | ||||
| 		if pricing_rule_rate: | ||||
| 			is_blank_uom = pricing_rule.get("uom") != args.get("uom") | ||||
| 			# Override already set price list rate (from item price) | ||||
| 			# if pricing_rule_rate > 0 | ||||
| 			item_details.update( | ||||
| 				{ | ||||
| 					"price_list_rate": pricing_rule_rate * args.get("conversion_factor", 1), | ||||
| 					"price_list_rate": pricing_rule_rate | ||||
| 					* (args.get("conversion_factor", 1) if is_blank_uom else 1), | ||||
| 				} | ||||
| 			) | ||||
| 		item_details.update({"discount_percentage": 0.0}) | ||||
|  | ||||
| @ -595,6 +595,121 @@ class TestPricingRule(unittest.TestCase): | ||||
| 		frappe.get_doc("Item Price", {"item_code": "Water Flask"}).delete() | ||||
| 		item.delete() | ||||
| 
 | ||||
| 	def test_item_price_with_blank_uom_pricing_rule(self): | ||||
| 		properties = { | ||||
| 			"item_code": "Item Blank UOM", | ||||
| 			"stock_uom": "Nos", | ||||
| 			"sales_uom": "Box", | ||||
| 			"uoms": [dict(uom="Box", conversion_factor=10)], | ||||
| 		} | ||||
| 		item = make_item(properties=properties) | ||||
| 
 | ||||
| 		make_item_price("Item Blank UOM", "_Test Price List", 100) | ||||
| 
 | ||||
| 		pricing_rule_record = { | ||||
| 			"doctype": "Pricing Rule", | ||||
| 			"title": "_Test Item Blank UOM Rule", | ||||
| 			"apply_on": "Item Code", | ||||
| 			"items": [ | ||||
| 				{ | ||||
| 					"item_code": "Item Blank UOM", | ||||
| 				} | ||||
| 			], | ||||
| 			"selling": 1, | ||||
| 			"currency": "INR", | ||||
| 			"rate_or_discount": "Rate", | ||||
| 			"rate": 101, | ||||
| 			"company": "_Test Company", | ||||
| 		} | ||||
| 		rule = frappe.get_doc(pricing_rule_record) | ||||
| 		rule.insert() | ||||
| 
 | ||||
| 		si = create_sales_invoice( | ||||
| 			do_not_save=True, item_code="Item Blank UOM", uom="Box", conversion_factor=10 | ||||
| 		) | ||||
| 		si.selling_price_list = "_Test Price List" | ||||
| 		si.save() | ||||
| 
 | ||||
| 		# If UOM is blank consider it as stock UOM and apply pricing_rule on all UOM. | ||||
| 		# rate is 101, Selling UOM is Box that have conversion_factor of 10 so 101 * 10 = 1010 | ||||
| 		self.assertEqual(si.items[0].price_list_rate, 1010) | ||||
| 		self.assertEqual(si.items[0].rate, 1010) | ||||
| 
 | ||||
| 		si.delete() | ||||
| 
 | ||||
| 		si = create_sales_invoice(do_not_save=True, item_code="Item Blank UOM", uom="Nos") | ||||
| 		si.selling_price_list = "_Test Price List" | ||||
| 		si.save() | ||||
| 
 | ||||
| 		# UOM is blank so consider it as stock UOM and apply pricing_rule on all UOM. | ||||
| 		# rate is 101, Selling UOM is Nos that have conversion_factor of 1 so 101 * 1 = 101 | ||||
| 		self.assertEqual(si.items[0].price_list_rate, 101) | ||||
| 		self.assertEqual(si.items[0].rate, 101) | ||||
| 
 | ||||
| 		si.delete() | ||||
| 		rule.delete() | ||||
| 		frappe.get_doc("Item Price", {"item_code": "Item Blank UOM"}).delete() | ||||
| 
 | ||||
| 		item.delete() | ||||
| 
 | ||||
| 	def test_item_price_with_selling_uom_pricing_rule(self): | ||||
| 		properties = { | ||||
| 			"item_code": "Item UOM other than Stock", | ||||
| 			"stock_uom": "Nos", | ||||
| 			"sales_uom": "Box", | ||||
| 			"uoms": [dict(uom="Box", conversion_factor=10)], | ||||
| 		} | ||||
| 		item = make_item(properties=properties) | ||||
| 
 | ||||
| 		make_item_price("Item UOM other than Stock", "_Test Price List", 100) | ||||
| 
 | ||||
| 		pricing_rule_record = { | ||||
| 			"doctype": "Pricing Rule", | ||||
| 			"title": "_Test Item UOM other than Stock Rule", | ||||
| 			"apply_on": "Item Code", | ||||
| 			"items": [ | ||||
| 				{ | ||||
| 					"item_code": "Item UOM other than Stock", | ||||
| 					"uom": "Box", | ||||
| 				} | ||||
| 			], | ||||
| 			"selling": 1, | ||||
| 			"currency": "INR", | ||||
| 			"rate_or_discount": "Rate", | ||||
| 			"rate": 101, | ||||
| 			"company": "_Test Company", | ||||
| 		} | ||||
| 		rule = frappe.get_doc(pricing_rule_record) | ||||
| 		rule.insert() | ||||
| 
 | ||||
| 		si = create_sales_invoice( | ||||
| 			do_not_save=True, item_code="Item UOM other than Stock", uom="Box", conversion_factor=10 | ||||
| 		) | ||||
| 		si.selling_price_list = "_Test Price List" | ||||
| 		si.save() | ||||
| 
 | ||||
| 		# UOM is Box so apply pricing_rule only on Box UOM. | ||||
| 		# Selling UOM is Box and as both UOM are same no need to multiply by conversion_factor. | ||||
| 		self.assertEqual(si.items[0].price_list_rate, 101) | ||||
| 		self.assertEqual(si.items[0].rate, 101) | ||||
| 
 | ||||
| 		si.delete() | ||||
| 
 | ||||
| 		si = create_sales_invoice(do_not_save=True, item_code="Item UOM other than Stock", uom="Nos") | ||||
| 		si.selling_price_list = "_Test Price List" | ||||
| 		si.save() | ||||
| 
 | ||||
| 		# UOM is Box so pricing_rule won't apply as selling_uom is Nos. | ||||
| 		# As Pricing Rule is not applied price of 100 will be fetched from Item Price List. | ||||
| 		self.assertEqual(si.items[0].price_list_rate, 100) | ||||
| 		self.assertEqual(si.items[0].rate, 100) | ||||
| 
 | ||||
| 		si.delete() | ||||
| 		rule.delete() | ||||
| 		frappe.get_doc("Item Price", {"item_code": "Item UOM other than Stock"}).delete() | ||||
| 
 | ||||
| 		item.delete() | ||||
| 
 | ||||
| 	def test_pricing_rule_for_different_currency(self): | ||||
| 		make_item("Test Sanitizer Item") | ||||
| 
 | ||||
|  | ||||
| @ -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") | ||||
| 
 | ||||
|  | ||||
| @ -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
 | ||||
|  | ||||
| @ -12,39 +12,23 @@ | ||||
|   "supplier", | ||||
|   "supplier_name", | ||||
|   "tax_id", | ||||
|   "due_date", | ||||
|   "tax_withholding_category", | ||||
|   "column_break1", | ||||
|   "company", | ||||
|   "column_break_6", | ||||
|   "posting_date", | ||||
|   "posting_time", | ||||
|   "set_posting_time", | ||||
|   "due_date", | ||||
|   "column_break1", | ||||
|   "is_paid", | ||||
|   "is_return", | ||||
|   "return_against", | ||||
|   "apply_tds", | ||||
|   "tax_withholding_category", | ||||
|   "amended_from", | ||||
|   "accounting_dimensions_section", | ||||
|   "cost_center", | ||||
|   "dimension_col_break", | ||||
|   "project", | ||||
|   "supplier_invoice_details", | ||||
|   "bill_no", | ||||
|   "column_break_15", | ||||
|   "bill_date", | ||||
|   "returns", | ||||
|   "return_against", | ||||
|   "section_addresses", | ||||
|   "supplier_address", | ||||
|   "address_display", | ||||
|   "contact_person", | ||||
|   "contact_display", | ||||
|   "contact_mobile", | ||||
|   "contact_email", | ||||
|   "col_break_address", | ||||
|   "shipping_address", | ||||
|   "shipping_address_display", | ||||
|   "billing_address", | ||||
|   "billing_address_display", | ||||
|   "currency_and_price_list", | ||||
|   "currency", | ||||
|   "conversion_rate", | ||||
| @ -54,39 +38,33 @@ | ||||
|   "plc_conversion_rate", | ||||
|   "ignore_pricing_rule", | ||||
|   "sec_warehouse", | ||||
|   "set_warehouse", | ||||
|   "rejected_warehouse", | ||||
|   "col_break_warehouse", | ||||
|   "set_from_warehouse", | ||||
|   "supplier_warehouse", | ||||
|   "is_subcontracted", | ||||
|   "items_section", | ||||
|   "update_stock", | ||||
|   "scan_barcode", | ||||
|   "col_break_warehouse", | ||||
|   "update_stock", | ||||
|   "set_warehouse", | ||||
|   "set_from_warehouse", | ||||
|   "is_subcontracted", | ||||
|   "rejected_warehouse", | ||||
|   "supplier_warehouse", | ||||
|   "items_section", | ||||
|   "items", | ||||
|   "pricing_rule_details", | ||||
|   "pricing_rules", | ||||
|   "raw_materials_supplied", | ||||
|   "supplied_items", | ||||
|   "section_break_26", | ||||
|   "total_qty", | ||||
|   "total_net_weight", | ||||
|   "column_break_50", | ||||
|   "base_total", | ||||
|   "base_net_total", | ||||
|   "column_break_28", | ||||
|   "total_net_weight", | ||||
|   "total", | ||||
|   "net_total", | ||||
|   "taxes_section", | ||||
|   "taxes_and_charges", | ||||
|   "column_break_58", | ||||
|   "tax_category", | ||||
|   "column_break_49", | ||||
|   "shipping_rule", | ||||
|   "section_break_51", | ||||
|   "taxes_and_charges", | ||||
|   "taxes", | ||||
|   "tax_withheld_vouchers_section", | ||||
|   "tax_withheld_vouchers", | ||||
|   "sec_tax_breakup", | ||||
|   "other_charges_calculation", | ||||
|   "totals", | ||||
|   "base_taxes_and_charges_added", | ||||
|   "base_taxes_and_charges_deducted", | ||||
| @ -95,12 +73,6 @@ | ||||
|   "taxes_and_charges_added", | ||||
|   "taxes_and_charges_deducted", | ||||
|   "total_taxes_and_charges", | ||||
|   "section_break_44", | ||||
|   "apply_discount_on", | ||||
|   "base_discount_amount", | ||||
|   "column_break_46", | ||||
|   "additional_discount_percentage", | ||||
|   "discount_amount", | ||||
|   "section_break_49", | ||||
|   "base_grand_total", | ||||
|   "base_rounding_adjustment", | ||||
| @ -114,24 +86,58 @@ | ||||
|   "total_advance", | ||||
|   "outstanding_amount", | ||||
|   "disable_rounded_total", | ||||
|   "section_break_44", | ||||
|   "apply_discount_on", | ||||
|   "base_discount_amount", | ||||
|   "additional_discount_account", | ||||
|   "column_break_46", | ||||
|   "additional_discount_percentage", | ||||
|   "discount_amount", | ||||
|   "tax_withheld_vouchers_section", | ||||
|   "tax_withheld_vouchers", | ||||
|   "sec_tax_breakup", | ||||
|   "other_charges_calculation", | ||||
|   "pricing_rule_details", | ||||
|   "pricing_rules", | ||||
|   "raw_materials_supplied", | ||||
|   "supplied_items", | ||||
|   "payments_tab", | ||||
|   "payments_section", | ||||
|   "mode_of_payment", | ||||
|   "cash_bank_account", | ||||
|   "base_paid_amount", | ||||
|   "clearance_date", | ||||
|   "col_br_payments", | ||||
|   "cash_bank_account", | ||||
|   "paid_amount", | ||||
|   "base_paid_amount", | ||||
|   "advances_section", | ||||
|   "allocate_advances_automatically", | ||||
|   "get_advances", | ||||
|   "advances", | ||||
|   "advance_tax", | ||||
|   "write_off", | ||||
|   "write_off_amount", | ||||
|   "base_write_off_amount", | ||||
|   "column_break_61", | ||||
|   "write_off_account", | ||||
|   "write_off_cost_center", | ||||
|   "advances_section", | ||||
|   "allocate_advances_automatically", | ||||
|   "get_advances", | ||||
|   "advances", | ||||
|   "advance_tax", | ||||
|   "address_and_contact_tab", | ||||
|   "section_addresses", | ||||
|   "supplier_address", | ||||
|   "address_display", | ||||
|   "col_break_address", | ||||
|   "contact_person", | ||||
|   "contact_display", | ||||
|   "contact_mobile", | ||||
|   "contact_email", | ||||
|   "company_shipping_address_section", | ||||
|   "shipping_address", | ||||
|   "column_break_126", | ||||
|   "shipping_address_display", | ||||
|   "company_billing_address_section", | ||||
|   "billing_address", | ||||
|   "column_break_130", | ||||
|   "billing_address_display", | ||||
|   "terms_tab", | ||||
|   "payment_schedule_section", | ||||
|   "payment_terms_template", | ||||
|   "ignore_default_payment_terms_template", | ||||
| @ -139,23 +145,15 @@ | ||||
|   "terms_section_break", | ||||
|   "tc_name", | ||||
|   "terms", | ||||
|   "printing_settings", | ||||
|   "letter_head", | ||||
|   "select_print_heading", | ||||
|   "column_break_112", | ||||
|   "group_same_items", | ||||
|   "language", | ||||
|   "sb_14", | ||||
|   "on_hold", | ||||
|   "release_date", | ||||
|   "cb_17", | ||||
|   "hold_comment", | ||||
|   "more_info", | ||||
|   "more_info_tab", | ||||
|   "status_section", | ||||
|   "status", | ||||
|   "inter_company_invoice_reference", | ||||
|   "represents_company", | ||||
|   "column_break_147", | ||||
|   "is_internal_supplier", | ||||
|   "column_break_177", | ||||
|   "per_received", | ||||
|   "supplier_invoice_details", | ||||
|   "bill_no", | ||||
|   "column_break_15", | ||||
|   "bill_date", | ||||
|   "accounting_details_section", | ||||
|   "credit_to", | ||||
|   "party_account_currency", | ||||
| @ -163,15 +161,32 @@ | ||||
|   "against_expense_account", | ||||
|   "column_break_63", | ||||
|   "unrealized_profit_loss_account", | ||||
|   "remarks", | ||||
|   "subscription_section", | ||||
|   "from_date", | ||||
|   "to_date", | ||||
|   "column_break_114", | ||||
|   "auto_repeat", | ||||
|   "update_auto_repeat_reference", | ||||
|   "per_received", | ||||
|   "is_old_subcontracting_flow" | ||||
|   "column_break_114", | ||||
|   "from_date", | ||||
|   "to_date", | ||||
|   "printing_settings", | ||||
|   "letter_head", | ||||
|   "group_same_items", | ||||
|   "column_break_112", | ||||
|   "select_print_heading", | ||||
|   "language", | ||||
|   "sb_14", | ||||
|   "on_hold", | ||||
|   "release_date", | ||||
|   "cb_17", | ||||
|   "hold_comment", | ||||
|   "additional_info_section", | ||||
|   "is_internal_supplier", | ||||
|   "represents_company", | ||||
|   "column_break_147", | ||||
|   "inter_company_invoice_reference", | ||||
|   "is_old_subcontracting_flow", | ||||
|   "remarks", | ||||
|   "connections_tab", | ||||
|   "column_break_38" | ||||
|  ], | ||||
|  "fields": [ | ||||
|   { | ||||
| @ -354,7 +369,7 @@ | ||||
|    "collapsible_depends_on": "bill_no", | ||||
|    "fieldname": "supplier_invoice_details", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Supplier Invoice Details" | ||||
|    "label": "Supplier Invoice" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "bill_no", | ||||
| @ -377,12 +392,6 @@ | ||||
|    "oldfieldtype": "Date", | ||||
|    "print_hide": 1 | ||||
|   }, | ||||
|   { | ||||
|    "depends_on": "return_against", | ||||
|    "fieldname": "returns", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Returns" | ||||
|   }, | ||||
|   { | ||||
|    "depends_on": "return_against", | ||||
|    "fieldname": "return_against", | ||||
| @ -394,10 +403,9 @@ | ||||
|    "read_only": 1 | ||||
|   }, | ||||
|   { | ||||
|    "collapsible": 1, | ||||
|    "fieldname": "section_addresses", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Address and Contact" | ||||
|    "label": "Supplier Address" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "supplier_address", | ||||
| @ -518,11 +526,12 @@ | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "sec_warehouse", | ||||
|    "fieldtype": "Section Break" | ||||
|    "fieldtype": "Section Break", | ||||
|    "hide_border": 1, | ||||
|    "label": "Items" | ||||
|   }, | ||||
|   { | ||||
|    "depends_on": "update_stock", | ||||
|    "description": "Sets 'Accepted Warehouse' in each row of the items table.", | ||||
|    "fieldname": "set_warehouse", | ||||
|    "fieldtype": "Link", | ||||
|    "label": "Set Accepted Warehouse", | ||||
| @ -531,7 +540,6 @@ | ||||
|   }, | ||||
|   { | ||||
|    "depends_on": "update_stock", | ||||
|    "description": "Warehouse where you are maintaining stock of rejected items", | ||||
|    "fieldname": "rejected_warehouse", | ||||
|    "fieldtype": "Link", | ||||
|    "label": "Rejected Warehouse", | ||||
| @ -554,6 +562,7 @@ | ||||
|   { | ||||
|    "fieldname": "items_section", | ||||
|    "fieldtype": "Section Break", | ||||
|    "hide_border": 1, | ||||
|    "oldfieldtype": "Section Break", | ||||
|    "options": "fa fa-shopping-cart" | ||||
|   }, | ||||
| @ -581,6 +590,7 @@ | ||||
|    "reqd": 1 | ||||
|   }, | ||||
|   { | ||||
|    "collapsible": 1, | ||||
|    "fieldname": "pricing_rule_details", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Pricing Rules" | ||||
| @ -593,6 +603,7 @@ | ||||
|    "read_only": 1 | ||||
|   }, | ||||
|   { | ||||
|    "collapsible": 1, | ||||
|    "collapsible_depends_on": "supplied_items", | ||||
|    "fieldname": "raw_materials_supplied", | ||||
|    "fieldtype": "Section Break", | ||||
| @ -656,6 +667,7 @@ | ||||
|    "read_only": 1 | ||||
|   }, | ||||
|   { | ||||
|    "depends_on": "total_net_weight", | ||||
|    "fieldname": "total_net_weight", | ||||
|    "fieldtype": "Float", | ||||
|    "label": "Total Net Weight", | ||||
| @ -665,6 +677,8 @@ | ||||
|   { | ||||
|    "fieldname": "taxes_section", | ||||
|    "fieldtype": "Section Break", | ||||
|    "hide_border": 1, | ||||
|    "label": "Taxes and Charges", | ||||
|    "oldfieldtype": "Section Break", | ||||
|    "options": "fa fa-money" | ||||
|   }, | ||||
| @ -688,7 +702,8 @@ | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "section_break_51", | ||||
|    "fieldtype": "Section Break" | ||||
|    "fieldtype": "Section Break", | ||||
|    "hide_border": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "taxes_and_charges", | ||||
| @ -792,7 +807,6 @@ | ||||
|   }, | ||||
|   { | ||||
|    "collapsible": 1, | ||||
|    "collapsible_depends_on": "discount_amount", | ||||
|    "fieldname": "section_break_44", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Additional Discount" | ||||
| @ -832,7 +846,8 @@ | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "section_break_49", | ||||
|    "fieldtype": "Section Break" | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Totals" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "base_grand_total", | ||||
| @ -1003,8 +1018,6 @@ | ||||
|   }, | ||||
|   { | ||||
|    "collapsible": 1, | ||||
|    "collapsible_depends_on": "write_off_amount", | ||||
|    "depends_on": "grand_total", | ||||
|    "fieldname": "write_off", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Write Off" | ||||
| @ -1081,7 +1094,6 @@ | ||||
|    "print_hide": 1 | ||||
|   }, | ||||
|   { | ||||
|    "collapsible": 1, | ||||
|    "collapsible_depends_on": "eval:(!doc.is_return)", | ||||
|    "fieldname": "payment_schedule_section", | ||||
|    "fieldtype": "Section Break", | ||||
| @ -1102,8 +1114,6 @@ | ||||
|    "print_hide": 1 | ||||
|   }, | ||||
|   { | ||||
|    "collapsible": 1, | ||||
|    "collapsible_depends_on": "terms", | ||||
|    "fieldname": "terms_section_break", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Terms and Conditions", | ||||
| @ -1119,13 +1129,13 @@ | ||||
|   { | ||||
|    "fieldname": "terms", | ||||
|    "fieldtype": "Text Editor", | ||||
|    "label": "Terms and Conditions1" | ||||
|    "label": "Terms and Conditions" | ||||
|   }, | ||||
|   { | ||||
|    "collapsible": 1, | ||||
|    "fieldname": "printing_settings", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Printing Settings" | ||||
|    "label": "Print Settings" | ||||
|   }, | ||||
|   { | ||||
|    "allow_on_submit": 1, | ||||
| @ -1166,15 +1176,6 @@ | ||||
|    "print_hide": 1, | ||||
|    "read_only": 1 | ||||
|   }, | ||||
|   { | ||||
|    "collapsible": 1, | ||||
|    "fieldname": "more_info", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "More Information", | ||||
|    "oldfieldtype": "Section Break", | ||||
|    "options": "fa fa-file-text", | ||||
|    "print_hide": 1 | ||||
|   }, | ||||
|   { | ||||
|    "default": "0", | ||||
|    "fetch_from": "supplier.is_internal_supplier", | ||||
| @ -1260,7 +1261,7 @@ | ||||
|    "collapsible": 1, | ||||
|    "fieldname": "subscription_section", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Subscription Section", | ||||
|    "label": "Subscription", | ||||
|    "print_hide": 1 | ||||
|   }, | ||||
|   { | ||||
| @ -1339,7 +1340,7 @@ | ||||
|   }, | ||||
|   { | ||||
|    "depends_on": "eval:doc.is_internal_supplier", | ||||
|    "description": "Unrealized Profit / Loss account for intra-company transfers", | ||||
|    "description": "Unrealized Profit/Loss account for intra-company transfers", | ||||
|    "fieldname": "unrealized_profit_loss_account", | ||||
|    "fieldtype": "Link", | ||||
|    "label": "Unrealized Profit / Loss Account", | ||||
| @ -1356,7 +1357,6 @@ | ||||
|   }, | ||||
|   { | ||||
|    "depends_on": "eval:doc.update_stock && doc.is_internal_supplier", | ||||
|    "description": "Sets 'From Warehouse' in each row of the items table.", | ||||
|    "fieldname": "set_from_warehouse", | ||||
|    "fieldtype": "Link", | ||||
|    "label": "Set From Warehouse", | ||||
| @ -1422,6 +1422,7 @@ | ||||
|    "read_only": 1 | ||||
|   }, | ||||
|   { | ||||
|    "collapsible_depends_on": "tax_withheld_vouchers", | ||||
|    "fieldname": "tax_withheld_vouchers_section", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Tax Withheld Vouchers" | ||||
| @ -1433,13 +1434,92 @@ | ||||
|    "no_copy": 1, | ||||
|    "options": "Tax Withheld Vouchers", | ||||
|    "read_only": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "payments_tab", | ||||
|    "fieldtype": "Tab Break", | ||||
|    "label": "Payments" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "address_and_contact_tab", | ||||
|    "fieldtype": "Tab Break", | ||||
|    "label": "Address & Contact" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "terms_tab", | ||||
|    "fieldtype": "Tab Break", | ||||
|    "label": "Terms" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "more_info_tab", | ||||
|    "fieldtype": "Tab Break", | ||||
|    "label": "More Info" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "connections_tab", | ||||
|    "fieldtype": "Tab Break", | ||||
|    "label": "Connections", | ||||
|    "show_dashboard": 1 | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "column_break_6", | ||||
|    "fieldtype": "Column Break" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "column_break_38", | ||||
|    "fieldtype": "Column Break" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "column_break_50", | ||||
|    "fieldtype": "Column Break" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "column_break_58", | ||||
|    "fieldtype": "Column Break" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "company_shipping_address_section", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Company Shipping Address" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "column_break_126", | ||||
|    "fieldtype": "Column Break" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "company_billing_address_section", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Company Billing Address" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "column_break_130", | ||||
|    "fieldtype": "Column Break" | ||||
|   }, | ||||
|   { | ||||
|    "collapsible": 1, | ||||
|    "fieldname": "status_section", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Status" | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "column_break_177", | ||||
|    "fieldtype": "Column Break" | ||||
|   }, | ||||
|   { | ||||
|    "collapsible": 1, | ||||
|    "fieldname": "additional_info_section", | ||||
|    "fieldtype": "Section Break", | ||||
|    "label": "Additional Info", | ||||
|    "oldfieldtype": "Section Break", | ||||
|    "options": "fa fa-file-text", | ||||
|    "print_hide": 1 | ||||
|   } | ||||
|  ], | ||||
|  "icon": "fa fa-file-text", | ||||
|  "idx": 204, | ||||
|  "is_submittable": 1, | ||||
|  "links": [], | ||||
|  "modified": "2022-10-07 14:19:14.214157", | ||||
|  "modified": "2022-10-11 13:04:44.304389", | ||||
|  "modified_by": "Administrator", | ||||
|  "module": "Accounts", | ||||
|  "name": "Purchase Invoice", | ||||
|  | ||||
| @ -705,6 +705,10 @@ class PurchaseInvoice(BuyingController): | ||||
| 							) | ||||
| 						) | ||||
| 
 | ||||
| 						credit_amount = item.base_net_amount | ||||
| 						if self.is_internal_supplier and item.valuation_rate: | ||||
| 							credit_amount = flt(item.valuation_rate * item.stock_qty) | ||||
| 
 | ||||
| 						# Intentionally passed negative debit amount to avoid incorrect GL Entry validation | ||||
| 						gl_entries.append( | ||||
| 							self.get_gl_dict( | ||||
| @ -714,7 +718,7 @@ class PurchaseInvoice(BuyingController): | ||||
| 									"cost_center": item.cost_center, | ||||
| 									"project": item.project or self.project, | ||||
| 									"remarks": self.get("remarks") or _("Accounting Entry for Stock"), | ||||
| 									"debit": -1 * flt(item.base_net_amount, item.precision("base_net_amount")), | ||||
| 									"debit": -1 * flt(credit_amount, item.precision("base_net_amount")), | ||||
| 								}, | ||||
| 								warehouse_account[item.from_warehouse]["account_currency"], | ||||
| 								item=item, | ||||
| @ -1411,6 +1415,7 @@ class PurchaseInvoice(BuyingController): | ||||
| 			"Stock Ledger Entry", | ||||
| 			"Repost Item Valuation", | ||||
| 			"Payment Ledger Entry", | ||||
| 			"Purchase Invoice", | ||||
| 		) | ||||
| 		self.update_advance_tax_references(cancel=1) | ||||
| 
 | ||||
|  | ||||
| @ -711,6 +711,7 @@ | ||||
|    "label": "Valuation Rate", | ||||
|    "no_copy": 1, | ||||
|    "options": "Company:company:default_currency", | ||||
|    "precision": "6", | ||||
|    "print_hide": 1, | ||||
|    "read_only": 1 | ||||
|   }, | ||||
| @ -870,7 +871,7 @@ | ||||
|  "idx": 1, | ||||
|  "istable": 1, | ||||
|  "links": [], | ||||
|  "modified": "2022-09-27 10:54:23.980713", | ||||
|  "modified": "2022-10-12 03:37:29.032732", | ||||
|  "modified_by": "Administrator", | ||||
|  "module": "Accounts", | ||||
|  "name": "Purchase Invoice Item", | ||||
|  | ||||
| @ -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", | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -32,10 +32,20 @@ from erpnext.stock.doctype.stock_entry.test_stock_entry import ( | ||||
| 	get_qty_after_transaction, | ||||
| 	make_stock_entry, | ||||
| ) | ||||
| from erpnext.stock.utils import get_incoming_rate | ||||
| from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import ( | ||||
| 	create_stock_reconciliation, | ||||
| ) | ||||
| from erpnext.stock.utils import get_incoming_rate, get_stock_balance | ||||
| 
 | ||||
| 
 | ||||
| class TestSalesInvoice(unittest.TestCase): | ||||
| 	def setUp(self): | ||||
| 		from erpnext.stock.doctype.stock_ledger_entry.test_stock_ledger_entry import create_items | ||||
| 
 | ||||
| 		create_items(["_Test Internal Transfer Item"], uoms=[{"uom": "Box", "conversion_factor": 10}]) | ||||
| 		create_internal_parties() | ||||
| 		setup_accounts() | ||||
| 
 | ||||
| 	def make(self): | ||||
| 		w = frappe.copy_doc(test_records[0]) | ||||
| 		w.is_pos = 0 | ||||
| @ -1705,7 +1715,7 @@ class TestSalesInvoice(unittest.TestCase): | ||||
| 		si.save() | ||||
| 		self.assertEqual(si.get("items")[0].rate, flt((price_list_rate * 25) / 100 + price_list_rate)) | ||||
| 
 | ||||
| 	def test_outstanding_amount_after_advance_jv_cancelation(self): | ||||
| 	def test_outstanding_amount_after_advance_jv_cancellation(self): | ||||
| 		from erpnext.accounts.doctype.journal_entry.test_journal_entry import ( | ||||
| 			test_records as jv_test_records, | ||||
| 		) | ||||
| @ -1749,7 +1759,7 @@ class TestSalesInvoice(unittest.TestCase): | ||||
| 			flt(si.rounded_total + si.total_advance, si.precision("outstanding_amount")), | ||||
| 		) | ||||
| 
 | ||||
| 	def test_outstanding_amount_after_advance_payment_entry_cancelation(self): | ||||
| 	def test_outstanding_amount_after_advance_payment_entry_cancellation(self): | ||||
| 		pe = frappe.get_doc( | ||||
| 			{ | ||||
| 				"doctype": "Payment Entry", | ||||
| @ -2367,29 +2377,6 @@ class TestSalesInvoice(unittest.TestCase): | ||||
| 		acc_settings.save() | ||||
| 
 | ||||
| 	def test_inter_company_transaction(self): | ||||
| 		from erpnext.selling.doctype.customer.test_customer import create_internal_customer | ||||
| 
 | ||||
| 		create_internal_customer( | ||||
| 			customer_name="_Test Internal Customer", | ||||
| 			represents_company="_Test Company 1", | ||||
| 			allowed_to_interact_with="Wind Power LLC", | ||||
| 		) | ||||
| 
 | ||||
| 		if not frappe.db.exists("Supplier", "_Test Internal Supplier"): | ||||
| 			supplier = frappe.get_doc( | ||||
| 				{ | ||||
| 					"supplier_group": "_Test Supplier Group", | ||||
| 					"supplier_name": "_Test Internal Supplier", | ||||
| 					"doctype": "Supplier", | ||||
| 					"is_internal_supplier": 1, | ||||
| 					"represents_company": "Wind Power LLC", | ||||
| 				} | ||||
| 			) | ||||
| 
 | ||||
| 			supplier.append("companies", {"company": "_Test Company 1"}) | ||||
| 
 | ||||
| 			supplier.insert() | ||||
| 
 | ||||
| 		si = create_sales_invoice( | ||||
| 			company="Wind Power LLC", | ||||
| 			customer="_Test Internal Customer", | ||||
| @ -2440,38 +2427,6 @@ class TestSalesInvoice(unittest.TestCase): | ||||
| 			"Expenses Included In Valuation - _TC1", | ||||
| 		) | ||||
| 
 | ||||
| 		if not frappe.db.exists("Customer", "_Test Internal Customer"): | ||||
| 			customer = frappe.get_doc( | ||||
| 				{ | ||||
| 					"customer_group": "_Test Customer Group", | ||||
| 					"customer_name": "_Test Internal Customer", | ||||
| 					"customer_type": "Individual", | ||||
| 					"doctype": "Customer", | ||||
| 					"territory": "_Test Territory", | ||||
| 					"is_internal_customer": 1, | ||||
| 					"represents_company": "_Test Company 1", | ||||
| 				} | ||||
| 			) | ||||
| 
 | ||||
| 			customer.append("companies", {"company": "Wind Power LLC"}) | ||||
| 
 | ||||
| 			customer.insert() | ||||
| 
 | ||||
| 		if not frappe.db.exists("Supplier", "_Test Internal Supplier"): | ||||
| 			supplier = frappe.get_doc( | ||||
| 				{ | ||||
| 					"supplier_group": "_Test Supplier Group", | ||||
| 					"supplier_name": "_Test Internal Supplier", | ||||
| 					"doctype": "Supplier", | ||||
| 					"is_internal_supplier": 1, | ||||
| 					"represents_company": "Wind Power LLC", | ||||
| 				} | ||||
| 			) | ||||
| 
 | ||||
| 			supplier.append("companies", {"company": "_Test Company 1"}) | ||||
| 
 | ||||
| 			supplier.insert() | ||||
| 
 | ||||
| 		# begin test | ||||
| 		si = create_sales_invoice( | ||||
| 			company="Wind Power LLC", | ||||
| @ -2541,34 +2496,9 @@ class TestSalesInvoice(unittest.TestCase): | ||||
| 		se.cancel() | ||||
| 
 | ||||
| 	def test_internal_transfer_gl_entry(self): | ||||
| 		## Create internal transfer account | ||||
| 		from erpnext.selling.doctype.customer.test_customer import create_internal_customer | ||||
| 
 | ||||
| 		account = create_account( | ||||
| 			account_name="Unrealized Profit", | ||||
| 			parent_account="Current Liabilities - TCP1", | ||||
| 			company="_Test Company with perpetual inventory", | ||||
| 		) | ||||
| 
 | ||||
| 		frappe.db.set_value( | ||||
| 			"Company", "_Test Company with perpetual inventory", "unrealized_profit_loss_account", account | ||||
| 		) | ||||
| 
 | ||||
| 		customer = create_internal_customer( | ||||
| 			"_Test Internal Customer 2", | ||||
| 			"_Test Company with perpetual inventory", | ||||
| 			"_Test Company with perpetual inventory", | ||||
| 		) | ||||
| 
 | ||||
| 		create_internal_supplier( | ||||
| 			"_Test Internal Supplier 2", | ||||
| 			"_Test Company with perpetual inventory", | ||||
| 			"_Test Company with perpetual inventory", | ||||
| 		) | ||||
| 
 | ||||
| 		si = create_sales_invoice( | ||||
| 			company="_Test Company with perpetual inventory", | ||||
| 			customer=customer, | ||||
| 			customer="_Test Internal Customer 2", | ||||
| 			debit_to="Debtors - TCP1", | ||||
| 			warehouse="Stores - TCP1", | ||||
| 			income_account="Sales - TCP1", | ||||
| @ -2582,7 +2512,7 @@ class TestSalesInvoice(unittest.TestCase): | ||||
| 		si.update_stock = 1 | ||||
| 		si.items[0].target_warehouse = "Work In Progress - TCP1" | ||||
| 
 | ||||
| 		# Add stock to stores for succesful stock transfer | ||||
| 		# Add stock to stores for successful stock transfer | ||||
| 		make_stock_entry( | ||||
| 			target="Stores - TCP1", company="_Test Company with perpetual inventory", qty=1, basic_rate=100 | ||||
| 		) | ||||
| @ -2638,6 +2568,77 @@ class TestSalesInvoice(unittest.TestCase): | ||||
| 
 | ||||
| 		check_gl_entries(self, target_doc.name, pi_gl_entries, add_days(nowdate(), -1)) | ||||
| 
 | ||||
| 	def test_internal_transfer_gl_precision_issues(self): | ||||
| 		# Make a stock queue of an item with two valuations | ||||
| 
 | ||||
| 		# Remove all existing stock for this | ||||
| 		if get_stock_balance("_Test Internal Transfer Item", "Stores - TCP1", "2022-04-10"): | ||||
| 			create_stock_reconciliation( | ||||
| 				item_code="_Test Internal Transfer Item", | ||||
| 				warehouse="Stores - TCP1", | ||||
| 				qty=0, | ||||
| 				rate=0, | ||||
| 				company="_Test Company with perpetual inventory", | ||||
| 				expense_account="Stock Adjustment - TCP1" | ||||
| 				if frappe.get_all("Stock Ledger Entry") | ||||
| 				else "Temporary Opening - TCP1", | ||||
| 				posting_date="2020-04-10", | ||||
| 				posting_time="14:00", | ||||
| 			) | ||||
| 
 | ||||
| 		make_stock_entry( | ||||
| 			item_code="_Test Internal Transfer Item", | ||||
| 			target="Stores - TCP1", | ||||
| 			qty=9000000, | ||||
| 			basic_rate=52.0, | ||||
| 			posting_date="2020-04-10", | ||||
| 			posting_time="14:00", | ||||
| 		) | ||||
| 		make_stock_entry( | ||||
| 			item_code="_Test Internal Transfer Item", | ||||
| 			target="Stores - TCP1", | ||||
| 			qty=60000000, | ||||
| 			basic_rate=52.349777, | ||||
| 			posting_date="2020-04-10", | ||||
| 			posting_time="14:00", | ||||
| 		) | ||||
| 
 | ||||
| 		# Make an internal transfer Sales Invoice Stock in non stock uom to check | ||||
| 		# for rounding errors while converting to stock uom | ||||
| 		si = create_sales_invoice( | ||||
| 			company="_Test Company with perpetual inventory", | ||||
| 			customer="_Test Internal Customer 2", | ||||
| 			item_code="_Test Internal Transfer Item", | ||||
| 			qty=5000000, | ||||
| 			uom="Box", | ||||
| 			debit_to="Debtors - TCP1", | ||||
| 			warehouse="Stores - TCP1", | ||||
| 			income_account="Sales - TCP1", | ||||
| 			expense_account="Cost of Goods Sold - TCP1", | ||||
| 			cost_center="Main - TCP1", | ||||
| 			currency="INR", | ||||
| 			do_not_save=1, | ||||
| 		) | ||||
| 
 | ||||
| 		# Check GL Entries with precision | ||||
| 		si.update_stock = 1 | ||||
| 		si.items[0].target_warehouse = "Work In Progress - TCP1" | ||||
| 		si.items[0].conversion_factor = 10 | ||||
| 		si.save() | ||||
| 		si.submit() | ||||
| 
 | ||||
| 		# Check if adjustment entry is created | ||||
| 		self.assertTrue( | ||||
| 			frappe.db.exists( | ||||
| 				"GL Entry", | ||||
| 				{ | ||||
| 					"voucher_type": "Sales Invoice", | ||||
| 					"voucher_no": si.name, | ||||
| 					"remarks": "Rounding gain/loss Entry for Stock Transfer", | ||||
| 				}, | ||||
| 			) | ||||
| 		) | ||||
| 
 | ||||
| 	def test_item_tax_net_range(self): | ||||
| 		item = create_item("T Shirt") | ||||
| 
 | ||||
| @ -3077,7 +3078,7 @@ class TestSalesInvoice(unittest.TestCase): | ||||
| 			[deferred_account, 2022.47, 0.0, "2019-03-15"], | ||||
| 		] | ||||
| 
 | ||||
| 		gl_entries = gl_entries = frappe.db.sql( | ||||
| 		gl_entries = frappe.db.sql( | ||||
| 			"""select account, debit, credit, posting_date | ||||
| 			from `tabGL Entry` | ||||
| 			where voucher_type='Journal Entry' and voucher_detail_no=%s and posting_date <= %s | ||||
| @ -3227,6 +3228,22 @@ class TestSalesInvoice(unittest.TestCase): | ||||
| 
 | ||||
| 		self.assertTrue(return_si.docstatus == 1) | ||||
| 
 | ||||
| 	def test_sales_invoice_with_payable_tax_account(self): | ||||
| 		si = create_sales_invoice(do_not_submit=True) | ||||
| 		si.append( | ||||
| 			"taxes", | ||||
| 			{ | ||||
| 				"charge_type": "Actual", | ||||
| 				"account_head": "Creditors - _TC", | ||||
| 				"description": "Test", | ||||
| 				"cost_center": "Main - _TC", | ||||
| 				"tax_amount": 10, | ||||
| 				"total": 10, | ||||
| 				"dont_recompute_tax": 0, | ||||
| 			}, | ||||
| 		) | ||||
| 		self.assertRaises(frappe.ValidationError, si.submit) | ||||
| 
 | ||||
| 
 | ||||
| def get_sales_invoice_for_e_invoice(): | ||||
| 	si = make_sales_invoice_for_ewaybill() | ||||
| @ -3306,6 +3323,7 @@ def create_sales_invoice(**args): | ||||
| 			"item_name": args.item_name or "_Test Item", | ||||
| 			"description": args.description or "_Test Item", | ||||
| 			"warehouse": args.warehouse or "_Test Warehouse - _TC", | ||||
| 			"target_warehouse": args.target_warehouse, | ||||
| 			"qty": args.qty or 1, | ||||
| 			"uom": args.uom or "Nos", | ||||
| 			"stock_uom": args.uom or "Nos", | ||||
| @ -3318,7 +3336,7 @@ def create_sales_invoice(**args): | ||||
| 			"asset": args.asset or None, | ||||
| 			"cost_center": args.cost_center or "_Test Cost Center - _TC", | ||||
| 			"serial_no": args.serial_no, | ||||
| 			"conversion_factor": 1, | ||||
| 			"conversion_factor": args.get("conversion_factor", 1), | ||||
| 			"incoming_rate": args.incoming_rate or 0, | ||||
| 			"batch_no": args.batch_no or None, | ||||
| 		}, | ||||
| @ -3431,6 +3449,34 @@ def get_taxes_and_charges(): | ||||
| 	] | ||||
| 
 | ||||
| 
 | ||||
| def create_internal_parties(): | ||||
| 	from erpnext.selling.doctype.customer.test_customer import create_internal_customer | ||||
| 
 | ||||
| 	create_internal_customer( | ||||
| 		customer_name="_Test Internal Customer", | ||||
| 		represents_company="_Test Company 1", | ||||
| 		allowed_to_interact_with="Wind Power LLC", | ||||
| 	) | ||||
| 
 | ||||
| 	create_internal_customer( | ||||
| 		customer_name="_Test Internal Customer 2", | ||||
| 		represents_company="_Test Company with perpetual inventory", | ||||
| 		allowed_to_interact_with="_Test Company with perpetual inventory", | ||||
| 	) | ||||
| 
 | ||||
| 	create_internal_supplier( | ||||
| 		supplier_name="_Test Internal Supplier", | ||||
| 		represents_company="Wind Power LLC", | ||||
| 		allowed_to_interact_with="_Test Company 1", | ||||
| 	) | ||||
| 
 | ||||
| 	create_internal_supplier( | ||||
| 		supplier_name="_Test Internal Supplier 2", | ||||
| 		represents_company="_Test Company with perpetual inventory", | ||||
| 		allowed_to_interact_with="_Test Company with perpetual inventory", | ||||
| 	) | ||||
| 
 | ||||
| 
 | ||||
| def create_internal_supplier(supplier_name, represents_company, allowed_to_interact_with): | ||||
| 	if not frappe.db.exists("Supplier", supplier_name): | ||||
| 		supplier = frappe.get_doc( | ||||
| @ -3453,6 +3499,19 @@ def create_internal_supplier(supplier_name, represents_company, allowed_to_inter | ||||
| 	return supplier_name | ||||
| 
 | ||||
| 
 | ||||
| def setup_accounts(): | ||||
| 	## Create internal transfer account | ||||
| 	account = create_account( | ||||
| 		account_name="Unrealized Profit", | ||||
| 		parent_account="Current Liabilities - TCP1", | ||||
| 		company="_Test Company with perpetual inventory", | ||||
| 	) | ||||
| 
 | ||||
| 	frappe.db.set_value( | ||||
| 		"Company", "_Test Company with perpetual inventory", "unrealized_profit_loss_account", account | ||||
| 	) | ||||
| 
 | ||||
| 
 | ||||
| def add_taxes(doc): | ||||
| 	doc.append( | ||||
| 		"taxes", | ||||
|  | ||||
| @ -820,6 +820,7 @@ | ||||
|    "label": "Incoming Rate (Costing)", | ||||
|    "no_copy": 1, | ||||
|    "options": "Company:company:default_currency", | ||||
|    "precision": "6", | ||||
|    "print_hide": 1 | ||||
|   }, | ||||
|   { | ||||
| @ -875,7 +876,7 @@ | ||||
|  "idx": 1, | ||||
|  "istable": 1, | ||||
|  "links": [], | ||||
|  "modified": "2022-09-06 14:17:43.394309", | ||||
|  "modified": "2022-10-10 20:57:38.340026", | ||||
|  "modified_by": "Administrator", | ||||
|  "module": "Accounts", | ||||
|  "name": "Sales Invoice Item", | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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) | ||||
| 
 | ||||
|  | ||||
| @ -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", | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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", | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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 | ||||
| 
 | ||||
|  | ||||
| @ -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 | ||||
| 
 | ||||
|  | ||||
| @ -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( | ||||
|  | ||||
| @ -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"): | ||||
|  | ||||
| @ -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", | ||||
|  | ||||
| @ -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", | ||||
|  | ||||
| @ -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", | ||||
|  | ||||
| @ -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 = { | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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}) | ||||
|  | ||||
| @ -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 | ||||
| 			), | ||||
| 			{ | ||||
|  | ||||
| @ -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" | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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): | ||||
| 	""" | ||||
|  | ||||
| @ -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\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"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\":\"<span class=\\\"h4\\\"><b>Reports & Masters</b></span>\",\"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\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"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\":\"<span class=\\\"h4\\\"><b>Reports & Masters</b></span>\",\"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", | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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", | ||||
|  | ||||
| @ -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, | ||||
| 		), | ||||
|  | ||||
| @ -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'), () => { | ||||
|  | ||||
| @ -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" | ||||
| } | ||||
| } | ||||
| @ -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", | ||||
|  | ||||
| @ -18,6 +18,7 @@ from erpnext.accounts.doctype.sales_invoice.sales_invoice import ( | ||||
| 	update_linked_doc, | ||||
| 	validate_inter_company_party, | ||||
| ) | ||||
| from erpnext.accounts.party import get_party_account | ||||
| from erpnext.controllers.selling_controller import SellingController | ||||
| from erpnext.manufacturing.doctype.production_plan.production_plan import ( | ||||
| 	get_items_for_material_requests, | ||||
| @ -727,6 +728,8 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False): | ||||
| 		if source.loyalty_points and source.order_type == "Shopping Cart": | ||||
| 			target.redeem_loyalty_points = 1 | ||||
| 
 | ||||
| 		target.debit_to = get_party_account("Customer", source.customer, source.company) | ||||
| 
 | ||||
| 	def update_item(source, target, source_parent): | ||||
| 		target.amount = flt(source.amount) - flt(source.billed_amt) | ||||
| 		target.base_amount = target.amount * flt(source_parent.conversion_rate) | ||||
|  | ||||
| @ -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 } | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| @ -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"}, | ||||
| } | ||||
| @ -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", | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -753,6 +753,7 @@ | ||||
|    "fieldtype": "Currency", | ||||
|    "label": "Incoming Rate", | ||||
|    "no_copy": 1, | ||||
|    "precision": "6", | ||||
|    "print_hide": 1, | ||||
|    "read_only": 1 | ||||
|   }, | ||||
| @ -813,7 +814,7 @@ | ||||
|  "index_web_pages_for_search": 1, | ||||
|  "istable": 1, | ||||
|  "links": [], | ||||
|  "modified": "2022-09-06 14:19:42.876357", | ||||
|  "modified": "2022-10-12 03:36:05.344847", | ||||
|  "modified_by": "Administrator", | ||||
|  "module": "Stock", | ||||
|  "name": "Delivery Note Item", | ||||
|  | ||||
| @ -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"): | ||||
|  | ||||
| @ -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( | ||||
|  | ||||
| @ -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", | ||||
|  | ||||
| @ -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", | ||||
|  | ||||
| @ -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 | ||||
| 
 | ||||
|  | ||||
| @ -744,6 +744,7 @@ | ||||
|    "oldfieldname": "valuation_rate", | ||||
|    "oldfieldtype": "Currency", | ||||
|    "options": "Company:company:default_currency", | ||||
|    "precision": "6", | ||||
|    "print_hide": 1, | ||||
|    "print_width": "80px", | ||||
|    "read_only": 1, | ||||
| @ -999,7 +1000,7 @@ | ||||
|  "idx": 1, | ||||
|  "istable": 1, | ||||
|  "links": [], | ||||
|  "modified": "2022-07-28 19:27:54.880781", | ||||
|  "modified": "2022-10-12 03:37:59.516609", | ||||
|  "modified_by": "Administrator", | ||||
|  "module": "Stock", | ||||
|  "name": "Purchase Receipt Item", | ||||
|  | ||||
| @ -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": [] | ||||
| } | ||||
| @ -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") | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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 | ||||
| 
 | ||||
|  | ||||
| @ -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 | ||||
| 
 | ||||
|  | ||||
| @ -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) | ||||
| 
 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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) | ||||
| 
 | ||||
|  | ||||
| @ -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: | ||||
|  | ||||
| @ -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()] | ||||
|  | ||||
| @ -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() | ||||
|  | ||||
| @ -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): | ||||
|  | ||||
| @ -542,6 +542,14 @@ class update_entries_after(object): | ||||
| 		if not self.args.get("sle_id"): | ||||
| 			self.get_dynamic_incoming_outgoing_rate(sle) | ||||
| 
 | ||||
| 		if ( | ||||
| 			sle.voucher_type in ["Purchase Receipt", "Purchase Invoice"] | ||||
| 			and sle.voucher_detail_no | ||||
| 			and sle.actual_qty < 0 | ||||
| 			and frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "is_internal_supplier") | ||||
| 		): | ||||
| 			sle.outgoing_rate = get_incoming_rate_for_inter_company_transfer(sle) | ||||
| 
 | ||||
| 		if get_serial_nos(sle.serial_no): | ||||
| 			self.get_serialized_values(sle) | ||||
| 			self.wh_data.qty_after_transaction += flt(sle.actual_qty) | ||||
| @ -589,6 +597,7 @@ class update_entries_after(object): | ||||
| 		sle.stock_queue = json.dumps(self.wh_data.stock_queue) | ||||
| 		sle.stock_value_difference = stock_value_difference | ||||
| 		sle.doctype = "Stock Ledger Entry" | ||||
| 
 | ||||
| 		frappe.get_doc(sle).db_update() | ||||
| 
 | ||||
| 		if not self.args.get("sle_id"): | ||||
| @ -652,22 +661,7 @@ class update_entries_after(object): | ||||
| 				and sle.voucher_detail_no | ||||
| 				and frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "is_internal_supplier") | ||||
| 			): | ||||
| 				field = ( | ||||
| 					"delivery_note_item" if sle.voucher_type == "Purchase Receipt" else "sales_invoice_item" | ||||
| 				) | ||||
| 				doctype = ( | ||||
| 					"Delivery Note Item" if sle.voucher_type == "Purchase Receipt" else "Sales Invoice Item" | ||||
| 				) | ||||
| 				refernce_name = frappe.get_cached_value( | ||||
| 					sle.voucher_type + " Item", sle.voucher_detail_no, field | ||||
| 				) | ||||
| 
 | ||||
| 				if refernce_name: | ||||
| 					rate = frappe.get_cached_value( | ||||
| 						doctype, | ||||
| 						refernce_name, | ||||
| 						"incoming_rate", | ||||
| 					) | ||||
| 				rate = get_incoming_rate_for_inter_company_transfer(sle) | ||||
| 			else: | ||||
| 				if sle.voucher_type in ("Purchase Receipt", "Purchase Invoice"): | ||||
| 					rate_field = "valuation_rate" | ||||
| @ -748,14 +742,12 @@ class update_entries_after(object): | ||||
| 
 | ||||
| 	def update_rate_on_purchase_receipt(self, sle, outgoing_rate): | ||||
| 		if frappe.db.exists(sle.voucher_type + " Item", sle.voucher_detail_no): | ||||
| 			frappe.db.set_value( | ||||
| 				sle.voucher_type + " Item", | ||||
| 				sle.voucher_detail_no, | ||||
| 				{ | ||||
| 					"base_net_rate": outgoing_rate, | ||||
| 					"valuation_rate": outgoing_rate, | ||||
| 				}, | ||||
| 			) | ||||
| 			if sle.voucher_type in ["Purchase Receipt", "Purchase Invoice"] and frappe.get_cached_value( | ||||
| 				sle.voucher_type, sle.voucher_no, "is_internal_supplier" | ||||
| 			): | ||||
| 				frappe.db.set_value( | ||||
| 					f"{sle.voucher_type} Item", sle.voucher_detail_no, "valuation_rate", sle.outgoing_rate | ||||
| 				) | ||||
| 		else: | ||||
| 			frappe.db.set_value( | ||||
| 				"Purchase Receipt Item Supplied", sle.voucher_detail_no, "rate", outgoing_rate | ||||
| @ -1546,3 +1538,25 @@ def is_negative_stock_allowed(*, item_code: Optional[str] = None) -> bool: | ||||
| 	if item_code and cint(frappe.db.get_value("Item", item_code, "allow_negative_stock", cache=True)): | ||||
| 		return True | ||||
| 	return False | ||||
| 
 | ||||
| 
 | ||||
| def get_incoming_rate_for_inter_company_transfer(sle) -> float: | ||||
| 	""" | ||||
| 	For inter company transfer, incoming rate is the average of the outgoing rate | ||||
| 	""" | ||||
| 	rate = 0.0 | ||||
| 
 | ||||
| 	field = "delivery_note_item" if sle.voucher_type == "Purchase Receipt" else "sales_invoice_item" | ||||
| 
 | ||||
| 	doctype = "Delivery Note Item" if sle.voucher_type == "Purchase Receipt" else "Sales Invoice Item" | ||||
| 
 | ||||
| 	reference_name = frappe.get_cached_value(sle.voucher_type + " Item", sle.voucher_detail_no, field) | ||||
| 
 | ||||
| 	if reference_name: | ||||
| 		rate = frappe.get_cached_value( | ||||
| 			doctype, | ||||
| 			reference_name, | ||||
| 			"incoming_rate", | ||||
| 		) | ||||
| 
 | ||||
| 	return rate | ||||
|  | ||||
| @ -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 {} | ||||
| 
 | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user