Merge branch 'develop' into payment-req-status-fix

This commit is contained in:
Saqib 2020-04-03 11:29:15 +05:30 committed by GitHub
commit e2c355f670
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
88 changed files with 1216 additions and 917 deletions

View File

@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
__version__ = '12.2.0'
__version__ = '12.0.0-dev'
def get_default_company(user=None):
'''Get default company for user'''

View File

@ -102,7 +102,7 @@ class Account(NestedSet):
if not frappe.db.get_value("Account",
{'account_name': self.account_name, 'company': ancestors[0]}, 'name'):
frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0]))
else:
elif self.parent_account:
descendants = get_descendants_of('Company', self.company)
if not descendants: return
parent_acc_name_map = {}

View File

@ -2433,29 +2433,26 @@
"Erl\u00f6se aus Verk\u00e4ufen Sachanlageverm\u00f6gen (bei Buchgewinn)": {
"account_number": "4849"
},
"Erl\u00f6se aus Verk\u00e4ufen immaterieller VG (bei Buchgewinn) (Gruppe)": {
"is_group": 1,
"Erl\u00f6se aus Verk\u00e4ufen immaterieller VG (bei Buchgewinn)": {
"account_number": "4850"
},
"Erl\u00f6se aus Verk\u00e4ufen Finanzanlagen (bei Buchgewinn)": {
"account_number": "4851"
},
"Erl\u00f6se aus Verk\u00e4ufen Finanzanlagen (inl\u00e4ndische Kap.Ges., bei Buchgewinn)": {
"account_number": "4852"
},
"Anlagenabg\u00e4nge Sachanlagen (Restbuchwert bei Buchvergewinn)": {
"account_number": "4855"
},
"Anlagenabg\u00e4nge immaterielle VG (Restbuchwert bei Buchgewinn)": {
"account_number": "4856"
},
"Anlagenabg\u00e4nge Finanzanlagen (Restbuchwert bei Buchgewinn)": {
"account_number": "4857"
},
"Anlagenabg\u00e4nge Finanzanlagen (inl\u00e4ndische Kap.Ges., Restbuchwert bei Buchgewinn)": {
"account_number": "4858"
}
"Erl\u00f6se aus Verk\u00e4ufen immaterieller VG (bei Buchgewinn)": {
"account_number": "4850"
},
"Erl\u00f6se aus Verk\u00e4ufen Finanzanlagen (bei Buchgewinn)": {
"account_number": "4851"
},
"Erl\u00f6se aus Verk\u00e4ufen Finanzanlagen (inl\u00e4ndische Kap.Ges., bei Buchgewinn)": {
"account_number": "4852"
},
"Anlagenabg\u00e4nge Sachanlagen (Restbuchwert bei Buchvergewinn)": {
"account_number": "4855"
},
"Anlagenabg\u00e4nge immaterielle VG (Restbuchwert bei Buchgewinn)": {
"account_number": "4856"
},
"Anlagenabg\u00e4nge Finanzanlagen (Restbuchwert bei Buchgewinn)": {
"account_number": "4857"
},
"Anlagenabg\u00e4nge Finanzanlagen (inl\u00e4ndische Kap.Ges., Restbuchwert bei Buchgewinn)": {
"account_number": "4858"
},
"Ertr\u00e4ge aus Zuschreibungen des Sachanlageverm\u00f6gens": {
"account_number": "4910",
@ -2578,20 +2575,17 @@
"Entnahme von Gegenst\u00e4nden ohne USt": {
"account_number": "4605"
},
"Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternehmens 7 % USt (Gruppe)": {
"is_group": 1,
"Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternehmens 7 % USt": {
"account_number": "4630"
},
"Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternehmens ohne USt": {
"account_number": "4637"
},
"Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternnehmens ohne USt (Telefon-Nutzung)": {
"account_number": "4638"
},
"Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternehmens ohne USt (Kfz-Nutzung)": {
"account_number": "4639"
}
"Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternehmens 7 % USt": {
"account_number": "4630"
},
"Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternehmens ohne USt": {
"account_number": "4637"
},
"Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternnehmens ohne USt (Telefon-Nutzung)": {
"account_number": "4638"
},
"Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternehmens ohne USt (Kfz-Nutzung)": {
"account_number": "4639"
},
"Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternehmens 19 % USt (Gruppe)": {
"is_group": 1,
@ -2629,14 +2623,11 @@
"Unentgeltliche Zuwendung von Gegenst\u00e4nden ohne USt": {
"account_number": "4689"
},
"Nicht steuerbare Ums\u00e4tze (Innenums\u00e4tze) (Gruppe)": {
"is_group": 1,
"Nicht steuerbare Ums\u00e4tze (Innenums\u00e4tze)": {
"account_number": "4690"
},
"Umsatzsteuerverg\u00fctungen, z.B. nach \u00a7 24 UStG": {
"account_number": "4695"
}
"Nicht steuerbare Ums\u00e4tze (Innenums\u00e4tze)": {
"account_number": "4690"
},
"Umsatzsteuerverg\u00fctungen, z.B. nach \u00a7 24 UStG": {
"account_number": "4695"
},
"Au\u00dferordentliche Ertr\u00e4ge (Gruppe)": {
"is_group": 1,
@ -2646,41 +2637,35 @@
"Au\u00dferordentliche Ertr\u00e4ge finanzwirksam": {
"account_number": "7401"
},
"Au\u00dferordentliche Ertr\u00e4ge nicht finanzwirksam (Gruppe)": {
"is_group": 1,
"Au\u00dferordentliche Ertr\u00e4ge nicht finanzwirksam": {
"account_number": "7450"
},
"Ertr\u00e4ge durch Verschmelzung und Umwandlung": {
"account_number": "7451"
},
"Ertr\u00e4ge durch den Verkauf von bedeutenden Beteiligungen": {
"account_number": "7452"
},
"Ert\u00e4ge durch den Verkauf von bedeutenden Grundst\u00fccken": {
"account_number": "7453"
},
"Gewinn aus der Ver\u00e4u\u00dferung oder der Aufgabe von Gesch\u00e4ftsaktivit\u00e4ten nach Steuern": {
"account_number": "7454"
}
"Au\u00dferordentliche Ertr\u00e4ge nicht finanzwirksam": {
"account_number": "7450"
},
"Au\u00dferordentliche Ertr\u00e4ge aus der Anwendung von \u00dcbergangsvorschriften (Gruppe)": {
"is_group": 1,
"Au\u00dferordentliche Ertr\u00e4ge aus der Anwendung von \u00dcbergangsvorschriften": {
"account_number": "7460"
},
"Au\u00dferordentliche Ertr\u00e4ge: Zuschreibung f. Sachanlageverm\u00f6gen": {
"account_number": "7461"
},
"Au\u00dferordentliche Ertr\u00e4ge: Zuschreibung f. Finanzanlageverm\u00f6gen": {
"account_number": "7462"
},
"Au\u00dferordentliche Ertr\u00e4ge: Wertpapiere im Umlaufverm\u00f6gen": {
"account_number": "7463"
},
"Au\u00dferordentliche Ertr\u00e4ge: latente Steuern": {
"account_number": "7464"
}
"Ertr\u00e4ge durch Verschmelzung und Umwandlung": {
"account_number": "7451"
},
"Ertr\u00e4ge durch den Verkauf von bedeutenden Beteiligungen": {
"account_number": "7452"
},
"Ert\u00e4ge durch den Verkauf von bedeutenden Grundst\u00fccken": {
"account_number": "7453"
},
"Gewinn aus der Ver\u00e4u\u00dferung oder der Aufgabe von Gesch\u00e4ftsaktivit\u00e4ten nach Steuern": {
"account_number": "7454"
},
"Au\u00dferordentliche Ertr\u00e4ge aus der Anwendung von \u00dcbergangsvorschriften": {
"account_number": "7460"
},
"Au\u00dferordentliche Ertr\u00e4ge: Zuschreibung f. Sachanlageverm\u00f6gen": {
"account_number": "7461"
},
"Au\u00dferordentliche Ertr\u00e4ge: Zuschreibung f. Finanzanlageverm\u00f6gen": {
"account_number": "7462"
},
"Au\u00dferordentliche Ertr\u00e4ge: Wertpapiere im Umlaufverm\u00f6gen": {
"account_number": "7463"
},
"Au\u00dferordentliche Ertr\u00e4ge: latente Steuern": {
"account_number": "7464"
}
}
},
@ -2718,40 +2703,43 @@
},
"Erl\u00f6sschm\u00e4lerungen aus im Inland steuerpfl. EU-Lieferungen 16 % USt": {
"account_number": "4729"
}
},
"Gew\u00e4hrte Skonti (Gruppe)": {
"is_group": 1,
"Gew. Skonti": {
"account_number": "4730"
},
"Gew\u00e4hrte Skonti (Gruppe)": {
"is_group": 1,
"Gew. Skonti": {
"account_number": "4730"
},
"Gew. Skonti 7 % USt": {
"account_number": "4731"
},
"Gew. Skonti 19 % USt": {
"account_number": "4736"
},
"Gew. Skonti aus Lieferungen von Mobilfunkger./Schaltkr., f. die der Leistungsempf. die Ust. schuldet": {
"account_number": "4738"
},
"Gew. Skonti aus Leistungen, f. die der Leistungsempf. die Umsatzsteuer nach \u00a7 13b UStG schuldet": {
"account_number": "4741"
},
"Gew. Skonti aus Erl\u00f6sen aus im anderen EU-Land steuerpfl. Leistungen, f. die der Leistungsempf. die Ust. schuldet": {
"account_number": "4742"
},
"Gew. Skonti aus steuerfreien innergem. Lieferungen \u00a7 4 Nr. 1b UStG": {
"account_number": "4743"
},
"Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen": {
"account_number": "4745"
},
"Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen 7% USt": {
"account_number": "4746"
},
"Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen 19% USt": {
"account_number": "4748"
}
"Gew. Skonti 7 % USt": {
"account_number": "4731"
},
"Gew. Skonti 19 % USt": {
"account_number": "4736"
},
"Gew. Skonti aus Lieferungen von Mobilfunkger./Schaltkr., f. die der Leistungsempf. die Ust. schuldet": {
"account_number": "4738"
},
"Gew. Skonti aus Leistungen, f. die der Leistungsempf. die Umsatzsteuer nach \u00a7 13b UStG schuldet": {
"account_number": "4741"
},
"Gew. Skonti aus Erl\u00f6sen aus im anderen EU-Land steuerpfl. Leistungen, f. die der Leistungsempf. die Ust. schuldet": {
"account_number": "4742"
},
"Gew. Skonti aus steuerfreien innergem. Lieferungen \u00a7 4 Nr. 1b UStG": {
"account_number": "4743"
},
"Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen": {
"account_number": "4745"
},
"Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen 7% USt": {
"account_number": "4746"
},
"Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen 19% USt": {
"account_number": "4748"
}
},
"Gew\u00e4hrte Boni (Gruppe)": {
"is_group": 1,
"Gew\u00e4hrte Boni 7 % USt": {
"account_number": "4750"
},
@ -2864,103 +2852,79 @@
"account_number": "6398"
}
},
"Versicherungen (Gruppe)": {
"is_group": 1,
"Versicherungen": {
"account_number": "6400"
},
"Versicherungen f. Geb\u00e4ude, die zum Betriebsverm\u00f6gen geh\u00f6ren": {
"account_number": "6405"
},
"Netto-Pr\u00e4mie f. R\u00fcckdeckung k\u00fcnftiger Versorgungsleistungen": {
"account_number": "6410"
},
"Beitr\u00e4ge": {
"account_number": "6420"
},
"Sonstige Abgaben": {
"account_number": "6430"
},
"Steuerlich abzugsf\u00e4hige Versp\u00e4tungszuschl\u00e4ge und Zwangsgelder": {
"account_number": "6436"
},
"Steuerlich nicht abzugsf\u00e4hige Versp\u00e4tungszuschl\u00e4ge und Zwangsgelder": {
"account_number": "6437"
},
"Ausgleichsabgabe i. S. d. Schwerbehindertengesetzes": {
"account_number": "6440"
},
"Reparaturen und Instandhaltung von Bauten": {
"account_number": "6450"
},
"Reparaturen und Instandhaltung von technischenAnlagen und Maschinen": {
"account_number": "6460"
},
"Reparaturen und Instandhaltung von anderen Anlagen und Betriebs- und Gesch\u00e4ftsausstattung": {
"account_number": "6470"
},
"Zuf\u00fchrung zu Aufwandsr\u00fcckstellungen": {
"account_number": "6475"
},
"Reparaturen und Instandhaltung von anderen Anlagen": {
"account_number": "6485"
},
"Sonstige Reparaturen und Instandhaltungen": {
"account_number": "6490"
},
"Wartungskosten f. Hard- und Software": {
"account_number": "6495"
},
"Mietleasing (bewegliche Wirtschaftsg\u00fcter)": {
"account_number": "6498"
}
"Versicherungen": {
"account_number": "6400"
},
"Versicherungen f. Geb\u00e4ude, die zum Betriebsverm\u00f6gen geh\u00f6ren": {
"account_number": "6405"
},
"Netto-Pr\u00e4mie f. R\u00fcckdeckung k\u00fcnftiger Versorgungsleistungen": {
"account_number": "6410"
},
"Beitr\u00e4ge": {
"account_number": "6420"
},
"Sonstige Abgaben": {
"account_number": "6430"
},
"Steuerlich abzugsf\u00e4hige Versp\u00e4tungszuschl\u00e4ge und Zwangsgelder": {
"account_number": "6436"
},
"Steuerlich nicht abzugsf\u00e4hige Versp\u00e4tungszuschl\u00e4ge und Zwangsgelder": {
"account_number": "6437"
},
"Ausgleichsabgabe i. S. d. Schwerbehindertengesetzes": {
"account_number": "6440"
},
"Reparaturen und Instandhaltung von Bauten": {
"account_number": "6450"
},
"Reparaturen und Instandhaltung von technischenAnlagen und Maschinen": {
"account_number": "6460"
},
"Reparaturen und Instandhaltung von anderen Anlagen und Betriebs- und Gesch\u00e4ftsausstattung": {
"account_number": "6470"
},
"Zuf\u00fchrung zu Aufwandsr\u00fcckstellungen": {
"account_number": "6475"
},
"Reparaturen und Instandhaltung von anderen Anlagen": {
"account_number": "6485"
},
"Sonstige Reparaturen und Instandhaltungen": {
"account_number": "6490"
},
"Wartungskosten f. Hard- und Software": {
"account_number": "6495"
},
"Mietleasing (bewegliche Wirtschaftsg\u00fcter)": {
"account_number": "6498"
},
"Fahrzeugkosten (Gruppe)": {
"is_group": 1,
"Fahrzeugkosten": {
"account_number": "6500"
},
"Kfz-Versicherungen (Gruppe)": {
"is_group": 1,
"Kfz-Versicherungen": {
"account_number": "6520"
}
"Kfz-Versicherungen": {
"account_number": "6520"
},
"Laufende Kfz-Betriebskosten (Gruppe)": {
"is_group": 1,
"Laufende Kfz-Betriebskosten": {
"account_number": "6530"
}
"Laufende Kfz-Betriebskosten": {
"account_number": "6530"
},
"Kfz-Reparaturen (Gruppe)": {
"is_group": 1,
"Kfz-Reparaturen": {
"account_number": "6540"
}
"Kfz-Reparaturen": {
"account_number": "6540"
},
"Garagenmiete (Gruppe)": {
"is_group": 1,
"Garagenmiete": {
"account_number": "6550"
}
"Garagenmiete": {
"account_number": "6550"
},
"Mietleasing Kfz (Gruppe)": {
"is_group": 1,
"Mietleasing Kfz": {
"account_number": "6560"
}
"Mietleasing Kfz": {
"account_number": "6560"
},
"Sonstige Kfz-Kosten (Gruppe)": {
"is_group": 1,
"Sonstige Kfz-Kosten": {
"account_number": "6570"
}
"Sonstige Kfz-Kosten": {
"account_number": "6570"
},
"Mautgeb\u00fchren (Gruppe)": {
"is_group": 1,
"Mautgeb\u00fchren": {
"account_number": "6580"
}
"Mautgeb\u00fchren": {
"account_number": "6580"
},
"Kfz-Kosten f. betrieblich genutzte zum Privatverm\u00f6gen geh\u00f6rende Kraftfahrzeuge": {
"account_number": "6590"
@ -3022,20 +2986,23 @@
"Nicht abzugsf\u00e4hige Betriebsausgaben aus Werbe- und Repr\u00e4sentationskosten": {
"account_number": "6645"
},
"Reisekosten Arbeitnehmer": {
"account_number": "6650"
},
"Reisekosten Arbeitnehmer \u00dcbernachtungsaufwand": {
"account_number": "6660"
},
"Reisekosten Arbeitnehmer Fahrtkosten": {
"account_number": "6663"
},
"Reisekosten Arbeitnehmer Verpflegungsmehraufwand": {
"account_number": "6664"
},
"Kilometergelderstattung Arbeitnehmer": {
"account_number": "6668"
"Reisekosten Arbeitnehmer (Gruppe)": {
"is_group": 1,
"Reisekosten Arbeitnehmer": {
"account_number": "6650"
},
"Reisekosten Arbeitnehmer \u00dcbernachtungsaufwand": {
"account_number": "6660"
},
"Reisekosten Arbeitnehmer Fahrtkosten": {
"account_number": "6663"
},
"Reisekosten Arbeitnehmer Verpflegungsmehraufwand": {
"account_number": "6664"
},
"Kilometergelderstattung Arbeitnehmer": {
"account_number": "6668"
}
},
"Reisekosten Unternehmer (Gruppe)": {
"is_group": 1,

View File

@ -48,12 +48,6 @@ frappe.ui.form.on('Accounting Dimension', {
frm.set_value('label', frm.doc.document_type);
frm.set_value('fieldname', frappe.model.scrub(frm.doc.document_type));
if (frm.is_new()){
let row = frappe.model.add_child(frm.doc, "Accounting Dimension Detail", "dimension_defaults");
row.reference_document = frm.doc.document_type;
frm.refresh_fields("dimension_defaults");
}
frappe.db.get_value('Accounting Dimension', {'document_type': frm.doc.document_type}, 'document_type', (r) => {
if (r && r.document_type) {
frm.set_df_property('document_type', 'description', "Document type is already set as dimension");

View File

@ -1,4 +1,5 @@
{
"actions": [],
"autoname": "field:label",
"creation": "2019-05-04 18:13:37.002352",
"doctype": "DocType",
@ -46,7 +47,8 @@
"options": "Accounting Dimension Detail"
}
],
"modified": "2019-07-17 16:49:31.134385",
"links": [],
"modified": "2020-03-22 20:34:39.805728",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting Dimension",
@ -63,9 +65,20 @@
"role": "System Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"share": 1,
"write": 1
}
],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "ASC",
"track_changes": 1

View File

@ -7,7 +7,20 @@ frappe.ui.form.on('Bank', {
},
refresh: function(frm) {
add_fields_to_mapping_table(frm);
}
frappe.dynamic_link = { doc: frm.doc, fieldname: 'name', doctype: 'Bank' };
frm.toggle_display(['address_html','contact_html'], !frm.doc.__islocal);
if (frm.doc.__islocal) {
frm.set_df_property('address_and_contact', 'hidden', 1);
frappe.contacts.clear_address_and_contact(frm);
}
else {
frm.set_df_property('address_and_contact', 'hidden', 0);
frappe.contacts.render_address_and_contact(frm);
}
},
});

View File

@ -1,224 +1,137 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:bank_name",
"beta": 0,
"creation": "2018-04-07 16:59:59.496668",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:bank_name",
"creation": "2018-04-07 16:59:59.496668",
"doctype": "DocType",
"document_type": "Setup",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"bank_details_section",
"bank_name",
"swift_number",
"column_break_1",
"branch_code",
"website",
"address_and_contact",
"address_html",
"column_break_13",
"contact_html",
"data_import_configuration_section",
"bank_transaction_mapping",
"section_break_4",
"plaid_access_token"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "bank_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Bank Name",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"fieldname": "bank_name",
"fieldtype": "Data",
"label": "Bank Name",
"reqd": 1,
"unique": 1
},
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
"fieldname": "data_import_configuration_section",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Data Import Configuration",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "bank_details_section",
"fieldtype": "Section Break",
"label": "Bank Details"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "bank_transaction_mapping",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Bank Transaction Mapping",
"length": 0,
"no_copy": 0,
"options": "Bank Transaction Mapping",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"allow_in_quick_entry": 1,
"fieldname": "swift_number",
"fieldtype": "Data",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "SWIFT number",
"unique": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_4",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "column_break_1",
"fieldtype": "Column Break",
"search_index": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "plaid_access_token",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Plaid Access Token",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"allow_in_quick_entry": 1,
"fieldname": "branch_code",
"fieldtype": "Data",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Branch Code",
"unique": 1
},
{
"fieldname": "address_and_contact",
"fieldtype": "Section Break",
"label": "Address and Contact",
"options": "fa fa-map-marker"
},
{
"fieldname": "address_html",
"fieldtype": "HTML",
"label": "Address HTML"
},
{
"fieldname": "website",
"fieldtype": "Data",
"label": "Website"
},
{
"fieldname": "column_break_13",
"fieldtype": "Column Break"
},
{
"fieldname": "contact_html",
"fieldtype": "HTML",
"label": "Contact HTML"
},
{
"collapsible": 1,
"fieldname": "data_import_configuration_section",
"fieldtype": "Section Break",
"label": "Data Import Configuration"
},
{
"fieldname": "bank_transaction_mapping",
"fieldtype": "Table",
"label": "Bank Transaction Mapping",
"options": "Bank Transaction Mapping"
},
{
"fieldname": "section_break_4",
"fieldtype": "Section Break"
},
{
"fieldname": "plaid_access_token",
"fieldtype": "Data",
"hidden": 1,
"label": "Plaid Access Token",
"no_copy": 1,
"read_only": 1
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-11-27 16:12:13.938776",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank",
"name_case": "",
"owner": "Administrator",
],
"links": [],
"modified": "2020-03-25 21:22:33.496264",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0,
"track_views": 0
],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -5,6 +5,12 @@
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe.contacts.address_and_contact import load_address_and_contact, delete_contact_and_address
class Bank(Document):
pass
def onload(self):
"""Load address and contacts in `__onload`"""
load_address_and_contact(self)
def on_trash(self):
delete_contact_and_address('Bank', self.name)

View File

@ -24,8 +24,6 @@
"iban",
"column_break_12",
"bank_account_no",
"branch_code",
"swift_number",
"address_and_contact",
"address_html",
"website",
@ -145,17 +143,6 @@
"label": "Bank Account No",
"length": 30
},
{
"fieldname": "branch_code",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Branch Code"
},
{
"fieldname": "swift_number",
"fieldtype": "Data",
"label": "SWIFT number"
},
{
"fieldname": "address_and_contact",
"fieldtype": "Section Break",
@ -213,7 +200,7 @@
}
],
"links": [],
"modified": "2020-01-29 20:42:26.458316",
"modified": "2020-01-30 20:42:26.458316",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Account",

View File

@ -4,8 +4,8 @@
cur_frm.add_fetch('bank_account','account','account');
cur_frm.add_fetch('bank_account','bank_account_no','bank_account_no');
cur_frm.add_fetch('bank_account','iban','iban');
cur_frm.add_fetch('bank_account','branch_code','branch_code');
cur_frm.add_fetch('bank_account','swift_number','swift_number');
cur_frm.add_fetch('bank','branch_code','branch_code');
cur_frm.add_fetch('bank','swift_number','swift_number');
frappe.ui.form.on('Bank Guarantee', {
setup: function(frm) {

View File

@ -114,13 +114,13 @@
"fieldname": "debit_in_account_currency",
"fieldtype": "Currency",
"label": "Debit Amount in Account Currency",
"options": "currency"
"options": "account_currency"
},
{
"fieldname": "credit_in_account_currency",
"fieldtype": "Currency",
"label": "Credit Amount in Account Currency",
"options": "currency"
"options": "account_currency"
},
{
"fieldname": "against",
@ -250,7 +250,7 @@
"icon": "fa fa-list",
"idx": 1,
"in_create": 1,
"modified": "2020-02-10 04:54:57.777905",
"modified": "2020-03-28 16:22:33.766994",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GL Entry",

View File

@ -33,7 +33,9 @@ frappe.ui.form.on('Payment Entry', {
frm.set_query("party_bank_account", function() {
return {
filters: {
"is_company_account":0
"is_company_account":0,
party_type: frm.doc.party_type,
party: frm.doc.party
}
}
});

View File

@ -319,13 +319,13 @@ def make_payment_request(**args):
"payment_request_type": args.get("payment_request_type"),
"currency": ref_doc.currency,
"grand_total": grand_total,
"email_to": args.recipient_id or "",
"email_to": args.recipient_id or ref_doc.owner,
"subject": _("Payment Request for {0}").format(args.dn),
"message": gateway_account.get("message") or get_dummy_message(ref_doc),
"reference_doctype": args.dt,
"reference_name": args.dn,
"party_type": args.get("party_type"),
"party": args.get("party"),
"party_type": args.get("party_type") or "Customer",
"party": args.get("party") or ref_doc.customer,
"bank_account": bank_account
})

View File

@ -761,7 +761,7 @@
"depends_on": "is_fixed_asset",
"fetch_from": "item_code.asset_category",
"fieldname": "asset_category",
"fieldtype": "Data",
"fieldtype": "Link",
"label": "Asset Category",
"options": "Asset Category",
"read_only": 1
@ -777,7 +777,7 @@
"idx": 1,
"istable": 1,
"links": [],
"modified": "2020-03-11 14:20:17.297284",
"modified": "2020-04-01 14:20:17.297284",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",

View File

@ -437,13 +437,17 @@ class SalesInvoice(SellingController):
if (not for_validate) or (for_validate and not self.get(fieldname)):
self.set(fieldname, pos.get(fieldname))
customer_price_list = frappe.get_value("Customer", self.customer, 'default_price_list')
if pos.get("company_address"):
self.company_address = pos.get("company_address")
if not customer_price_list:
self.set('selling_price_list', pos.get('selling_price_list'))
customer_price_list, customer_group = frappe.get_value("Customer", self.customer, ['default_price_list', 'customer_group'])
customer_group_price_list = frappe.get_value("Customer Group", customer_group, 'default_price_list')
selling_price_list = customer_price_list or customer_group_price_list or pos.get('selling_price_list')
if selling_price_list:
self.set('selling_price_list', selling_price_list)
if not for_validate:
self.update_stock = cint(pos.get("update_stock"))

View File

@ -11,7 +11,7 @@ from frappe.utils import (add_days, getdate, formatdate, date_diff,
add_years, get_timestamp, nowdate, flt, cstr, add_months, get_last_day)
from frappe.contacts.doctype.address.address import (get_address_display,
get_default_address, get_company_address)
from frappe.contacts.doctype.contact.contact import get_contact_details, get_default_contact
from frappe.contacts.doctype.contact.contact import get_contact_details
from erpnext.exceptions import PartyFrozen, PartyDisabled, InvalidAccountCurrency
from erpnext.accounts.utils import get_fiscal_year
from erpnext import get_company_currency
@ -281,8 +281,8 @@ def validate_party_gle_currency(party_type, party, company, party_account_curren
existing_gle_currency = get_party_gle_currency(party_type, party, company)
if existing_gle_currency and party_account_currency != existing_gle_currency:
frappe.throw(_("Accounting Entry for {0}: {1} can only be made in currency: {2}")
.format(party_type, party, existing_gle_currency), InvalidAccountCurrency)
frappe.throw(_("{0} {1} has accounting entries in currency {2} for company {3}. Please select a receivable or payable account with currency {2}.")
.format(frappe.bold(party_type), frappe.bold(party), frappe.bold(existing_gle_currency), frappe.bold(company)), InvalidAccountCurrency)
def validate_party_accounts(doc):
companies = []
@ -295,15 +295,13 @@ def validate_party_accounts(doc):
companies.append(account.company)
party_account_currency = frappe.db.get_value("Account", account.account, "account_currency", cache=True)
existing_gle_currency = get_party_gle_currency(doc.doctype, doc.name, account.company)
if frappe.db.get_default("Company"):
company_default_currency = frappe.get_cached_value('Company',
frappe.db.get_default("Company"), "default_currency")
else:
company_default_currency = frappe.db.get_value('Company', account.company, "default_currency")
if existing_gle_currency and party_account_currency != existing_gle_currency:
frappe.throw(_("Accounting entries have already been made in currency {0} for company {1}. Please select a receivable or payable account with currency {0}.").format(existing_gle_currency, account.company))
validate_party_gle_currency(doc.doctype, doc.name, account.company, party_account_currency)
if doc.get("default_currency") and party_account_currency and company_default_currency:
if doc.default_currency != party_account_currency and doc.default_currency != company_default_currency:
@ -615,3 +613,26 @@ def get_partywise_advanced_payment_amount(party_type, posting_date = None):
if data:
return frappe._dict(data)
def get_default_contact(doctype, name):
"""
Returns default contact for the given doctype and name.
Can be ordered by `contact_type` to either is_primary_contact or is_billing_contact.
"""
out = frappe.db.sql("""
SELECT dl.parent, c.is_primary_contact, c.is_billing_contact
FROM `tabDynamic Link` dl
INNER JOIN tabContact c ON c.name = dl.parent
WHERE
dl.link_doctype=%s AND
dl.link_name=%s AND
dl.parenttype = "Contact"
ORDER BY is_primary_contact DESC, is_billing_contact DESC
""", (doctype, name))
if out:
try:
return out[0][0]
except:
return None
else:
return None

View File

@ -218,15 +218,15 @@
<td></td>
<td style="text-align: right"><b>{%= __("Total") %}</b></td>
<td style="text-align: right">
{%= format_currency(data[i]["invoiced"], data[i]["currency"] ) %}</td>
{%= format_currency(data[i]["invoiced"], data[0]["currency"] ) %}</td>
{% if(!filters.show_future_payments) { %}
<td style="text-align: right">
{%= format_currency(data[i]["paid"], data[i]["currency"]) %}</td>
<td style="text-align: right">{%= format_currency(data[i]["credit_note"], data[i]["currency"]) %} </td>
{%= format_currency(data[i]["paid"], data[0]["currency"]) %}</td>
<td style="text-align: right">{%= format_currency(data[i]["credit_note"], data[0]["currency"]) %} </td>
{% } %}
<td style="text-align: right">
{%= format_currency(data[i]["outstanding"], data[i]["currency"]) %}</td>
{%= format_currency(data[i]["outstanding"], data[0]["currency"]) %}</td>
{% if(filters.show_future_payments) { %}
{% if(report.report_name === "Accounts Receivable") { %}
@ -234,8 +234,8 @@
{%= data[i]["po_no"] %}</td>
{% } %}
<td style="text-align: right">{%= data[i]["future_ref"] %}</td>
<td style="text-align: right">{%= format_currency(data[i]["future_amount"], data[i]["currency"]) %}</td>
<td style="text-align: right">{%= format_currency(data[i]["remaining_balance"], data[i]["currency"]) %}</td>
<td style="text-align: right">{%= format_currency(data[i]["future_amount"], data[0]["currency"]) %}</td>
<td style="text-align: right">{%= format_currency(data[i]["remaining_balance"], data[0]["currency"]) %}</td>
{% } %}
{% } %}
{% } else { %}
@ -256,10 +256,10 @@
{% } else { %}
<td><b>{%= __("Total") %}</b></td>
{% } %}
<td style="text-align: right">{%= format_currency(data[i]["invoiced"], data[i]["currency"]) %}</td>
<td style="text-align: right">{%= format_currency(data[i]["paid"], data[i]["currency"]) %}</td>
<td style="text-align: right">{%= format_currency(data[i]["credit_note"], data[i]["currency"]) %}</td>
<td style="text-align: right">{%= format_currency(data[i]["outstanding"], data[i]["currency"]) %}</td>
<td style="text-align: right">{%= format_currency(data[i]["invoiced"], data[0]["currency"]) %}</td>
<td style="text-align: right">{%= format_currency(data[i]["paid"], data[0]["currency"]) %}</td>
<td style="text-align: right">{%= format_currency(data[i]["credit_note"], data[0]["currency"]) %}</td>
<td style="text-align: right">{%= format_currency(data[i]["outstanding"], data[0]["currency"]) %}</td>
{% } %}
{% } %}
</tr>

View File

@ -131,7 +131,7 @@ def get_gl_entries(filters):
gl_entries = frappe.db.sql(
"""
select
posting_date, account, party_type, party,
name as gl_entry, posting_date, account, party_type, party,
voucher_type, voucher_no, cost_center, project,
against_voucher_type, against_voucher, account_currency,
remarks, against, is_opening {select_fields}
@ -362,6 +362,12 @@ def get_columns(filters):
currency = get_company_currency(company)
columns = [
{
"fieldname": "gl_entry",
"fieldtype": "Link",
"options": "GL Entry",
"hidden": 1
},
{
"label": _("Posting Date"),
"fieldname": "posting_date",

View File

@ -499,7 +499,8 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
reference_doctype: me.frm.doctype,
reference_name: me.frm.docname,
content: __('Reason for hold: ')+data.reason_for_hold,
comment_email: frappe.session.user
comment_email: frappe.session.user,
comment_by: frappe.session.user_fullname
},
callback: function(r) {
if(!r.exc) {

View File

@ -34,4 +34,4 @@ def get_data():
'items': ['Pricing Rule']
}
]
}
}

View File

@ -4,15 +4,17 @@
// attach required files
{% include 'erpnext/public/js/controllers/buying.js' %};
frappe.ui.form.on('Suppier Quotation', {
setup: function(frm) {
frm.custom_make_buttons = {
'Purchase Order': 'Purchase Order'
}
}
});
erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.extend({
setup: function() {
this.frm.custom_make_buttons = {
'Purchase Order': 'Purchase Order',
'Quotation': 'Quotation',
'Subscription': 'Subscription'
}
this._super();
},
refresh: function() {
var me = this;
this._super();

View File

@ -1,22 +0,0 @@
{
"cards": [],
"charts": [],
"creation": "2020-01-28 11:49:55.003637",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Desk Page",
"extends_another_page": 0,
"icon": "",
"idx": 0,
"is_standard": 1,
"label": "Communication",
"modified": "2020-03-12 16:30:40.534226",
"modified_by": "Administrator",
"module": "Communication",
"name": "Communication",
"owner": "Administrator",
"pin_to_bottom": 0,
"pin_to_top": 0,
"shortcuts": []
}

View File

@ -19,6 +19,7 @@ from erpnext.accounts.doctype.pricing_rule.utils import (apply_pricing_rule_on_t
from erpnext.exceptions import InvalidCurrency
from six import text_type
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
from erpnext.stock.get_item_details import get_item_warehouse
force_item_fields = ("item_group", "brand", "stock_uom", "is_fixed_asset", "item_tax_rate", "pricing_rules")
@ -1126,16 +1127,16 @@ def set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname,
"""
Returns a Sales Order Item child item containing the default values
"""
p_doctype = frappe.get_doc(parent_doctype, parent_doctype_name)
child_item = frappe.new_doc('Sales Order Item', p_doctype, child_docname)
p_doc = frappe.get_doc(parent_doctype, parent_doctype_name)
child_item = frappe.new_doc('Sales Order Item', p_doc, child_docname)
item = frappe.get_doc("Item", item_code)
child_item.item_code = item.item_code
child_item.item_name = item.item_name
child_item.description = item.description
child_item.reqd_by_date = p_doctype.delivery_date
child_item.reqd_by_date = p_doc.delivery_date
child_item.uom = item.stock_uom
child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0
child_item.warehouse = p_doctype.set_warehouse or p_doctype.items[0].warehouse
child_item.warehouse = get_item_warehouse(item, p_doc, overwrite_warehouse=True)
return child_item
@ -1143,13 +1144,13 @@ def set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docna
"""
Returns a Purchase Order Item child item containing the default values
"""
p_doctype = frappe.get_doc(parent_doctype, parent_doctype_name)
child_item = frappe.new_doc('Purchase Order Item', p_doctype, child_docname)
p_doc = frappe.get_doc(parent_doctype, parent_doctype_name)
child_item = frappe.new_doc('Purchase Order Item', p_doc, child_docname)
item = frappe.get_doc("Item", item_code)
child_item.item_code = item.item_code
child_item.item_name = item.item_name
child_item.description = item.description
child_item.schedule_date = p_doctype.schedule_date
child_item.schedule_date = p_doc.schedule_date
child_item.uom = item.stock_uom
child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0
child_item.base_rate = 1 # Initiallize value will update in parent validation

View File

@ -672,19 +672,32 @@ class BuyingController(StockController):
# If asset has to be auto created
# Check for asset naming series
if item_data.get('asset_naming_series'):
created_assets = []
for qty in range(cint(d.qty)):
self.make_asset(d)
is_plural = 's' if cint(d.qty) != 1 else ''
messages.append(_('{0} Asset{2} Created for <b>{1}</b>').format(cint(d.qty), d.item_code, is_plural))
asset = self.make_asset(d)
created_assets.append(asset)
if len(created_assets) > 5:
# dont show asset form links if more than 5 assets are created
messages.append(_('{} Asset{} created for {}').format(len(created_assets), is_plural, frappe.bold(d.item_code)))
else:
assets_link = list(map(lambda d: frappe.utils.get_link_to_form('Asset', d), created_assets))
assets_link = frappe.bold(','.join(assets_link))
is_plural = 's' if len(created_assets) != 1 else ''
messages.append(
_('Asset{} {assets_link} created for {}').format(is_plural, frappe.bold(d.item_code), assets_link=assets_link)
)
else:
frappe.throw(_("Row {1}: Asset Naming Series is mandatory for the auto creation for item {0}")
.format(d.item_code, d.idx))
frappe.throw(_("Row {}: Asset Naming Series is mandatory for the auto creation for item {}")
.format(d.idx, frappe.bold(d.item_code)))
else:
messages.append(_("Assets not created for <b>{0}</b>. You will have to create asset manually.")
.format(d.item_code))
messages.append(_("Assets not created for {0}. You will have to create asset manually.")
.format(frappe.bold(d.item_code)))
for message in messages:
frappe.msgprint(message, title="Success")
frappe.msgprint(message, title="Success", indicator="green")
def make_asset(self, row):
if not row.asset_location:
@ -716,6 +729,8 @@ class BuyingController(StockController):
asset.set_missing_values()
asset.insert()
return asset.name
def update_fixed_asset(self, field, delete_asset = False):
for d in self.get("items"):
if d.is_fixed_asset:
@ -745,7 +760,7 @@ class BuyingController(StockController):
asset.supplier = None
if asset.docstatus == 1 and delete_asset:
frappe.throw(_('Cannot cancel this document as it is linked with submitted asset {0}.\
Please cancel the it to continue.').format(asset.name))
Please cancel the it to continue.').format(frappe.utils.get_link_to_form('Asset', asset.name)))
asset.flags.ignore_validate_update_after_submit = True
asset.flags.ignore_mandatory = True
@ -1026,4 +1041,4 @@ def get_batches_with_qty(item_code, fg_item, required_qty, transferred_batch_qty
available_batches.append({'batch': batch, 'qty': available_qty})
required_qty -= available_qty
return available_batches
return available_batches

View File

@ -3,6 +3,7 @@
from __future__ import unicode_literals
import frappe
import erpnext
from frappe.desk.reportview import get_match_cond, get_filters_cond
from frappe.utils import nowdate, getdate
from collections import defaultdict
@ -129,23 +130,26 @@ def supplier_query(doctype, txt, searchfield, start, page_len, filters):
})
def tax_account_query(doctype, txt, searchfield, start, page_len, filters):
company_currency = erpnext.get_company_currency(filters.get('company'))
tax_accounts = frappe.db.sql("""select name, parent_account from tabAccount
where tabAccount.docstatus!=2
and account_type in (%s)
and is_group = 0
and company = %s
and account_currency = %s
and `%s` LIKE %s
order by idx desc, name
limit %s, %s""" %
(", ".join(['%s']*len(filters.get("account_type"))), "%s", searchfield, "%s", "%s", "%s"),
tuple(filters.get("account_type") + [filters.get("company"), "%%%s%%" % txt,
(", ".join(['%s']*len(filters.get("account_type"))), "%s", "%s", searchfield, "%s", "%s", "%s"),
tuple(filters.get("account_type") + [filters.get("company"), company_currency, "%%%s%%" % txt,
start, page_len]))
if not tax_accounts:
tax_accounts = frappe.db.sql("""select name, parent_account from tabAccount
where tabAccount.docstatus!=2 and is_group = 0
and company = %s and `%s` LIKE %s limit %s, %s"""
% ("%s", searchfield, "%s", "%s", "%s"),
(filters.get("company"), "%%%s%%" % txt, start, page_len))
and company = %s and account_currency = %s and `%s` LIKE %s limit %s, %s""" #nosec
% ("%s", "%s", searchfield, "%s", "%s", "%s"),
(filters.get("company"), company_currency, "%%%s%%" % txt, start, page_len))
return tax_accounts

View File

@ -171,7 +171,6 @@
"options": "Customer"
},
{
"depends_on": "eval: doc.source==\"Campaign\"",
"fieldname": "campaign_name",
"fieldtype": "Link",
"label": "Campaign Name",
@ -512,4 +511,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "title"
}
}

View File

@ -135,10 +135,17 @@ class Lead(SellingController):
# do not create an address if no fields are available,
# skipping country since the system auto-sets it from system defaults
if not any([self.get(field) for field in address_fields if field != "country"]):
address = frappe.new_doc("Address")
mandatory_fields = [ df.fieldname for df in address.meta.fields if df.reqd ]
if not all([self.get(field) for field in mandatory_fields]):
frappe.msgprint(_('Missing mandatory fields in address. \
{0} to create address' ).format("<a href='desk#Form/Address/New Address 1' \
> Click here </a>"),
alert=True, indicator='yellow')
return
address = frappe.new_doc("Address")
address.update({addr_field: self.get(addr_field) for addr_field in address_fields})
address.update({info_field: self.get(info_field) for info_field in info_fields})
address.insert()

View File

@ -1,4 +1,5 @@
{
"actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "naming_series:",
@ -214,7 +215,8 @@
{
"fieldname": "opportunity_amount",
"fieldtype": "Currency",
"label": "Opportunity Amount"
"label": "Opportunity Amount",
"options": "currency"
},
{
"default": "0",
@ -418,7 +420,8 @@
],
"icon": "fa fa-info-sign",
"idx": 195,
"modified": "2019-09-30 12:58:37.385400",
"links": [],
"modified": "2020-03-20 12:28:45.228994",
"modified_by": "Administrator",
"module": "CRM",
"name": "Opportunity",

View File

@ -6,46 +6,28 @@ from __future__ import unicode_literals
import frappe
from frappe.utils.make_random import get_random
from erpnext.assets.doctype.asset.asset import make_purchase_invoice, make_sales_invoice
from erpnext.assets.doctype.asset.asset import make_sales_invoice
from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries, scrap_asset
def work():
frappe.set_user(frappe.db.get_global('demo_accounts_user'))
asset_list = make_asset_purchase_entry()
if not asset_list:
# fixed_asset.work() already run
return
# Enable booking asset depreciation entry automatically
frappe.db.set_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically", 1)
# post depreciation entries as on today
post_depreciation_entries()
# scrap a random asset
frappe.db.set_value("Company", "Wind Power LLC", "disposal_account", "Gain/Loss on Asset Disposal - WPL")
asset = get_random_asset()
scrap_asset(asset.name)
# Sell a random asset
sell_an_asset()
def make_asset_purchase_entry():
asset_list = frappe.get_all("Asset", filters={"purchase_invoice": ["in", ("", None)]},
fields=["name", "item_code", "gross_purchase_amount", "company", "purchase_date"])
# make purchase invoice
for asset in asset_list:
pi = make_purchase_invoice(asset.name, asset.item_code, asset.gross_purchase_amount,
asset.company, asset.purchase_date)
pi.supplier = get_random("Supplier")
pi.save()
pi.submit()
return asset_list
# Sell a random asset
sell_an_asset()
def sell_an_asset():
asset = get_random_asset()
@ -55,8 +37,9 @@ def sell_an_asset():
if asset.value_after_depreciation else asset.gross_purchase_amount * 0.9
si.save()
si.submit()
def get_random_asset():
return frappe.db.sql(""" select name, item_code, value_after_depreciation, gross_purchase_amount
from `tabAsset`
from `tabAsset`
where docstatus=1 and status not in ("Scrapped", "Sold") order by rand() limit 1""", as_dict=1)[0]

View File

@ -74,7 +74,7 @@
}
],
"image_field": "hero_image",
"modified": "2019-06-12 12:34:23.748157",
"modified": "2020-03-29 12:50:27.677589",
"modified_by": "Administrator",
"module": "Education",
"name": "Course",
@ -103,6 +103,30 @@
"role": "Instructor",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Administrator",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Education Manager",
"share": 1,
"write": 1
}
],
"restrict_to_domain": "Education",

View File

@ -0,0 +1,60 @@
{
"custom_fields": [
{
"_assign": null,
"_comments": null,
"_liked_by": null,
"_user_tags": null,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"collapsible_depends_on": null,
"columns": 0,
"creation": "2019-12-02 11:00:03.432994",
"default": null,
"depends_on": null,
"description": null,
"docstatus": 0,
"dt": "Contact",
"fetch_from": null,
"fetch_if_empty": 0,
"fieldname": "is_billing_contact",
"fieldtype": "Check",
"hidden": 0,
"idx": 27,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"insert_after": "is_primary_contact",
"label": "Is Billing Contact",
"length": 0,
"modified": "2019-12-02 11:00:03.432994",
"modified_by": "Administrator",
"name": "Contact-is_billing_contact",
"no_copy": 0,
"options": null,
"owner": "Administrator",
"parent": null,
"parentfield": null,
"parenttype": null,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": null,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"translatable": 0,
"unique": 0,
"width": null
}
],
"custom_perms": [],
"doctype": "Contact",
"property_setters": [],
"sync_on_migrate": 1
}

View File

@ -273,11 +273,11 @@ class TestLoan(unittest.TestCase):
penalty_amount = (accrued_interest_amount * 4 * 25) / (100 * days_in_year(get_datetime(first_date).year))
lia = frappe.get_all("Loan Interest Accrual", fields=["is_paid"],
filters={"loan": loan.name}, order_by="posting_date")
lia1 = frappe.get_value("Loan Interest Accrual", {"loan": loan.name, "is_paid": 1}, 'name')
lia2 = frappe.get_value("Loan Interest Accrual", {"loan": loan.name, "is_paid": 0}, 'name')
self.assertTrue(lia[0].get('is_paid'))
self.assertFalse(lia[1].get('is_paid'))
self.assertTrue(lia1)
self.assertTrue(lia2)
def test_security_shortfall(self):
pledges = []

View File

@ -14,27 +14,37 @@ frappe.ui.form.on('Blanket Order', {
refresh: function(frm) {
erpnext.hide_company();
if (frm.doc.customer && frm.doc.docstatus === 1) {
frm.add_custom_button(__('View Orders'), function() {
frappe.set_route('List', 'Sales Order', {blanket_order: frm.doc.name});
});
frm.add_custom_button(__("Create Sales Order"), function(){
frm.add_custom_button(__("Sales Order"), function() {
frappe.model.open_mapped_doc({
method: "erpnext.manufacturing.doctype.blanket_order.blanket_order.make_sales_order",
frm: frm
method: "erpnext.manufacturing.doctype.blanket_order.blanket_order.make_order",
frm: frm,
args: {
doctype: 'Sales Order'
}
});
}).addClass("btn-primary");
}, __('Create'));
frm.add_custom_button(__("Quotation"), function() {
frappe.model.open_mapped_doc({
method: "erpnext.manufacturing.doctype.blanket_order.blanket_order.make_order",
frm: frm,
args: {
doctype: 'Quotation'
}
});
}, __('Create'));
}
if (frm.doc.supplier && frm.doc.docstatus === 1) {
frm.add_custom_button(__('View Orders'), function() {
frappe.set_route('List', 'Purchase Order', {blanket_order: frm.doc.name});
});
frm.add_custom_button(__("Create Purchase Order"), function(){
frm.add_custom_button(__("Purchase Order"), function(){
frappe.model.open_mapped_doc({
method: "erpnext.manufacturing.doctype.blanket_order.blanket_order.make_purchase_order",
frm: frm
method: "erpnext.manufacturing.doctype.blanket_order.blanket_order.make_order",
frm: frm,
args: {
doctype: 'Purchase Order'
}
});
}).addClass("btn-primary");
}, __('Create'));
}
},

View File

@ -14,10 +14,18 @@ from erpnext.stock.doctype.item.item import get_item_defaults
class BlanketOrder(Document):
def validate(self):
self.validate_dates()
self.validate_duplicate_items()
def validate_dates(self):
if getdate(self.from_date) > getdate(self.to_date):
frappe.throw(_("From date cannot be greater than To date"))
frappe.throw(_("From date cannot be greater than To date"))
def validate_duplicate_items(self):
item_list = []
for item in self.items:
if item.item_code in item_list:
frappe.throw(_("Note: Item {0} added multiple times").format(frappe.bold(item.item_code)))
item_list.append(item.item_code)
def update_ordered_qty(self):
ref_doctype = "Sales Order" if self.blanket_order_type == "Selling" else "Purchase Order"
@ -35,7 +43,14 @@ class BlanketOrder(Document):
d.db_set("ordered_qty", item_ordered_qty.get(d.item_code, 0))
@frappe.whitelist()
def make_sales_order(source_name):
def make_order(source_name):
doctype = frappe.flags.args.doctype
def update_doc(source_doc, target_doc, source_parent):
if doctype == 'Quotation':
target_doc.quotation_to = 'Customer'
target_doc.party_name = source_doc.customer
def update_item(source, target, source_parent):
target_qty = source.get("qty") - source.get("ordered_qty")
target.qty = target_qty if not flt(target_qty) < 0 else 0
@ -49,39 +64,11 @@ def make_sales_order(source_name):
target_doc = get_mapped_doc("Blanket Order", source_name, {
"Blanket Order": {
"doctype": "Sales Order"
"doctype": doctype,
"postprocess": update_doc
},
"Blanket Order Item": {
"doctype": "Sales Order Item",
"field_map": {
"rate": "blanket_order_rate",
"parent": "blanket_order"
},
"postprocess": update_item
}
})
return target_doc
@frappe.whitelist()
def make_purchase_order(source_name):
def update_item(source, target, source_parent):
target_qty = source.get("qty") - source.get("ordered_qty")
target.qty = target_qty if not flt(target_qty) < 0 else 0
item = get_item_defaults(target.item_code, source_parent.company)
if item:
target.item_name = item.get("item_name")
target.description = item.get("description")
target.uom = item.get("stock_uom")
target.warehouse = item.get("default_warehouse")
target.against_blanket_order = 1
target.blanket_order = source_name
target_doc = get_mapped_doc("Blanket Order", source_name, {
"Blanket Order": {
"doctype": "Purchase Order"
},
"Blanket Order Item": {
"doctype": "Purchase Order Item",
"doctype": doctype + " Item",
"field_map": {
"rate": "blanket_order_rate",
"parent": "blanket_order"

View File

@ -6,7 +6,7 @@ def get_data():
'fieldname': 'blanket_order',
'transactions': [
{
'items': ['Purchase Order', 'Sales Order']
'items': ['Purchase Order', 'Sales Order', 'Quotation']
}
]
}

View File

@ -7,13 +7,17 @@ import frappe
import unittest
from frappe.utils import add_months, today
from erpnext import get_company_currency
from .blanket_order import make_sales_order, make_purchase_order
from .blanket_order import make_order
class TestBlanketOrder(unittest.TestCase):
def setUp(self):
frappe.flags.args = frappe._dict()
def test_sales_order_creation(self):
bo = make_blanket_order(blanket_order_type="Selling")
so = make_sales_order(bo.name)
frappe.flags.args.doctype = 'Sales Order'
so = make_order(bo.name)
so.currency = get_company_currency(so.company)
so.delivery_date = today()
so.items[0].qty = 10
@ -29,7 +33,8 @@ class TestBlanketOrder(unittest.TestCase):
self.assertEqual(so.items[0].qty, bo.items[0].ordered_qty)
# test the quantity
so1 = make_sales_order(bo.name)
frappe.flags.args.doctype = 'Sales Order'
so1 = make_order(bo.name)
so1.currency = get_company_currency(so1.company)
self.assertEqual(so1.items[0].qty, (bo.items[0].qty-bo.items[0].ordered_qty))
@ -37,7 +42,8 @@ class TestBlanketOrder(unittest.TestCase):
def test_purchase_order_creation(self):
bo = make_blanket_order(blanket_order_type="Purchasing")
po = make_purchase_order(bo.name)
frappe.flags.args.doctype = 'Purchase Order'
po = make_order(bo.name)
po.currency = get_company_currency(po.company)
po.schedule_date = today()
po.items[0].qty = 10
@ -53,7 +59,8 @@ class TestBlanketOrder(unittest.TestCase):
self.assertEqual(po.items[0].qty, bo.items[0].ordered_qty)
# test the quantity
po1 = make_sales_order(bo.name)
frappe.flags.args.doctype = 'Purchase Order'
po1 = make_order(bo.name)
po1.currency = get_company_currency(po1.company)
self.assertEqual(po1.items[0].qty, (bo.items[0].qty-bo.items[0].ordered_qty))
@ -78,7 +85,7 @@ def make_blanket_order(**args):
"qty": args.quantity or 1000,
"rate": args.rate or 100
})
bo.insert()
bo.submit()
return bo

View File

@ -43,8 +43,7 @@ frappe.ui.form.on("BOM", {
frm.set_query("item_code", "items", function() {
return {
query: "erpnext.controllers.queries.item_query",
filters: [["Item", "name", "!=", cur_frm.doc.item]]
query: "erpnext.controllers.queries.item_query"
};
});
@ -135,6 +134,7 @@ frappe.ui.form.on("BOM", {
frappe.call({
method: "erpnext.manufacturing.doctype.work_order.work_order.make_work_order",
args: {
bom_no: frm.doc.name,
item: frm.doc.item,
qty: data.qty || 0.0,
project: frm.doc.project

View File

@ -114,10 +114,6 @@ class BOM(WebsiteGenerator):
child = self.append('operations', d)
child.hour_rate = flt(d.hour_rate / self.conversion_rate, 2)
def validate_rm_item(self, item):
if (item[0]['name'] in [it.item_code for it in self.items]) and item[0]['name'] == self.item:
frappe.throw(_("BOM #{0}: Raw material cannot be same as main Item").format(self.name))
def set_bom_material_details(self):
for item in self.get("items"):
self.validate_bom_currecny(item)
@ -147,7 +143,6 @@ class BOM(WebsiteGenerator):
args = json.loads(args)
item = self.get_item_det(args['item_code'])
self.validate_rm_item(item)
args['bom_no'] = args['bom_no'] or item and cstr(item[0]['default_bom']) or ''
args['transfer_for_manufacture'] = (cstr(args.get('include_item_in_manufacturing', '')) or

View File

@ -20,7 +20,7 @@ frappe.ui.form.on('Job Card', {
}
}
if (frm.doc.docstatus == 0 && frm.doc.for_quantity > frm.doc.total_completed_qty
if (frm.doc.docstatus == 0 && (frm.doc.for_quantity > frm.doc.total_completed_qty || !frm.doc.for_quantity)
&& (!frm.doc.items.length || frm.doc.for_quantity == frm.doc.transferred_qty)) {
frm.trigger("prepare_timer_buttons");
}
@ -59,10 +59,14 @@ frappe.ui.form.on('Job Card', {
let completed_time = frappe.datetime.now_datetime();
frm.trigger("hide_timer");
frappe.prompt({fieldtype: 'Float', label: __('Completed Quantity'),
fieldname: 'qty', reqd: 1, default: frm.doc.for_quantity}, data => {
frm.events.complete_job(frm, completed_time, data.qty);
}, __("Enter Value"), __("Complete"));
if (frm.doc.for_quantity) {
frappe.prompt({fieldtype: 'Float', label: __('Completed Quantity'),
fieldname: 'qty', reqd: 1, default: frm.doc.for_quantity}, data => {
frm.events.complete_job(frm, completed_time, data.qty);
}, __("Enter Value"), __("Complete"));
} else {
frm.events.complete_job(frm, completed_time, 0);
}
}).addClass("btn-primary");
}
},

View File

@ -99,8 +99,7 @@
"fieldname": "for_quantity",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Qty To Manufacture",
"reqd": 1
"label": "Qty To Manufacture"
},
{
"fieldname": "wip_warehouse",
@ -122,6 +121,7 @@
"options": "Employee"
},
{
"allow_bulk_edit": 1,
"fieldname": "time_logs",
"fieldtype": "Table",
"label": "Time Logs",
@ -290,7 +290,7 @@
}
],
"is_submittable": 1,
"modified": "2019-12-03 13:08:57.926201",
"modified": "2020-03-27 13:36:35.417502",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Job Card",

View File

@ -191,12 +191,9 @@ class JobCard(Document):
if not self.time_logs:
frappe.throw(_("Time logs are required for job card {0}").format(self.name))
if self.total_completed_qty <= 0.0:
frappe.throw(_("Total completed qty must be greater than zero"))
if self.total_completed_qty != self.for_quantity:
frappe.throw(_("The total completed qty({0}) must be equal to qty to manufacture({1})")
.format(frappe.bold(self.total_completed_qty),frappe.bold(self.for_quantity)))
if self.for_quantity and self.total_completed_qty != self.for_quantity:
frappe.throw(_("The total completed qty({0}) must be equal to qty to manufacture({1})"
.format(frappe.bold(self.total_completed_qty),frappe.bold(self.for_quantity))))
def update_work_order(self):
if not self.work_order:
@ -205,27 +202,34 @@ class JobCard(Document):
for_quantity, time_in_mins = 0, 0
from_time_list, to_time_list = [], []
for d in frappe.get_all('Job Card',
filters = {'docstatus': 1, 'operation_id': self.operation_id}):
doc = frappe.get_doc('Job Card', d.name)
for_quantity += doc.total_completed_qty
time_in_mins += doc.total_time_in_mins
for time_log in doc.time_logs:
if time_log.from_time:
from_time_list.append(time_log.from_time)
if time_log.to_time:
to_time_list.append(time_log.to_time)
data = frappe.get_all('Job Card',
fields = ["sum(total_time_in_mins) as time_in_mins", "sum(total_completed_qty) as completed_qty"],
filters = {"docstatus": 1, "work_order": self.work_order,
"workstation": self.workstation, "operation": self.operation})
if data and len(data) > 0:
for_quantity = data[0].completed_qty
time_in_mins = data[0].time_in_mins
if for_quantity:
time_data = frappe.db.sql("""
SELECT
min(from_time) as start_time, max(to_time) as end_time
FROM `tabJob Card` jc, `tabJob Card Time Log` jctl
WHERE
jctl.parent = jc.name and jc.work_order = %s
and jc.workstation = %s and jc.operation = %s and jc.docstatus = 1
""", (self.work_order, self.workstation, self.operation), as_dict=1)
wo = frappe.get_doc('Work Order', self.work_order)
for data in wo.operations:
if data.name == self.operation_id:
if data.workstation == self.workstation and data.operation == self.operation:
data.completed_qty = for_quantity
data.actual_operation_time = time_in_mins
data.actual_start_time = min(from_time_list) if from_time_list else None
data.actual_end_time = max(to_time_list) if to_time_list else None
data.actual_start_time = time_data[0].start_time if time_data else None
data.actual_end_time = time_data[0].end_time if time_data else None
wo.flags.ignore_validate_update_after_submit = True
wo.update_operation_status()

View File

@ -144,7 +144,7 @@ class ProductionPlan(Document):
item_condition = " and mr_item.item_code ={0}".format(frappe.db.escape(self.item_code))
items = frappe.db.sql("""select distinct parent, name, item_code, warehouse, description,
(qty - ordered_qty) as pending_qty
(qty - ordered_qty) * conversion_factor as pending_qty
from `tabMaterial Request Item` mr_item
where parent in (%s) and docstatus = 1 and qty > ordered_qty
and exists (select name from `tabBOM` bom where bom.item=mr_item.item_code

View File

@ -314,7 +314,7 @@ class WorkOrder(Document):
stock_entry = frappe.db.sql("""select name from `tabStock Entry`
where work_order = %s and docstatus = 1""", self.name)
if stock_entry:
frappe.throw(_("Cannot cancel because submitted Stock Entry {0} exists").format(stock_entry[0][0]))
frappe.throw(_("Cannot cancel because submitted Stock Entry {0} exists").format(frappe.utils.get_link_to_form('Stock Entry', stock_entry[0][0])))
def update_planned_qty(self):
update_bin_qty(self.production_item, self.fg_warehouse, {
@ -552,24 +552,33 @@ class WorkOrder(Document):
d.db_set('transferred_qty', flt(transferred_qty), update_modified = False)
def update_consumed_qty_for_required_items(self):
'''update consumed qty from submitted stock entries for that item against
the work order'''
'''
Update consumed qty from submitted stock entries
against a work order for each stock item
'''
for d in self.required_items:
consumed_qty = frappe.db.sql('''select sum(qty)
from `tabStock Entry` entry, `tabStock Entry Detail` detail
where
for item in self.required_items:
consumed_qty = frappe.db.sql('''
SELECT
SUM(qty)
FROM
`tabStock Entry` entry,
`tabStock Entry Detail` detail
WHERE
entry.work_order = %(name)s
and (entry.purpose = "Material Consumption for Manufacture"
or entry.purpose = "Manufacture")
and entry.docstatus = 1
and detail.parent = entry.name
and (detail.item_code = %(item)s or detail.original_item = %(item)s)''', {
'name': self.name,
'item': d.item_code
})[0][0]
AND (entry.purpose = "Material Consumption for Manufacture"
OR entry.purpose = "Manufacture")
AND entry.docstatus = 1
AND detail.parent = entry.name
AND detail.s_warehouse IS NOT null
AND (detail.item_code = %(item)s
OR detail.original_item = %(item)s)
''', {
'name': self.name,
'item': item.item_code
})[0][0]
d.db_set('consumed_qty', flt(consumed_qty), update_modified = False)
item.db_set('consumed_qty', flt(consumed_qty), update_modified=False)
def make_bom(self):
data = frappe.db.sql(""" select sed.item_code, sed.qty, sed.s_warehouse
@ -648,7 +657,7 @@ def get_item_details(item, project = None):
return res
@frappe.whitelist()
def make_work_order(item, qty=0, project=None):
def make_work_order(bom_no, item, qty=0, project=None):
if not frappe.has_permission("Work Order", "write"):
frappe.throw(_("Not permitted"), frappe.PermissionError)
@ -657,6 +666,7 @@ def make_work_order(item, qty=0, project=None):
wo_doc = frappe.new_doc("Work Order")
wo_doc.production_item = item
wo_doc.update(item_details)
wo_doc.bom_no = bom_no
if flt(qty) > 0:
wo_doc.qty = flt(qty)

View File

@ -626,10 +626,11 @@ erpnext.patches.v12_0.update_ewaybill_field_position
erpnext.patches.v12_0.create_accounting_dimensions_in_missing_doctypes
erpnext.patches.v11_1.set_status_for_material_request_type_manufacture
erpnext.patches.v12_0.move_plaid_settings_to_doctype
execute:frappe.reload_doc('desk', 'doctype','dashboard_chart_link')
execute:frappe.reload_doc('desk', 'doctype','dashboard')
execute:frappe.reload_doc('desk', 'doctype','dashboard_chart_source')
execute:frappe.reload_doc('desk', 'doctype','dashboard_chart')
execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart_link')
execute:frappe.reload_doc('desk', 'doctype', 'dashboard')
execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart_source')
execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart')
execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart_field')
erpnext.patches.v12_0.add_default_dashboards
erpnext.patches.v12_0.remove_bank_remittance_custom_fields
erpnext.patches.v12_0.generate_leave_ledger_entries
@ -658,4 +659,6 @@ erpnext.patches.v12_0.set_permission_einvoicing
erpnext.patches.v12_0.set_published_in_hub_tracked_item
erpnext.patches.v12_0.set_job_offer_applicant_email
erpnext.patches.v12_0.create_irs_1099_field_united_states
erpnext.patches.v12_0.move_bank_account_swift_number_to_bank
erpnext.patches.v12_0.rename_bank_reconciliation_fields # 2020-01-22
erpnext.patches.v12_0.set_received_qty_in_material_request_as_per_stock_uom

View File

@ -0,0 +1,15 @@
from __future__ import unicode_literals
import frappe
def execute():
frappe.reload_doc('accounts', 'doctype', 'bank', force=1)
if frappe.db.table_exists('Bank') and frappe.db.table_exists('Bank Account'):
frappe.db.sql("""
UPDATE `tabBank` b, `tabBank Account` ba
SET b.swift_number = ba.swift_number, b.branch_code = ba.branch_code
WHERE b.name = ba.bank
""")
frappe.reload_doc('accounts', 'doctype', 'bank_account')
frappe.reload_doc('accounts', 'doctype', 'payment_request')

View File

@ -0,0 +1,30 @@
from __future__ import unicode_literals
import frappe
def execute():
purchase_receipts = frappe.db.sql("""
SELECT
parent from `tabPurchase Receipt Item`
WHERE
material_request is not null
AND docstatus=1
""",as_dict=1)
purchase_receipts = set([d.parent for d in purchase_receipts])
for pr in purchase_receipts:
doc = frappe.get_doc("Purchase Receipt", pr)
doc.status_updater = [
{
'source_dt': 'Purchase Receipt Item',
'target_dt': 'Material Request Item',
'join_field': 'material_request_item',
'target_field': 'received_qty',
'target_parent_dt': 'Material Request',
'target_parent_field': 'per_received',
'target_ref_field': 'stock_qty',
'source_field': 'stock_qty',
'percent_join_field': 'material_request'
}
]
doc.update_qty()

View File

@ -18,7 +18,7 @@ frappe.ui.form.on("Project", {
};
},
onload: function (frm) {
var so = frappe.meta.get_docfield("Project", "sales_order");
var so = frm.get_docfield("Project", "sales_order");
so.get_route_options_for_new_doc = function (field) {
if (frm.is_new()) return;
return {
@ -135,4 +135,4 @@ function open_form(frm, doctype, child_doctype, parentfield) {
frappe.ui.form.make_quick_entry(doctype, null, null, new_doc);
});
}
}

View File

@ -6,7 +6,7 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
apply_pricing_rule_on_item: function(item){
let effective_item_rate = item.price_list_rate;
if (item.parenttype === "Sales Order" && item.blanket_order_rate) {
if (in_list(["Sales Order", "Quotation"], item.parenttype) && item.blanket_order_rate) {
effective_item_rate = item.blanket_order_rate;
}
if(item.margin_type == "Percentage"){

View File

@ -4,7 +4,7 @@
erpnext.TransactionController = erpnext.taxes_and_totals.extend({
setup: function() {
this._super();
frappe.flags.hide_serial_batch_dialog = false;
frappe.flags.hide_serial_batch_dialog = true;
frappe.ui.form.on(this.frm.doctype + " Item", "rate", function(frm, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn);
var has_margin_field = frappe.meta.has_field(cdt, 'margin_type');
@ -165,6 +165,16 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
return (doc.rule_applied) ? "green" : "red";
});
}
let batch_no_field = this.frm.get_docfield("items", "batch_no");
if (batch_no_field) {
batch_no_field.get_route_options_for_new_doc = function(row) {
return {
"item": row.doc.item_code
}
};
}
},
onload: function() {
var me = this;
@ -352,12 +362,17 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
['serial_no', 'batch_no', 'barcode'].forEach(field => {
if (data[field] && frappe.meta.has_field(row_to_modify.doctype, field)) {
let value = (row_to_modify[field] && field === "serial_no")
? row_to_modify[field] + '\n' + data[field] : data[field];
frappe.model.set_value(row_to_modify.doctype,
row_to_modify.name, field, data[field]);
row_to_modify.name, field, value);
}
});
scan_barcode_field.set_value('');
refresh_field("items");
});
}
return false;
@ -519,6 +534,15 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
},
() => me.toggle_conversion_factor(item),
() => {
if (show_batch_dialog)
return frappe.db.get_value("Item", item.item_code, ["has_batch_no", "has_serial_no"])
.then((r) => {
if(r.message.has_batch_no || r.message.has_serial_no) {
frappe.flags.hide_serial_batch_dialog = false;
}
});
},
() => {
if(show_batch_dialog && !frappe.flags.hide_serial_batch_dialog) {
var d = locals[cdt][cdn];
@ -528,7 +552,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
erpnext.show_serial_batch_selector(me.frm, d, (item) => {
me.frm.script_manager.trigger('qty', item.doctype, item.name);
});
if (!me.frm.doc.set_warehouse)
me.frm.script_manager.trigger('warehouse', item.doctype, item.name);
}, undefined, !frappe.flags.hide_serial_batch_dialog);
}
},
() => me.conversion_factor(doc, cdt, cdn, true),

View File

@ -29,7 +29,7 @@ class Quiz {
this.questions.push(question)
this.wrapper.appendChild(question_wrapper);
})
if (data.activity.is_complete) {
if (data.activity && data.activity.is_complete) {
this.disable()
let indicator = 'red'
let message = 'Your are not allowed to attempt the quiz again.'

View File

@ -453,7 +453,8 @@ erpnext.utils.update_child_items = function(opts) {
fields: [{
fieldtype:'Data',
fieldname:"docname",
hidden: 0,
read_only: 1,
hidden: 1,
}, {
fieldtype:'Link',
fieldname:"item_code",

View File

@ -1,23 +1,25 @@
frappe.provide('frappe.ui.form');
erpnext.doctypes_with_dimensions = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "Asset",
let default_dimensions = {};
let doctypes_with_dimensions = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "Asset",
"Expense Claim", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note", "Shipping Rule", "Loyalty Program",
"Fee Schedule", "Fee Structure", "Stock Reconciliation", "Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool",
"Subscription", "Purchase Order", "Journal Entry", "Material Request", "Purchase Receipt", "Landed Cost Item", "Asset"];
erpnext.child_docs = ["Sales Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Journal Entry Account",
let child_docs = ["Sales Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Journal Entry Account",
"Material Request Item", "Delivery Note Item", "Purchase Receipt Item", "Stock Entry Detail", "Payment Entry Deduction",
"Landed Cost Item", "Asset Value Adjustment", "Opening Invoice Creation Tool Item", "Subscription Plan"];
frappe.call({
method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.get_dimension_filters",
callback: function(r){
callback: function(r) {
erpnext.dimension_filters = r.message[0];
erpnext.default_dimensions = r.message[1];
default_dimensions = r.message[1];
}
});
erpnext.doctypes_with_dimensions.forEach((doctype) => {
doctypes_with_dimensions.forEach((doctype) => {
frappe.ui.form.on(doctype, {
onload: function(frm) {
erpnext.dimension_filters.forEach((dimension) => {
@ -27,41 +29,40 @@ erpnext.doctypes_with_dimensions.forEach((doctype) => {
"is_group": 0
});
}
if (Object.keys(erpnext.default_dimensions).length > 0) {
if (frappe.meta.has_field(doctype, dimension['fieldname'])) {
if (frm.is_new() && frappe.meta.has_field(doctype, 'company') && frm.doc.company) {
frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]);
}
}
if (frm.doc.items && frm.doc.items.length && frm.doc.docstatus === 0
&& (!frm.doc.items[0][dimension['fieldname']])) {
frm.doc.items[0][dimension['fieldname']] = erpnext.default_dimensions[frm.doc.company][dimension['document_type']];
}
if (frm.doc.accounts && frm.doc.accounts.length && frm.doc.docstatus === 0
&& (!frm.doc.items[0][dimension['fieldname']])) {
frm.doc.accounts[0][dimension['fieldname']] = erpnext.default_dimensions[frm.doc.company][dimension['document_type']];
}
}
});
});
},
company: function(frm) {
if(frm.doc.company && (Object.keys(erpnext.default_dimensions).length > 0)) {
erpnext.dimension_filters.forEach((dimension) => {
if (frappe.meta.has_field(doctype, dimension['fieldname'])) {
frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]);
}
});
if(frm.doc.company && (Object.keys(default_dimensions || {}).length > 0)
&& default_dimensions[frm.doc.company]) {
frm.trigger('update_dimension');
}
},
update_dimension: function(frm) {
erpnext.dimension_filters.forEach((dimension) => {
if (frm.is_new()) {
if (frm.doc.company && Object.keys(default_dimensions || {}).length > 0
&& default_dimensions[frm.doc.company]) {
if (frappe.meta.has_field(doctype, dimension['fieldname'])) {
frm.set_value(dimension['fieldname'],
default_dimensions[frm.doc.company][dimension['document_type']]);
}
$.each(frm.doc.items || frm.doc.accounts || [], function(i, row) {
frappe.model.set_value(row.doctype, row.name, dimension['fieldname'],
default_dimensions[frm.doc.company][dimension['document_type']])
});
}
}
});
}
});
});
erpnext.child_docs.forEach((doctype) => {
child_docs.forEach((doctype) => {
frappe.ui.form.on(doctype, {
items_add: function(frm, cdt, cdn) {
erpnext.dimension_filters.forEach((dimension) => {
@ -77,14 +78,6 @@ erpnext.child_docs.forEach((doctype) => {
});
},
company: function(frm) {
if(frm.doc.company) {
erpnext.dimension_filters.forEach((dimension) => {
frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]);
});
}
},
items_add: function(frm, cdt, cdn) {
erpnext.dimension_filters.forEach((dimension) => {
var row = frappe.get_doc(cdt, cdn);

View File

@ -8,12 +8,19 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
render_dialog: function() {
this.mandatory = this.get_variant_fields().concat(this.mandatory);
this.mandatory = this.mandatory.concat(this.get_attributes_fields());
this.check_naming_series_based_on();
this._super();
this.init_post_render_dialog_operations();
this.preset_fields_for_template();
this.dialog.$wrapper.find('.edit-full').text(__('Edit in full page for more options like assets, serial nos, batches etc.'))
},
check_naming_series_based_on: function() {
if (frappe.defaults.get_default("item_naming_by") === "Naming Series") {
this.mandatory = this.mandatory.filter(d => d.fieldname !== "item_code");
}
},
init_post_render_dialog_operations: function() {
this.dialog.fields_dict.attribute_html.$wrapper.append(frappe.render_template("item_quick_entry"));
this.init_for_create_variant_trigger();

View File

@ -5,14 +5,13 @@ erpnext.SerialNoBatchSelector = Class.extend({
this.show_dialog = show_dialog;
// frm, item, warehouse_details, has_batch, oldest
let d = this.item;
if (d && d.has_batch_no && (!d.batch_no || this.show_dialog)) {
this.has_batch = 1;
this.setup();
this.has_batch = 0; this.has_serial_no = 0;
if (d && d.has_batch_no && (!d.batch_no || this.show_dialog)) this.has_batch = 1;
// !(this.show_dialog == false) ensures that show_dialog is implictly true, even when undefined
} else if(d && d.has_serial_no && !(this.show_dialog == false)) {
this.has_batch = 0;
this.setup();
}
if(d && d.has_serial_no && !(this.show_dialog == false)) this.has_serial_no = 1;
this.setup();
},
setup: function() {
@ -36,16 +35,16 @@ erpnext.SerialNoBatchSelector = Class.extend({
label: __('Item Code'),
default: me.item_code
},
{fieldtype:'Column Break'},
{
fieldname: 'warehouse',
fieldtype:'Link',
options: 'Warehouse',
reqd: me.has_batch && !me.has_serial_no ? 0 : 1,
label: __(me.warehouse_details.type),
default: me.warehouse_details.name,
default: typeof me.warehouse_details.name == "string" ? me.warehouse_details.name : '',
onchange: function(e) {
if(me.has_batch) {
if(me.has_batch && !me.has_serial_no) {
fields = fields.concat(me.get_batch_fields());
} else {
fields = fields.concat(me.get_serial_no_fields());
@ -74,15 +73,16 @@ erpnext.SerialNoBatchSelector = Class.extend({
{
fieldname: 'qty',
fieldtype:'Float',
read_only: me.has_batch,
label: __(me.has_batch ? 'Total Qty' : 'Qty'),
read_only: me.has_batch && !me.has_serial_no,
label: __(me.has_batch && !me.has_serial_no ? 'Total Qty' : 'Qty'),
default: 0
},
{
fieldname: 'auto_fetch_button',
fieldtype:'Button',
hidden: me.has_batch,
label: __('Fetch based on FIFO'),
hidden: me.has_batch && !me.has_serial_no,
label: __('Auto Fetch'),
description: __('Fetch Serial Numbers based on FIFO'),
click: () => {
let qty = this.dialog.fields_dict.qty.get_value();
let numbers = frappe.call({
@ -90,7 +90,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
args: {
qty: qty,
item_code: me.item_code,
warehouse: me.warehouse_details.name,
warehouse: typeof me.warehouse_details.name == "string" ? me.warehouse_details.name : '',
batch_no: me.item.batch_no || null
}
});
@ -109,10 +109,12 @@ erpnext.SerialNoBatchSelector = Class.extend({
}
];
if (this.has_batch) {
if (this.has_batch && !this.has_serial_no) {
title = __("Select Batch Numbers");
fields = fields.concat(this.get_batch_fields());
} else {
// if only serial no OR
// if both batch_no & serial_no then only select serial_no and auto set batches nos
title = __("Select Serial Numbers");
fields = fields.concat(this.get_serial_no_fields());
}
@ -122,25 +124,31 @@ erpnext.SerialNoBatchSelector = Class.extend({
fields: fields
});
if (this.item.serial_no) {
this.dialog.fields_dict.serial_no.set_value(this.item.serial_no);
}
this.dialog.set_primary_action(__('Insert'), function() {
me.values = me.dialog.get_values();
if(me.validate()) {
me.set_items();
me.dialog.hide();
frappe.run_serially([
() => me.update_batch_items(),
() => me.update_serial_no_item(),
() => me.update_batch_serial_no_items(),
() => {
refresh_field("items");
if (me.callback) {
return me.callback(me.item);
}
},
() => me.dialog.hide()
])
}
});
if(this.show_dialog) {
let d = this.item;
if (d.has_serial_no && d.serial_no) {
this.dialog.set_value('serial_no', d.serial_no);
if (this.item.serial_no) {
this.dialog.fields_dict.serial_no.set_value(this.item.serial_no);
}
if (d.has_batch_no && d.batch_no) {
if (this.has_batch && !this.has_serial_no && d.batch_no) {
this.frm.doc.items.forEach(data => {
if(data.item_code == d.item_code) {
this.dialog.fields_dict.batches.df.data.push({
@ -155,7 +163,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
}
}
if (this.has_batch) {
if (this.has_batch && !this.has_serial_no) {
this.update_total_qty();
}
@ -174,7 +182,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
frappe.throw(__("Please select a warehouse"));
return false;
}
if(this.has_batch) {
if(this.has_batch && !this.has_serial_no) {
if(values.batches.length === 0 || !values.batches) {
frappe.throw(__("Please select batches for batched item "
+ values.item_code));
@ -193,34 +201,23 @@ erpnext.SerialNoBatchSelector = Class.extend({
} else {
let serial_nos = values.serial_no || '';
if (!serial_nos || !serial_nos.replace(/\s/g, '').length) {
if (!this.show_dialog) {
frappe.throw(__("Please enter serial numbers for serialized item "
+ values.item_code));
return false;
}
frappe.throw(__("Please enter serial numbers for serialized item "
+ values.item_code));
return false;
}
return true;
}
},
set_items: function() {
var me = this;
if(this.has_batch) {
update_batch_items() {
// clones an items if muliple batches are selected.
if(this.has_batch && !this.has_serial_no) {
this.values.batches.map((batch, i) => {
let batch_no = batch.batch_no;
let row = '';
if (i !== 0 && !this.batch_exists(batch_no)) {
row = this.frm.add_child("items", {
'item_code': this.item.item_code,
'item_name': this.item.item_name,
'price_list_rate': this.item.price_list_rate,
'rate': this.item.rate,
'qty': batch.selected_qty,
'batch_no': batch_no,
'actual_qty': this.item.actual_qty,
'discount_percentage': this.item.discount_percentage
});
row = this.frm.add_child("items", { ...this.item });
} else {
row = this.frm.doc.items.find(i => i.batch_no === batch_no);
}
@ -228,16 +225,59 @@ erpnext.SerialNoBatchSelector = Class.extend({
if (!row) {
row = this.item;
}
// this ensures that qty & batch no is set
this.map_row_values(row, batch, 'batch_no',
'selected_qty', this.values.warehouse);
});
} else {
}
},
update_serial_no_item() {
// just updates serial no for the item
if(this.has_serial_no && !this.has_batch) {
this.map_row_values(this.item, this.values, 'serial_no', 'qty');
}
},
refresh_field("items");
this.callback && this.callback(this.item);
update_batch_serial_no_items() {
// if serial no selected is from different batches, adds new rows for each batch.
if(this.has_batch && this.has_serial_no) {
const selected_serial_nos = this.values.serial_no.split(/\n/g).filter(s => s);
return frappe.db.get_list("Serial No", {
filters: { 'name': ["in", selected_serial_nos]},
fields: ["batch_no", "name"]
}).then((data) => {
// data = [{batch_no: 'batch-1', name: "SR-001"},
// {batch_no: 'batch-2', name: "SR-003"}, {batch_no: 'batch-2', name: "SR-004"}]
const batch_serial_map = data.reduce((acc, d) => {
if (!acc[d['batch_no']]) acc[d['batch_no']] = [];
acc[d['batch_no']].push(d['name'])
return acc
}, {})
// batch_serial_map = { "batch-1": ['SR-001'], "batch-2": ["SR-003", "SR-004"]}
Object.keys(batch_serial_map).map((batch_no, i) => {
let row = '';
const serial_no = batch_serial_map[batch_no];
if (i == 0) {
row = this.item;
this.map_row_values(row, {qty: serial_no.length, batch_no: batch_no}, 'batch_no',
'qty', this.values.warehouse);
} else if (!this.batch_exists(batch_no)) {
row = this.frm.add_child("items", { ...this.item });
row.batch_no = batch_no;
} else {
row = this.frm.doc.items.find(i => i.batch_no === batch_no);
}
const values = {
'qty': serial_no.length,
'serial_no': serial_no.join('\n')
}
this.map_row_values(row, values, 'serial_no',
'qty', this.values.warehouse);
});
})
}
},
batch_exists: function(batch) {
@ -287,7 +327,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
return {
filters: {
item_code: me.item_code,
warehouse: me.warehouse || me.warehouse_details.name
warehouse: me.warehouse || typeof me.warehouse_details.name == "string" ? me.warehouse_details.name : ''
},
query: 'erpnext.controllers.queries.get_batch_no'
};
@ -313,11 +353,15 @@ erpnext.SerialNoBatchSelector = Class.extend({
frappe.throw(__(`Batch ${val} already selected.`));
return;
}
let batch_number = me.item.batch_no ||
this.grid_row.on_grid_fields_dict.batch_no.get_value();
if (me.warehouse_details.name) {
frappe.call({
method: 'erpnext.stock.doctype.batch.batch.get_batch_qty',
args: {
batch_no: me.item.batch_no,
batch_no: batch_number,
warehouse: me.warehouse_details.name,
item_code: me.item_code
},
@ -444,7 +488,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
{
fieldname: 'serial_no',
fieldtype: 'Small Text',
label: __(me.has_batch ? 'Selected Batch Numbers' : 'Selected Serial Numbers'),
label: __(me.has_batch && !me.has_serial_no ? 'Selected Batch Numbers' : 'Selected Serial Numbers'),
onchange: function() {
me.serial_list = this.get_value()
.replace(/\n/g, ' ').match(/\S+/g) || [];

View File

@ -21,6 +21,12 @@ frappe.query_reports["DATEV"] = {
"default": frappe.datetime.now_date(),
"fieldtype": "Date",
"reqd": 1
},
{
"fieldname": "voucher_type",
"label": __("Voucher Type"),
"fieldtype": "Select",
"options": "\nSales Invoice\nPurchase Invoice\nPayment Entry\nExpense Claim\nPayroll Entry\nBank Reconciliation\nAsset\nStock Entry"
}
],
onload: function(query_report) {

View File

@ -62,6 +62,7 @@ def get_transactions(filters, as_dict=1):
filters -- dict of filters to be passed to the sql query
as_dict -- return as list of dicts [0,1]
"""
filter_by_voucher = 'AND gl.voucher_type = %(voucher_type)s' if filters.get('voucher_type') else ''
gl_entries = frappe.db.sql("""
SELECT
@ -80,8 +81,10 @@ def get_transactions(filters, as_dict=1):
gl.posting_date as 'Belegdatum',
gl.voucher_no as 'Belegfeld 1',
gl.remarks as 'Buchungstext',
gl.against_voucher_type as 'Beleginfo - Art 1',
gl.against_voucher as 'Beleginfo - Inhalt 1'
gl.voucher_type as 'Beleginfo - Art 1',
gl.voucher_no as 'Beleginfo - Inhalt 1',
gl.against_voucher_type as 'Beleginfo - Art 2',
gl.against_voucher as 'Beleginfo - Inhalt 2'
FROM `tabGL Entry` gl
@ -109,7 +112,8 @@ def get_transactions(filters, as_dict=1):
WHERE gl.company = %(company)s
AND DATE(gl.posting_date) >= %(from_date)s
AND DATE(gl.posting_date) <= %(to_date)s
ORDER BY 'Belegdatum', gl.voucher_no""", filters, as_dict=as_dict, as_utf8=1)
{}
ORDER BY 'Belegdatum', gl.voucher_no""".format(filter_by_voucher), filters, as_dict=as_dict)
return gl_entries
@ -160,7 +164,7 @@ def get_customers(filters):
and ccl.company = par.company
WHERE par.company = %(company)s
AND par.parenttype = 'Customer'""", filters, as_dict=1, as_utf8=1)
AND par.parenttype = 'Customer'""", filters, as_dict=1)
def get_suppliers(filters):
@ -217,7 +221,7 @@ def get_suppliers(filters):
and con.is_primary_contact = '1'
WHERE par.company = %(company)s
AND par.parenttype = 'Supplier'""", filters, as_dict=1, as_utf8=1)
AND par.parenttype = 'Supplier'""", filters, as_dict=1)
def get_account_names(filters):
@ -281,24 +285,24 @@ def get_datev_csv(data, filters, csv_class):
def get_header(filters, csv_class):
coa = frappe.get_value("Company", filters.get("company"), "chart_of_accounts")
coa_used = "SKR04" if "SKR04" in coa else ("SKR03" if "SKR03" in coa else "")
coa_used = "04" if "SKR04" in coa else ("03" if "SKR03" in coa else "")
header = [
# DATEV format
# "DTVF" = created by DATEV software,
# "EXTF" = created by other software
# "DTVF" = created by DATEV software,
# "EXTF" = created by other software
'"EXTF"',
# version of the DATEV format
# 141 = 1.41,
# 510 = 5.10,
# 720 = 7.20
# 141 = 1.41,
# 510 = 5.10,
# 720 = 7.20
'700',
csv_class.DATA_CATEGORY,
'"%s"' % csv_class.FORMAT_NAME,
# Format version (regarding format name)
csv_class.FORMAT_VERSION,
# Generated on
datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
datetime.datetime.now().strftime("%Y%m%d%H%M%S") + '000',
# Imported on -- stays empty
'',
# Origin. Any two symbols, will be replaced by "SV" on import.
@ -328,13 +332,21 @@ def get_header(filters, csv_class):
# R = Diktatkürzel
'',
# S = Buchungstyp
# 1 = Transaction batch (Finanzbuchführung),
# 2 = Annual financial statement (Jahresabschluss)
# 1 = Transaction batch (Finanzbuchführung),
# 2 = Annual financial statement (Jahresabschluss)
'1' if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else '',
# T = Rechnungslegungszweck
'',
# 0 oder leer = vom Rechnungslegungszweck unabhängig
# 50 = Handelsrecht
# 30 = Steuerrecht
# 64 = IFRS
# 40 = Kalkulatorik
# 11 = Reserviert
# 12 = Reserviert
'0',
# U = Festschreibung
'',
# TODO: Filter by Accounting Period. In export for closed Accounting Period, this will be "1"
'0',
# V = Default currency, for example, "EUR"
'"%s"' % frappe.get_value("Company", filters.get("company"), "default_currency"),
# reserviert

View File

@ -498,13 +498,27 @@ QUERY_REPORT_COLUMNS = [
},
{
"label": "Beleginfo - Art 1",
"fieldname": "Beleginfo - Art 2",
"fieldtype": "Data",
"fieldname": "Beleginfo - Art 1",
"fieldtype": "Link",
"options": "DocType"
},
{
"label": "Beleginfo - Inhalt 1",
"fieldname": "Beleginfo - Inhalt 1",
"fieldtype": "Dynamic Link",
"options": "Beleginfo - Art 1"
},
{
"label": "Beleginfo - Art 2",
"fieldname": "Beleginfo - Art 2",
"fieldtype": "Link",
"options": "DocType"
},
{
"label": "Beleginfo - Inhalt 2",
"fieldname": "Beleginfo - Inhalt 2",
"fieldtype": "Data",
"fieldtype": "Dynamic Link",
"options": "Beleginfo - Art 2"
}
]

View File

@ -54,8 +54,8 @@ class Gstr1Report(object):
return self.columns, self.data
def get_data(self):
if self.filters.get("type_of_business") == "B2C Small":
self.get_b2cs_data()
if self.filters.get("type_of_business") in ("B2C Small", "B2C Large"):
self.get_b2c_data()
else:
for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
invoice_details = self.invoices.get(inv)
@ -69,7 +69,7 @@ class Gstr1Report(object):
if taxable_value:
self.data.append(row)
def get_b2cs_data(self):
def get_b2c_data(self):
b2cs_output = {}
for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
@ -84,7 +84,10 @@ class Gstr1Report(object):
"rate": "",
"taxable_value": 0,
"cess_amount": 0,
"type": ""
"type": "",
"invoice_number": invoice_details.get("invoice_number"),
"posting_date": invoice_details.get("posting_date"),
"invoice_value": invoice_details.get("base_grand_total"),
})
row = b2cs_output.get((rate, place_of_supply, ecommerce_gstin))
@ -164,7 +167,7 @@ class Gstr1Report(object):
frappe.throw(_("Please set B2C Limit in GST Settings."))
if self.filters.get("type_of_business") == "B2C Large":
conditions += """ and SUBSTR(place_of_supply, 1, 2) != SUBSTR(company_gstin, 1, 2)
conditions += """ and ifnull(SUBSTR(place_of_supply, 1, 2),'') != ifnull(SUBSTR(company_gstin, 1, 2),'')
and grand_total > {0} and is_return != 1 and gst_category ='Unregistered' """.format(flt(b2c_limit))
elif self.filters.get("type_of_business") == "B2C Small":
@ -581,6 +584,11 @@ def get_b2b_json(res, gstin):
if not gst_in: continue
for number, invoice in iteritems(res[gst_in]):
if not invoice[0]["place_of_supply"]:
frappe.throw(_("""{0} not entered in Invoice {1}.
Please update and try again""").format(frappe.bold("Place Of Supply"),
frappe.bold(invoice[0]['invoice_number'])))
inv_item = get_basic_invoice_detail(invoice[0])
inv_item["pos"] = "%02d" % int(invoice[0]["place_of_supply"].split('-')[0])
inv_item["rchrg"] = invoice[0]["reverse_charge"]
@ -606,6 +614,9 @@ def get_b2cs_json(data, gstin):
out = []
for d in data:
if not d.get("place_of_supply"):
frappe.throw(_("""{0} not entered in some invoices.
Please update and try again""").format(frappe.bold("Place Of Supply")))
pos = d.get('place_of_supply').split('-')[0]
tax_details = {}
@ -642,6 +653,10 @@ def get_b2cs_json(data, gstin):
def get_b2cl_json(res, gstin):
out = []
for pos in res:
if not pos:
frappe.throw(_("""{0} not entered in some invoices.
Please update and try again""").format(frappe.bold("Place Of Supply")))
b2cl_item, inv = {"pos": "%02d" % int(pos.split('-')[0]), "inv": []}, []
for row in res[pos]:

View File

@ -268,9 +268,11 @@ def make_quotation(source_name, target_doc=None):
target_doc.run_method("set_other_charges")
target_doc.run_method("calculate_taxes_and_totals")
price_list = frappe.get_value("Customer", source_name, 'default_price_list')
price_list, currency = frappe.db.get_value("Customer", {'name': source_name}, ['default_price_list', 'default_currency'])
if price_list:
target_doc.selling_price_list = price_list
if currency:
target_doc.currency = currency
return target_doc

View File

@ -155,6 +155,11 @@ def _make_sales_order(source_name, target_doc=None, ignore_permissions=False):
def update_item(obj, target, source_parent):
target.stock_qty = flt(obj.qty) * flt(obj.conversion_factor)
if obj.against_blanket_order:
target.against_blanket_order = obj.against_blanket_order
target.blanket_order = obj.blanket_order
target.blanket_order_rate = obj.blanket_order_rate
doclist = get_mapped_doc("Quotation", source_name, {
"Quotation": {
"doctype": "Sales Order",

View File

@ -55,6 +55,9 @@
"weight_uom",
"reference",
"warehouse",
"against_blanket_order",
"blanket_order",
"blanket_order_rate",
"column_break_30",
"prevdoc_doctype",
"prevdoc_docname",
@ -573,12 +576,38 @@
"fieldname": "image_section",
"fieldtype": "Section Break",
"label": "Image"
},
{
"depends_on": "eval:doc.against_blanket_order",
"fieldname": "blanket_order",
"fieldtype": "Link",
"label": "Blanket Order",
"no_copy": 1,
"options": "Blanket Order",
"print_hide": 1
},
{
"depends_on": "eval:doc.against_blanket_order",
"fieldname": "blanket_order_rate",
"fieldtype": "Currency",
"label": "Blanket Order Rate",
"no_copy": 1,
"print_hide": 1,
"read_only": 1
},
{
"default": "0",
"fieldname": "against_blanket_order",
"fieldtype": "Check",
"label": "Against Blanket Order",
"no_copy": 1,
"print_hide": 1
}
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2020-03-05 14:18:58.783751",
"modified": "2020-03-30 18:40:28.782720",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation Item",

View File

@ -664,7 +664,8 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
reference_doctype: me.frm.doctype,
reference_name: me.frm.docname,
content: __('Reason for hold: ')+data.reason_for_hold,
comment_email: frappe.session.user
comment_email: frappe.session.user,
comment_by: frappe.session.user_fullname
},
callback: function(r) {
if(!r.exc) {

View File

@ -496,7 +496,7 @@ def close_or_unclose_sales_orders(names, status):
def get_requested_item_qty(sales_order):
return frappe._dict(frappe.db.sql("""
select sales_order_item, sum(stock_qty)
select sales_order_item, sum(qty)
from `tabMaterial Request Item`
where docstatus = 1
and sales_order = %s
@ -507,16 +507,12 @@ def get_requested_item_qty(sales_order):
def make_material_request(source_name, target_doc=None):
requested_item_qty = get_requested_item_qty(source_name)
def postprocess(source, doc):
doc.material_request_type = "Purchase"
def update_item(source, target, source_parent):
# qty is for packed items, because packed items don't have stock_qty field
qty = source.get("stock_qty") or source.get("qty")
qty = source.get("qty")
target.project = source_parent.project
target.qty = qty - requested_item_qty.get(source.name, 0)
target.conversion_factor = 1
target.stock_qty = qty - requested_item_qty.get(source.name, 0)
target.stock_qty = flt(target.qty) * flt(target.conversion_factor)
doc = get_mapped_doc("Sales Order", source_name, {
"Sales Order": {
@ -537,14 +533,12 @@ def make_material_request(source_name, target_doc=None):
"doctype": "Material Request Item",
"field_map": {
"name": "sales_order_item",
"parent": "sales_order",
"stock_uom": "uom",
"stock_qty": "qty"
"parent": "sales_order"
},
"condition": lambda doc: not frappe.db.exists('Product Bundle', doc.item_code) and doc.stock_qty > requested_item_qty.get(doc.name, 0),
"postprocess": update_item
}
}, target_doc, postprocess)
}, target_doc)
return doc

View File

@ -64,30 +64,40 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p
for d in item_prices_data:
item_prices[d.item_code] = d
# prepare filter for bin query
bin_filters = {'item_code': ['in', items]}
if warehouse:
bin_filters['warehouse'] = warehouse
if display_items_in_stock:
filters = {'actual_qty': [">", 0], 'item_code': ['in', items]}
bin_filters['actual_qty'] = [">", 0]
if warehouse:
filters['warehouse'] = warehouse
# query item bin
bin_data = frappe.get_all(
'Bin', fields=['item_code', 'sum(actual_qty) as actual_qty'],
filters=bin_filters, group_by='item_code'
)
bin_data = frappe._dict(
frappe.get_all("Bin", fields = ["item_code", "sum(actual_qty) as actual_qty"],
filters = filters, group_by = "item_code")
)
# convert list of dict into dict as {item_code: actual_qty}
bin_dict = {}
for b in bin_data:
bin_dict[b.get('item_code')] = b.get('actual_qty')
for item in items_data:
row = {}
item_code = item.item_code
item_price = item_prices.get(item_code) or {}
item_stock_qty = bin_dict.get(item_code)
row.update(item)
item_price = item_prices.get(item.item_code) or {}
row.update({
'price_list_rate': item_price.get('price_list_rate'),
'currency': item_price.get('currency'),
'actual_qty': bin_data.get('actual_qty')
})
result.append(row)
if display_items_in_stock and not item_stock_qty:
pass
else:
row = {}
row.update(item)
row.update({
'price_list_rate': item_price.get('price_list_rate'),
'currency': item_price.get('currency'),
'actual_qty': item_stock_qty,
})
result.append(row)
res = {
'items': result

View File

@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import getdate, cint
from frappe.utils import getdate, cint, cstr
import calendar
def execute(filters=None):
@ -48,7 +48,7 @@ def execute(filters=None):
new = new_customers_in.get(key, [0,0.0])
repeat = repeat_customers_in.get(key, [0,0.0])
out.append([year, calendar.month_name[month],
out.append([cstr(year), calendar.month_name[month],
new[0], repeat[0], new[0] + repeat[0],
new[1], repeat[1], new[1] + repeat[1]])

View File

@ -121,8 +121,8 @@ def get_columns(filters):
},
{
"label": _("Billed Amount"),
"fieldname": "rate",
"options": "billed_amount",
"fieldtype": "currency",
"fieldname": "billed_amount",
"width": 120
},
{

View File

@ -413,15 +413,20 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
*/
set_batch_number: function(cdt, cdn) {
const doc = frappe.get_doc(cdt, cdn);
if (doc && doc.has_batch_no) {
if (doc && doc.has_batch_no && doc.warehouse) {
this._set_batch_number(doc);
}
},
_set_batch_number: function(doc) {
let args = {'item_code': doc.item_code, 'warehouse': doc.warehouse, 'qty': flt(doc.qty) * flt(doc.conversion_factor)};
if (doc.has_serial_no && doc.serial_no) {
args['serial_no'] = doc.serial_no
}
return frappe.call({
method: 'erpnext.stock.doctype.batch.batch.get_batch_no',
args: {'item_code': doc.item_code, 'warehouse': doc.warehouse, 'qty': flt(doc.qty) * flt(doc.conversion_factor)},
args: args,
callback: function(r) {
if(r.message) {
frappe.model.set_value(doc.doctype, doc.name, 'batch_no', r.message);

View File

@ -41,8 +41,7 @@
"charts": [
{
"chart_name": "Bank Balance",
"label": "All Your Money",
"size": "Full"
"label": "Bank Balance"
}
],
"creation": "2020-01-23 13:46:38.833076",
@ -55,7 +54,7 @@
"idx": 0,
"is_standard": 1,
"label": "Getting Started",
"modified": "2020-03-12 16:30:37.821762",
"modified": "2020-03-23 11:20:49.161823",
"modified_by": "Administrator",
"module": "Setup",
"name": "Getting Started",
@ -82,6 +81,16 @@
"is_query_report": 0,
"link_to": "Sales Invoice",
"type": "DocType"
},
{
"is_query_report": 0,
"link_to": "dashboard",
"type": "Page"
},
{
"is_query_report": 0,
"link_to": "leaderboard",
"type": "Page"
}
]
}

View File

@ -157,6 +157,7 @@
{
"fieldname": "parent_company",
"fieldtype": "Link",
"ignore_user_permissions": 1,
"in_list_view": 1,
"label": "Parent Company",
"options": "Company"
@ -277,6 +278,7 @@
"depends_on": "eval:doc.create_chart_of_accounts_based_on===\"Existing Company\"",
"fieldname": "existing_company",
"fieldtype": "Link",
"ignore_user_permissions": 1,
"label": "Existing Company ",
"no_copy": 1,
"options": "Company"
@ -728,7 +730,7 @@
"image_field": "company_logo",
"is_tree": 1,
"links": [],
"modified": "2020-03-18 18:09:53.534211",
"modified": "2020-03-21 18:09:53.534211",
"modified_by": "Administrator",
"module": "Setup",
"name": "Company",

View File

@ -13,12 +13,16 @@ install_docs = [
]
def get_warehouse_account_map(company=None):
if not frappe.flags.warehouse_account_map or frappe.flags.in_test:
company_warehouse_account_map = company and frappe.flags.setdefault('warehouse_account_map', {}).get(company)
warehouse_account_map = frappe.flags.warehouse_account_map
if not warehouse_account_map or not company_warehouse_account_map or frappe.flags.in_test:
warehouse_account = frappe._dict()
filters = {}
if company:
filters['company'] = company
frappe.flags.setdefault('warehouse_account_map', {}).setdefault(company, {})
for d in frappe.get_all('Warehouse',
fields = ["name", "account", "parent_warehouse", "company", "is_group"],
@ -30,10 +34,12 @@ def get_warehouse_account_map(company=None):
if d.account:
d.account_currency = frappe.db.get_value('Account', d.account, 'account_currency', cache=True)
warehouse_account.setdefault(d.name, d)
frappe.flags.warehouse_account_map = warehouse_account
return frappe.flags.warehouse_account_map
if company:
frappe.flags.warehouse_account_map[company] = warehouse_account
else:
frappe.flags.warehouse_account_map = warehouse_account
return frappe.flags.warehouse_account_map.get(company) or frappe.flags.warehouse_account_map
def get_warehouse_account(warehouse, warehouse_account=None):
account = warehouse.account

View File

@ -122,8 +122,11 @@ class Batch(Document):
self.expiry_date = add_days(self.manufacturing_date, shelf_life_in_days)
if has_expiry_date and not self.expiry_date:
frappe.msgprint(_('Expiry date is mandatory for selected item.'))
frappe.throw(_("Set item's shelf life in days, to set expiry based on manufacturing date plus shelf-life."))
frappe.throw(msg=_("Please set {0} for Batched Item {1}, which is used to set {2} on Submit.") \
.format(frappe.bold("Shelf Life in Days"),
frappe.utils.get_link_to_form("Item", self.item),
frappe.bold("Batch Expiry Date")),
title=_("Expiry Date Mandatory"))
def get_name_from_naming_series(self):
"""

View File

@ -238,7 +238,7 @@ class DeliveryTrip(Document):
try:
directions = maps_client.directions(**directions_data)
except Exception as e:
frappe.throw(_(e))
frappe.throw(_(str(e)))
return directions[0] if directions else False

View File

@ -343,7 +343,8 @@
{
"fieldname": "shelf_life_in_days",
"fieldtype": "Int",
"label": "Shelf Life In Days"
"label": "Shelf Life In Days",
"mandatory_depends_on": "eval:doc.has_batch_no && doc.has_expiry_date"
},
{
"default": "2099-12-31",
@ -1045,7 +1046,7 @@
"image_field": "image",
"links": [],
"max_attachments": 1,
"modified": "2020-01-02 19:13:59.295963",
"modified": "2020-03-24 16:14:36.950677",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",

View File

@ -741,14 +741,12 @@ class Item(WebsiteGenerator):
defaults = frappe.defaults.get_defaults() or {}
# To check default warehouse is belong to the default company
if defaults.get("default_warehouse") and frappe.db.exists("Warehouse",
if defaults.get("default_warehouse") and defaults.company and frappe.db.exists("Warehouse",
{'name': defaults.default_warehouse, 'company': defaults.company}):
warehouse = defaults.default_warehouse
self.append("item_defaults", {
"company": defaults.get("company"),
"default_warehouse": warehouse
})
self.append("item_defaults", {
"company": defaults.get("company"),
"default_warehouse": defaults.default_warehouse
})
def update_variants(self):
if self.flags.dont_update_variants or \

View File

@ -8,6 +8,7 @@ from frappe.utils import flt
from frappe.model.meta import get_field_precision
from frappe.model.document import Document
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
from erpnext.accounts.doctype.account.account import get_account_currency
class LandedCostVoucher(Document):
def get_items_from_purchase_receipts(self):
@ -43,6 +44,7 @@ class LandedCostVoucher(Document):
else:
self.validate_applicable_charges_for_item()
self.validate_purchase_receipts()
self.validate_expense_accounts()
self.set_total_taxes_and_charges()
def check_mandatory(self):
@ -71,6 +73,14 @@ class LandedCostVoucher(Document):
frappe.throw(_("Row {0}: Cost center is required for an item {1}")
.format(item.idx, item.item_code))
def validate_expense_accounts(self):
company_currency = erpnext.get_company_currency(self.company)
for account in self.taxes:
if get_account_currency(account.expense_account) != company_currency:
frappe.throw(msg=_(""" Row {0}: Expense account currency should be same as company's default currency.
Please select expense account with account currency as {1}""")
.format(account.idx, frappe.bold(company_currency)), title=_("Invalid Account Currency"))
def set_total_taxes_and_charges(self):
self.total_taxes_and_charges = sum([flt(d.amount) for d in self.get("taxes")])

View File

@ -501,7 +501,7 @@ def raise_work_orders(material_request):
wo_order = frappe.new_doc("Work Order")
wo_order.update({
"production_item": d.item_code,
"qty": d.qty - d.ordered_qty,
"qty": d.stock_qty - d.ordered_qty,
"fg_warehouse": d.warehouse,
"wip_warehouse": default_wip_warehouse,
"description": d.description,

View File

@ -50,8 +50,8 @@ class PurchaseReceipt(BuyingController):
'target_field': 'received_qty',
'target_parent_dt': 'Material Request',
'target_parent_field': 'per_received',
'target_ref_field': 'qty',
'source_field': 'qty',
'target_ref_field': 'stock_qty',
'source_field': 'stock_qty',
'percent_join_field': 'material_request'
}]
if cint(self.is_return):
@ -357,7 +357,7 @@ class PurchaseReceipt(BuyingController):
if warehouse_with_no_account:
frappe.msgprint(_("No accounting entries for the following warehouses") + ": \n" +
"\n".join(warehouse_with_no_account))
return process_gl_map(gl_entries)
def get_asset_gl_entry(self, gl_entries):
@ -628,7 +628,7 @@ def get_item_account_wise_additional_cost(purchase_document):
if not landed_cost_vouchers:
return
item_account_wise_cost = {}
for lcv in landed_cost_vouchers:

View File

@ -523,12 +523,15 @@ def get_delivery_note_serial_no(item_code, qty, delivery_note):
return serial_nos
@frappe.whitelist()
def auto_fetch_serial_number(qty, item_code, warehouse, batch_no=None):
serial_numbers = frappe.get_list("Serial No", filters={
def auto_fetch_serial_number(qty, item_code, warehouse, batch_nos=None):
import json
filters = {
"item_code": item_code,
"warehouse": warehouse,
"batch_no": batch_no,
"delivery_document_no": "",
"sales_invoice": ""
}, limit=qty, order_by="creation")
}
if batch_nos: filters["batch_no"] = ["in", json.loads(batch_nos)]
serial_numbers = frappe.get_list("Serial No", filters=filters, limit=qty, order_by="creation")
return [item['name'] for item in serial_numbers]

View File

@ -60,7 +60,8 @@ frappe.ui.form.on('Stock Entry', {
}
}
if(item.s_warehouse) filters["warehouse"] = item.s_warehouse;
filters["warehouse"] = item.s_warehouse || item.t_warehouse;
return {
query : "erpnext.controllers.queries.get_batch_no",
filters: filters
@ -309,12 +310,12 @@ frappe.ui.form.on('Stock Entry', {
method: "erpnext.stock.get_item_details.get_serial_no",
args: {"args": args},
callback: function(r) {
if (!r.exe){
if (!r.exe && r.message){
frappe.model.set_value(cdt, cdn, "serial_no", r.message);
}
if (callback) {
callback();
if (callback) {
callback();
}
}
}
});
@ -622,10 +623,15 @@ frappe.ui.form.on('Stock Entry Detail', {
if(r.message) {
var d = locals[cdt][cdn];
$.each(r.message, function(k, v) {
frappe.model.set_value(cdt, cdn, k, v); // qty and it's subsequent fields weren't triggered
if (v) {
frappe.model.set_value(cdt, cdn, k, v); // qty and it's subsequent fields weren't triggered
}
});
refresh_field("items");
erpnext.stock.select_batch_and_serial_no(frm, d);
if (!d.serial_no) {
erpnext.stock.select_batch_and_serial_no(frm, d);
}
}
}
});
@ -964,7 +970,7 @@ erpnext.stock.select_batch_and_serial_no = (frm, item) => {
}
}
if(item && !item.has_serial_no && item.has_batch_no) return;
if(item && !item.has_serial_no && !item.has_batch_no) return;
if (frm.doc.purpose === 'Material Receipt') return;
frappe.require("assets/erpnext/js/utils/serial_no_batch_selector.js", function() {

View File

@ -177,6 +177,10 @@ class StockEntry(StockController):
stock_items = self.get_stock_items()
serialized_items = self.get_serialized_items()
for item in self.get("items"):
if item.qty and item.qty < 0:
frappe.throw(_("Row {0}: The item {1}, quantity must be positive number")
.format(item.idx, frappe.bold(item.item_code)))
if item.item_code not in stock_items:
frappe.throw(_("{0} is not a stock Item").format(item.item_code))
@ -234,7 +238,7 @@ class StockEntry(StockController):
if self.purpose == "Manufacture" and self.work_order:
production_item = frappe.get_value('Work Order', self.work_order, 'production_item')
for item in self.items:
if item.item_code == production_item and item.qty != self.fg_completed_qty:
if item.item_code == production_item and item.t_warehouse and item.qty != self.fg_completed_qty:
frappe.throw(_("Finished product quantity <b>{0}</b> and For Quantity <b>{1}</b> cannot be different")
.format(item.qty, self.fg_completed_qty))
@ -294,13 +298,8 @@ class StockEntry(StockController):
if validate_for_manufacture:
if d.bom_no:
d.s_warehouse = None
if not d.t_warehouse:
frappe.throw(_("Target warehouse is mandatory for row {0}").format(d.idx))
elif self.pro_doc and (cstr(d.t_warehouse) != self.pro_doc.fg_warehouse and cstr(d.t_warehouse) != self.pro_doc.scrap_warehouse):
frappe.throw(_("Target warehouse in row {0} must be same as Work Order").format(d.idx))
else:
d.t_warehouse = None
if not d.s_warehouse:

View File

@ -1,4 +1,5 @@
{
"actions": [],
"autoname": "hash",
"creation": "2013-03-29 18:22:12",
"doctype": "DocType",
@ -479,8 +480,7 @@
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
"options": "Project",
"read_only": 1
"options": "Project"
},
{
"fieldname": "po_detail",
@ -494,7 +494,8 @@
],
"idx": 1,
"istable": 1,
"modified": "2019-08-20 14:01:02.319754",
"links": [],
"modified": "2020-03-19 12:34:09.836295",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Entry Detail",

View File

@ -240,26 +240,13 @@ def get_basic_details(args, item, overwrite_warehouse=True):
item_group_defaults = get_item_group_defaults(item.name, args.company)
brand_defaults = get_brand_defaults(item.name, args.company)
if overwrite_warehouse or not args.warehouse:
warehouse = (
args.get("set_warehouse") or
item_defaults.get("default_warehouse") or
item_group_defaults.get("default_warehouse") or
brand_defaults.get("default_warehouse") or
args.warehouse
)
if not warehouse:
defaults = frappe.defaults.get_defaults() or {}
warehouse_exists = frappe.db.exists("Warehouse", {
'name': defaults.default_warehouse,
'company': args.company
})
if defaults.get("default_warehouse") and warehouse_exists:
warehouse = defaults.default_warehouse
else:
warehouse = args.warehouse
defaults = frappe._dict({
'item_defaults': item_defaults,
'item_group_defaults': item_group_defaults,
'brand_defaults': brand_defaults
})
warehouse = get_item_warehouse(item, args, overwrite_warehouse, defaults)
if args.get('doctype') == "Material Request" and not args.get('material_request_type'):
args['material_request_type'] = frappe.db.get_value('Material Request',
@ -272,7 +259,7 @@ def get_basic_details(args, item, overwrite_warehouse=True):
expense_account = get_asset_category_account(fieldname = "fixed_asset_account", item = args.item_code, company= args.company)
#Set the UOM to the Default Sales UOM or Default Purchase UOM if configured in the Item Master
if not args.uom:
if not args.get('uom'):
if args.get('doctype') in sales_doctypes:
args.uom = item.sales_uom if item.sales_uom else item.stock_uom
elif (args.get('doctype') in ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice']) or \
@ -362,6 +349,37 @@ def get_basic_details(args, item, overwrite_warehouse=True):
return out
def get_item_warehouse(item, args, overwrite_warehouse, defaults={}):
if not defaults:
defaults = frappe._dict({
'item_defaults' : get_item_defaults(item.name, args.company),
'item_group_defaults' : get_item_group_defaults(item.name, args.company),
'brand_defaults' : get_brand_defaults(item.name, args.company)
})
if overwrite_warehouse or not args.warehouse:
warehouse = (
args.get("set_warehouse") or
defaults.item_defaults.get("default_warehouse") or
defaults.item_group_defaults.get("default_warehouse") or
defaults.brand_defaults.get("default_warehouse") or
args.get('warehouse')
)
if not warehouse:
defaults = frappe.defaults.get_defaults() or {}
warehouse_exists = frappe.db.exists("Warehouse", {
'name': defaults.default_warehouse,
'company': args.company
})
if defaults.get("default_warehouse") and warehouse_exists:
warehouse = defaults.default_warehouse
else:
warehouse = args.get('warehouse')
return warehouse
def update_barcode_value(out):
from erpnext.accounts.doctype.sales_invoice.pos import get_barcode_data
barcode_data = get_barcode_data([out])

View File

@ -29,7 +29,13 @@ frappe.query_reports["Stock Ledger"] = {
"fieldname":"warehouse",
"label": __("Warehouse"),
"fieldtype": "Link",
"options": "Warehouse"
"options": "Warehouse",
"get_query": function() {
const company = frappe.query_report.get_filter_value('company');
return {
filters: { 'company': company }
}
}
},
{
"fieldname":"item_code",

View File

@ -428,7 +428,7 @@ class update_entries_after(object):
frappe.get_desk_link(self.exceptions[0]["voucher_type"], self.exceptions[0]["voucher_no"]))
if self.verbose:
frappe.throw(msg, NegativeStockError, title='Insufficent Stock')
frappe.throw(msg, NegativeStockError, title='Insufficient Stock')
else:
raise NegativeStockError(msg)

View File

@ -18,7 +18,7 @@
"is_standard": 1,
"login_required": 1,
"max_attachment_size": 0,
"modified": "2019-12-10 13:48:19.894186",
"modified": "2020-03-06 05:24:05.749664",
"modified_by": "Administrator",
"module": "Support",
"name": "issues",
@ -58,7 +58,7 @@
"options": "Open\nReplied\nHold\nClosed",
"read_only": 1,
"reqd": 0,
"show_in_filter": 0
"show_in_filter": 1
},
{
"allow_read_on_all_link_options": 0,

View File

@ -7,6 +7,8 @@ import frappe
def create_test_contact_and_address():
frappe.db.sql('delete from tabContact')
frappe.db.sql('delete from `tabContact Email`')
frappe.db.sql('delete from `tabContact Phone`')
frappe.db.sql('delete from tabAddress')
frappe.db.sql('delete from `tabDynamic Link`')

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
import frappe.share
from frappe import _
from frappe.utils import cstr, now_datetime, cint, flt, get_time
from frappe.utils import cstr, now_datetime, cint, flt, get_time, get_link_to_form
from erpnext.controllers.status_updater import StatusUpdater
from six import string_types
@ -123,8 +123,11 @@ class TransactionBase(StatusUpdater):
ref_rate = frappe.db.get_value(ref_dt + " Item", d.get(ref_link_field), "rate")
if abs(flt(d.rate - ref_rate, d.precision("rate"))) >= .01:
frappe.throw(_("Row #{0}: Rate must be same as {1}: {2} ({3} / {4}) ")
frappe.msgprint(_("Row #{0}: Rate must be same as {1}: {2} ({3} / {4}) ")
.format(d.idx, ref_dt, d.get(ref_dn_field), d.rate, ref_rate))
frappe.throw(_("To allow different rates, disable the {0} checkbox in {1}.")
.format(frappe.bold("Maintain Same Rate Throughout Sales Cycle"),
get_link_to_form("Selling Settings", "Selling Settings", frappe.bold("Selling Settings"))))
def get_link_filters(self, for_doctype):
if hasattr(self, "prev_link_mapper") and self.prev_link_mapper.get(for_doctype):

View File

@ -63,7 +63,7 @@
</a>
</div>
<div>
<h1>{{ content.name }} <span class="small text-muted">({{ position + 1 }}/{{length}})</span></h1>
<h2>{{ content.name }} <span class="small text-muted">({{ position + 1 }}/{{length}})</span></h2>
</div>
{% endmacro %}