From 1906f6da3aedeaf4e199308bda29f6589b5d7f54 Mon Sep 17 00:00:00 2001 From: Jay Parikh Date: Fri, 8 Feb 2019 11:13:09 +0000 Subject: [PATCH 1/8] Fix - POS >> Item listing after submit pos >> list all the items which are not restricted to that pos profile #16588 --- erpnext/selling/page/point_of_sale/point_of_sale.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.js b/erpnext/selling/page/point_of_sale/point_of_sale.js index 8b4d684466..c54430fd56 100644 --- a/erpnext/selling/page/point_of_sale/point_of_sale.js +++ b/erpnext/selling/page/point_of_sale/point_of_sale.js @@ -166,7 +166,7 @@ erpnext.pos.PointOfSale = class PointOfSale { }); frappe.ui.form.on('Sales Invoice', 'selling_price_list', (frm) => { - if(this.items) { + if(this.items && frm.doc.pos_profile) { this.items.reset_items(); } }) From 99e736200679cdf10f26a047ee64c6a266fbe025 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 18 Feb 2019 18:26:50 +0530 Subject: [PATCH 2/8] fix: Allow to make material request from draft job card --- erpnext/manufacturing/doctype/job_card/job_card.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py index 5ed03be545..ea9f714fc8 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.py +++ b/erpnext/manufacturing/doctype/job_card/job_card.py @@ -172,9 +172,6 @@ def make_material_request(source_name, target_doc=None): doclist = get_mapped_doc("Job Card", source_name, { "Job Card": { "doctype": "Material Request", - "validation": { - "docstatus": ["=", 1] - }, "field_map": { "name": "job_card", }, @@ -206,9 +203,6 @@ def make_stock_entry(source_name, target_doc=None): doclist = get_mapped_doc("Job Card", source_name, { "Job Card": { "doctype": "Stock Entry", - "validation": { - "docstatus": ["=", 1] - }, "field_map": { "name": "job_card", "for_quantity": "fg_completed_qty" From 750fe6eaea0a9b3da7ac01b7da97e4baddffd2ea Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 18 Feb 2019 18:55:53 +0530 Subject: [PATCH 3/8] fix: get item rate in bom --- erpnext/manufacturing/doctype/bom/bom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index ba3b7192a3..88d346ff0f 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -183,7 +183,7 @@ class BOM(WebsiteGenerator): args = frappe._dict({ "doctype": "BOM", "price_list": self.buying_price_list, - "qty": arg.get("qty"), + "qty": arg.get("qty") or 1, "uom": arg.get("uom") or arg.get("stock_uom"), "stock_uom": arg.get("stock_uom"), "transaction_type": "buying", From 5821b672adbdd20e91a641f635fcc027f6ce2415 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 18 Feb 2019 20:07:44 +0530 Subject: [PATCH 4/8] fix: multi-uom not working for the pricing rule rate --- erpnext/accounts/doctype/pricing_rule/pricing_rule.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index fe99763a35..ac0cd7e895 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -196,8 +196,9 @@ def get_pricing_rule_for_item(args): pricing_rule_rate = 0.0 if pricing_rule.currency == args.currency: pricing_rule_rate = pricing_rule.rate + item_details.update({ - "price_list_rate": pricing_rule_rate, + "price_list_rate": pricing_rule_rate * args.get("conversion_factor"), "discount_percentage": 0.0 }) else: From de0f59b818142e55435c12e87f83804651425e34 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Tue, 19 Feb 2019 08:40:16 +0530 Subject: [PATCH 5/8] fix: Removed precision from multiple doctypes --- .../cashier_closing/cashier_closing.json | 37 +++++++++++++---- .../cashier_closing_payments.json | 12 ++++-- .../journal_entry_account.json | 5 ++- .../payment_request/payment_request.json | 5 ++- .../purchase_invoice_item.json | 8 ++-- .../doctype/sales_invoice/sales_invoice.json | 4 +- .../sales_invoice_item.json | 6 +-- .../sales_invoice_timesheet.json | 23 +++++++++-- .../supplier_quotation_item.json | 4 +- .../hr/doctype/salary_slip/salary_slip.json | 10 ++--- .../salary_slip_timesheet.json | 27 ++++++++++-- .../salary_structure/salary_structure.json | 5 ++- .../timesheet_detail/timesheet_detail.json | 41 ++++++++++++++++--- .../quotation_item/quotation_item.json | 4 +- .../sales_order_item/sales_order_item.json | 4 +- .../delivery_note_item.json | 6 +-- 16 files changed, 149 insertions(+), 52 deletions(-) diff --git a/erpnext/accounts/doctype/cashier_closing/cashier_closing.json b/erpnext/accounts/doctype/cashier_closing/cashier_closing.json index 57a9c7aadd..14e9070f30 100644 --- a/erpnext/accounts/doctype/cashier_closing/cashier_closing.json +++ b/erpnext/accounts/doctype/cashier_closing/cashier_closing.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -15,6 +16,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -32,7 +34,7 @@ "label": "Series", "length": 0, "no_copy": 0, - "options": "Cashier-closing-\n", + "options": "Cashier-closing-", "permlevel": 0, "precision": "", "print_hide": 0, @@ -43,10 +45,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -74,10 +78,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -105,10 +111,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -135,10 +143,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -166,10 +176,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -188,7 +200,7 @@ "length": 0, "no_copy": 0, "permlevel": 0, - "precision": "2", + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -197,10 +209,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -219,7 +233,7 @@ "length": 0, "no_copy": 0, "permlevel": 0, - "precision": "2", + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -228,10 +242,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -250,7 +266,7 @@ "length": 0, "no_copy": 0, "permlevel": 0, - "precision": "2", + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, @@ -259,10 +275,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -291,10 +309,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -321,10 +341,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -351,6 +373,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -364,7 +387,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-09-03 10:59:54.500567", + "modified": "2019-02-19 08:35:23.157327", "modified_by": "Administrator", "module": "Accounts", "name": "Cashier Closing", @@ -373,7 +396,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -399,5 +421,6 @@ "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/cashier_closing_payments/cashier_closing_payments.json b/erpnext/accounts/doctype/cashier_closing_payments/cashier_closing_payments.json index bdfc70f8b1..7f16beafc3 100644 --- a/erpnext/accounts/doctype/cashier_closing_payments/cashier_closing_payments.json +++ b/erpnext/accounts/doctype/cashier_closing_payments/cashier_closing_payments.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -14,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,10 +43,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -63,7 +67,7 @@ "length": 0, "no_copy": 0, "permlevel": 0, - "precision": "2", + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -72,6 +76,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -85,7 +90,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-09-02 14:45:36.303520", + "modified": "2019-02-19 08:34:20.268037", "modified_by": "Administrator", "module": "Accounts", "name": "Cashier Closing Payments", @@ -99,5 +104,6 @@ "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json index 5a827bea81..32e49dbde4 100644 --- a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json +++ b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -398,7 +399,7 @@ "length": 0, "no_copy": 0, "permlevel": 0, - "precision": "6", + "precision": "9", "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, @@ -911,7 +912,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-08-19 04:08:44.742510", + "modified": "2019-02-18 19:00:53.662788", "modified_by": "Administrator", "module": "Accounts", "name": "Journal Entry Account", diff --git a/erpnext/accounts/doctype/payment_request/payment_request.json b/erpnext/accounts/doctype/payment_request/payment_request.json index 76fe884165..bff995ec5a 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.json +++ b/erpnext/accounts/doctype/payment_request/payment_request.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -425,7 +426,7 @@ "no_copy": 0, "options": "currency", "permlevel": 0, - "precision": "2", + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -1501,7 +1502,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-09-06 14:44:43.563367", + "modified": "2019-02-18 18:52:34.203239", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Request", diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json index c2309b264a..9e1d4bb916 100644 --- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json +++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json @@ -293,7 +293,7 @@ "length": 0, "no_copy": 0, "permlevel": 0, - "precision": "2", + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -321,7 +321,7 @@ "in_global_search": 0, "in_list_view": 1, "in_standard_filter": 0, - "label": "Qty", + "label": "Accepted Qty", "length": 0, "no_copy": 0, "oldfieldname": "qty", @@ -358,7 +358,7 @@ "length": 0, "no_copy": 0, "permlevel": 0, - "precision": "2", + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -2626,7 +2626,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2019-01-07 16:52:00.749414", + "modified": "2019-02-18 19:03:19.250250", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice Item", diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index 13ba053bae..077d99512a 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -1966,7 +1966,7 @@ "length": 0, "no_copy": 0, "permlevel": 0, - "precision": "2", + "precision": "", "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, @@ -5644,7 +5644,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2019-01-07 16:51:53.914523", + "modified": "2019-02-18 18:56:51.265257", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice", diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index d6ce11536e..a95f314661 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -779,7 +779,7 @@ "no_copy": 0, "options": "currency", "permlevel": 0, - "precision": "2", + "precision": "", "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, @@ -913,7 +913,7 @@ "no_copy": 0, "options": "Company:company:default_currency", "permlevel": 0, - "precision": "2", + "precision": "", "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, @@ -2766,7 +2766,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2019-01-07 16:51:55.018091", + "modified": "2019-02-18 18:59:52.223628", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", diff --git a/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json b/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json index 50eed241d4..f7b9aef96c 100644 --- a/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json +++ b/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json @@ -1,5 +1,7 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, + "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, "beta": 0, @@ -12,6 +14,8 @@ "engine": "InnoDB", "fields": [ { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -39,9 +43,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -68,9 +75,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -88,7 +98,7 @@ "length": 0, "no_copy": 0, "permlevel": 0, - "precision": "2", + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, @@ -97,9 +107,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 1, "bold": 0, "collapsible": 0, @@ -126,20 +139,21 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], + "has_web_view": 0, "hide_heading": 0, "hide_toolbar": 0, "idx": 0, "image_view": 0, "in_create": 0, - "is_submittable": 0, "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-02-17 16:47:04.413420", + "modified": "2019-02-18 18:50:44.770361", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Timesheet", @@ -153,5 +167,6 @@ "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json index 94d93f6a61..3c775cd6d9 100644 --- a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json +++ b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json @@ -848,7 +848,7 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "permlevel": 0, - "precision": "2", + "precision": "", "print_hide": 1, "print_hide_if_no_value": 0, "print_width": "100px", @@ -1786,7 +1786,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2019-01-07 16:52:02.125715", + "modified": "2019-02-18 18:58:10.351451", "modified_by": "Administrator", "module": "Buying", "name": "Supplier Quotation Item", diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.json b/erpnext/hr/doctype/salary_slip/salary_slip.json index 76e43d6ea7..c9a5d87281 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.json +++ b/erpnext/hr/doctype/salary_slip/salary_slip.json @@ -195,7 +195,7 @@ "columns": 0, "fetch_from": "employee.branch", "fieldname": "branch", - "fieldtype": "Link", + "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -208,11 +208,11 @@ "no_copy": 0, "oldfieldname": "branch", "oldfieldtype": "Link", - "options": "Branch", + "options": "Branch", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 1, + "read_only": 1, "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, @@ -901,7 +901,7 @@ "no_copy": 0, "options": "Company:company:default_currency", "permlevel": 0, - "precision": "2", + "precision": "", "print_hide": 0, "print_hide_if_no_value": 1, "read_only": 0, @@ -1906,7 +1906,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2019-02-12 11:24:20.848207", + "modified": "2019-02-18 18:54:36.161027", "modified_by": "Administrator", "module": "HR", "name": "Salary Slip", diff --git a/erpnext/hr/doctype/salary_slip_timesheet/salary_slip_timesheet.json b/erpnext/hr/doctype/salary_slip_timesheet/salary_slip_timesheet.json index 7a9393c332..797f8f7c02 100644 --- a/erpnext/hr/doctype/salary_slip_timesheet/salary_slip_timesheet.json +++ b/erpnext/hr/doctype/salary_slip_timesheet/salary_slip_timesheet.json @@ -1,5 +1,7 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, + "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, "beta": 0, @@ -11,16 +13,21 @@ "editable_grid": 1, "fields": [ { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "time_sheet", "fieldtype": "Link", "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": "Time Sheet", "length": 0, "no_copy": 0, @@ -30,49 +37,58 @@ "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, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "working_hours", "fieldtype": "Float", "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": "Working Hours", "length": 0, "no_copy": 1, "permlevel": 0, - "precision": "3", + "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 } ], + "has_web_view": 0, "hide_heading": 0, "hide_toolbar": 0, "idx": 0, "image_view": 0, "in_create": 0, - "is_submittable": 0, "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2016-07-11 03:28:07.152366", + "modified": "2019-02-19 08:33:41.762144", "modified_by": "Administrator", "module": "HR", "name": "Salary Slip Timesheet", @@ -82,7 +98,10 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", - "track_seen": 0 + "track_changes": 0, + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.json b/erpnext/hr/doctype/salary_structure/salary_structure.json index ce8b64eb4d..0e47278a3e 100644 --- a/erpnext/hr/doctype/salary_structure/salary_structure.json +++ b/erpnext/hr/doctype/salary_structure/salary_structure.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 1, @@ -365,7 +366,7 @@ "no_copy": 0, "options": "Company:company:default_currency", "permlevel": 0, - "precision": "2", + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -950,7 +951,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-07-24 18:36:25.169098", + "modified": "2019-02-18 18:51:53.932518", "modified_by": "Administrator", "module": "HR", "name": "Salary Structure", diff --git a/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json b/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json index b1f737296d..a9b3bfb06f 100644 --- a/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json +++ b/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -13,6 +14,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -44,6 +46,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -75,6 +78,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -105,6 +109,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -136,6 +141,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -166,6 +172,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -197,6 +204,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -230,6 +238,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -260,6 +269,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -278,7 +288,7 @@ "length": 0, "no_copy": 0, "permlevel": 0, - "precision": "2", + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -292,6 +302,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -325,6 +336,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -355,6 +367,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -388,6 +401,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -420,6 +434,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -450,6 +465,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -482,6 +498,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -512,6 +529,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -545,6 +563,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -575,6 +594,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 1, "bold": 0, "collapsible": 0, @@ -607,6 +627,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -637,6 +658,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 1, "bold": 0, "collapsible": 0, @@ -669,6 +691,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -700,6 +723,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -718,7 +742,7 @@ "length": 0, "no_copy": 0, "permlevel": 1, - "precision": "2", + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -732,6 +756,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 1, "bold": 0, "collapsible": 0, @@ -752,7 +777,7 @@ "length": 0, "no_copy": 0, "permlevel": 1, - "precision": "2", + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, @@ -766,6 +791,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -796,6 +822,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -827,6 +854,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 1, "bold": 0, "collapsible": 0, @@ -860,6 +888,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -891,6 +920,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 1, "bold": 0, "collapsible": 0, @@ -932,7 +962,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-05-07 15:12:31.510813", + "modified": "2019-02-18 18:55:53.190526", "modified_by": "Administrator", "module": "Projects", "name": "Timesheet Detail", @@ -944,5 +974,6 @@ "show_name_in_global_search": 0, "sort_order": "ASC", "track_changes": 0, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json index 3a8b0df5c5..24cb405657 100644 --- a/erpnext/selling/doctype/quotation_item/quotation_item.json +++ b/erpnext/selling/doctype/quotation_item/quotation_item.json @@ -762,7 +762,7 @@ "no_copy": 0, "options": "currency", "permlevel": 0, - "precision": "2", + "precision": "", "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, @@ -1914,7 +1914,7 @@ "istable": 1, "max_attachments": 0, "menu_index": 0, - "modified": "2019-01-07 16:51:56.248107", + "modified": "2019-02-18 18:57:25.277633", "modified_by": "Administrator", "module": "Selling", "name": "Quotation Item", diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index 19065dfa37..5ca2f81864 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -961,7 +961,7 @@ "no_copy": 0, "options": "Company:company:default_currency", "permlevel": 0, - "precision": "2", + "precision": "", "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, @@ -2477,7 +2477,7 @@ "istable": 1, "max_attachments": 0, "menu_index": 0, - "modified": "2019-01-07 16:51:51.852343", + "modified": "2019-02-18 18:53:23.425126", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json index 9fe741a11e..1e73d68fef 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -793,7 +793,7 @@ "no_copy": 0, "options": "currency", "permlevel": 0, - "precision": "2", + "precision": "", "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, @@ -928,7 +928,7 @@ "no_copy": 0, "options": "Company:company:default_currency", "permlevel": 0, - "precision": "2", + "precision": "", "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, @@ -2310,7 +2310,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2019-01-07 16:51:53.322875", + "modified": "2019-02-18 18:58:51.342901", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", From a4aa80fe0538830516576e2c116bdb900a938b78 Mon Sep 17 00:00:00 2001 From: Gaurav Date: Sun, 6 Jan 2019 12:40:28 +0530 Subject: [PATCH 6/8] feature(regional): Italian Localization Added setup.py for italy under regional Included fiscal regimes, tax exemption reasons and custom fields Issue #16259 --- erpnext/regional/italy/__init__.py | 32 ++++++++++++++++++++++++++ erpnext/regional/italy/setup.py | 37 ++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 erpnext/regional/italy/__init__.py create mode 100644 erpnext/regional/italy/setup.py diff --git a/erpnext/regional/italy/__init__.py b/erpnext/regional/italy/__init__.py new file mode 100644 index 0000000000..d7dbddce95 --- /dev/null +++ b/erpnext/regional/italy/__init__.py @@ -0,0 +1,32 @@ +# coding=utf-8 + +fiscal_regimes = [ + "RF01-Ordinario", + "RF02-Contribuenti minimi (art.1, c.96-117, L. 244/07)", + "RF04-Agricoltura e attività connesse e pesca (artt.34 e 34-bis, DPR 633/72)", + "RF05-Vendita sali e tabacchi (art.74, c.1, DPR. 633/72)", + "RF06-Commercio fiammiferi (art.74, c.1, DPR 633/72)", + "RF07-Editoria (art.74, c.1, DPR 633/72)", + "RF08-Gestione servizi telefonia pubblica (art.74, c.1, DPR 633/72)", + "RF09-Rivendita documenti di trasporto pubblico e di sosta (art.74, c.1, DPR 633/72)", + "RF10-Intrattenimenti, giochi e altre attività di cui alla tariffa allegata al DPR 640/72 (art.74, c.6, DPR 633/72)", + "RF11-Agenzie viaggi e turismo (art.74-ter, DPR 633/72)", + "RF12-Agriturismo (art.5, c.2, L. 413/91)", + "RF13-Vendite a domicilio (art.25-bis, c.6, DPR 600/73)", + "RF14-Rivendita beni usati, oggetti d’arte, d’antiquariato o da collezione (art.36, DL 41/95)", + "RF15-Agenzie di vendite all’asta di oggetti d’arte, antiquariato o da collezione (art.40-bis, DL 41/95)", + "RF16-IVA per cassa P.A. (art.6, c.5, DPR 633/72)", + "RF17-IVA per cassa (art. 32-bis, DL 83/2012)", + "RF18-Altro", + "RF19-Regime forfettario (art.1, c.54-89, L. 190/2014)" +] + +tax_exemption_reasons = [ + "N1-Escluse ex art. 15", + "N2-Non Soggette", + "N3-Non Imponibili", + "N4-Esenti", + "N5-Regime del margine / IVA non esposta in fattura", + "N6-Inversione Contabile", + "N7-IVA assolta in altro stato UE" +] diff --git a/erpnext/regional/italy/setup.py b/erpnext/regional/italy/setup.py new file mode 100644 index 0000000000..1931fdc581 --- /dev/null +++ b/erpnext/regional/italy/setup.py @@ -0,0 +1,37 @@ +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt +# coding=utf-8 + +from __future__ import unicode_literals + +import frappe +from frappe.custom.doctype.custom_field.custom_field import create_custom_fields +from erpnext.regional.italy import fiscal_regimes, tax_exemption_reasons + +def setup(company=None, patch=True): + make_custom_fields() + +def make_custom_fields(update=True): + fiscal_code_field = dict(fieldname='fiscal_code', label='Fiscal Code', fieldtype='Data', insert_after='tax_id', print_hide=1) + custom_fields = { + 'Company': [ + fiscal_code_field, + dict(fieldname='fiscal_regime', label='Fiscal Regime', + fieldtype='Select', insert_after='fiscal_code', print_hide=1, + options="\n".join(map(lambda x: x.decode('utf-8'), fiscal_regimes))) + ], + 'Customer': [ + fiscal_code_field, + dict(fieldname='recipient_code', label='Recipient Code', + fieldtype='Data', insert_after='fiscal_code', print_hide=1, default="0000000"), + dict(fieldname='pec', label='Recipient PEC', + fieldtype='Data', insert_after='fiscal_code', print_hide=1) + ], + 'Sales Taxes and Charges': [ + dict(fieldname='tax_exemption_reason', label='Tax Exemption Reason', + fieldtype='Select', insert_after='included_in_print_rate', print_hide=1, + options="\n".join(map(lambda x: x.decode('utf-8'), tax_exemption_reasons))) + ] + } + + create_custom_fields(custom_fields, ignore_validate = frappe.flags.in_patch, update=update) From f1e28e0e8dea00f92832022279cad20b5f0392ee Mon Sep 17 00:00:00 2001 From: Gaurav Date: Wed, 13 Feb 2019 16:46:24 +0530 Subject: [PATCH 7/8] mod(regional,italy): Updates to Italian Localization fixes: removed cleanup_files from italy/utils removed extract_doc_number from italy/utils added country filter to italian localization patch replaced dict assignment with dot operator in prepare_invoice correcions in e-invoice xml following changes in prepare_invoice added setup_report in patch added section for e-invoicing custom fields in company added Italy in test_company --- .../doctype/sales_invoice/sales_invoice.py | 5 + erpnext/controllers/accounts_controller.py | 14 + erpnext/hooks.py | 6 + erpnext/patches.txt | 3 +- .../v11_0/make_italian_localization_fields.py | 14 + erpnext/regional/italy/__init__.py | 31 +++ erpnext/regional/italy/e-invoice.xml | 208 +++++++++++++++ erpnext/regional/italy/setup.py | 147 +++++++++- erpnext/regional/italy/utils.py | 251 ++++++++++++++++++ .../electronic_invoice_register/__init__.py | 0 .../electronic_invoice_register.js | 53 ++++ .../electronic_invoice_register.json | 21 ++ .../electronic_invoice_register.py | 8 + erpnext/setup/doctype/company/test_company.py | 2 +- 14 files changed, 747 insertions(+), 16 deletions(-) create mode 100644 erpnext/patches/v11_0/make_italian_localization_fields.py create mode 100644 erpnext/regional/italy/e-invoice.xml create mode 100644 erpnext/regional/italy/utils.py create mode 100644 erpnext/regional/report/electronic_invoice_register/__init__.py create mode 100644 erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.js create mode 100644 erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.json create mode 100644 erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.py diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 895ca07da2..abd201f5c7 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -24,6 +24,7 @@ from erpnext.accounts.general_ledger import get_round_off_account_and_cost_cente from erpnext.accounts.doctype.loyalty_program.loyalty_program import \ get_loyalty_program_details_with_points, get_loyalty_details, validate_loyalty_points from erpnext.accounts.deferred_revenue import validate_service_stop_date +from erpnext.controllers.accounts_controller import on_submit_regional, on_cancel_regional from erpnext.healthcare.utils import manage_invoice_submit_cancel @@ -198,6 +199,8 @@ class SalesInvoice(SellingController): if "Healthcare" in active_domains: manage_invoice_submit_cancel(self, "on_submit") + on_submit_regional(self) + def validate_pos_paid_amount(self): if len(self.payments) == 0 and self.is_pos: frappe.throw(_("At least one mode of payment is required for POS invoice.")) @@ -253,6 +256,8 @@ class SalesInvoice(SellingController): if "Healthcare" in active_domains: manage_invoice_submit_cancel(self, "on_cancel") + on_cancel_regional(self) + def update_status_updater_args(self): if cint(self.update_stock): self.status_updater.extend([{ diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 0ba47edfc1..5a765aa273 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -94,6 +94,8 @@ class AccountsController(TransactionBase): if self.is_return: self.validate_qty() + validate_regional(self) + def validate_invoice_documents_schedule(self): self.validate_payment_schedule_dates() self.set_due_date() @@ -1132,3 +1134,15 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name): p_doctype.update_blanket_order() p_doctype.update_billing_percentage() p_doctype.set_status() + +@erpnext.allow_regional +def validate_regional(doc): + pass + +@erpnext.allow_regional +def on_submit_regional(doc): + pass + +@erpnext.allow_regional +def on_cancel_regional(doc): + pass diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 7d77f90afa..2a871f0bc6 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -301,5 +301,11 @@ regional_overrides = { }, 'Saudi Arabia': { 'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data' + }, + 'Italy': { + 'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.italy.utils.update_itemised_tax_data', + 'erpnext.controllers.accounts_controller.validate_regional': 'erpnext.regional.italy.utils.sales_invoice_validate', + 'erpnext.controllers.accounts_controller.on_submit_regional': 'erpnext.regional.italy.utils.sales_invoice_on_submit', + 'erpnext.controllers.accounts_controller.on_cancel_regional': 'erpnext.regional.italy.utils.sales_invoice_on_cancel' } } diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 2199491a71..45ee8dc2d7 100755 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -585,4 +585,5 @@ erpnext.patches.v11_0.renamed_from_to_fields_in_project erpnext.patches.v11_0.add_permissions_in_gst_settings erpnext.patches.v11_1.setup_guardian_role execute:frappe.delete_doc('DocType', 'Notification Control') -erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019 \ No newline at end of file +erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019 +erpnext.patches.v11_0.make_italian_localization_fields diff --git a/erpnext/patches/v11_0/make_italian_localization_fields.py b/erpnext/patches/v11_0/make_italian_localization_fields.py new file mode 100644 index 0000000000..b0b5ef159b --- /dev/null +++ b/erpnext/patches/v11_0/make_italian_localization_fields.py @@ -0,0 +1,14 @@ +# Copyright (c) 2017, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +from erpnext.regional.italy.setup import make_custom_fields, setup_report +import frappe + +def execute(): + company = frappe.get_all('Company', filters = {'country': 'Italy'}) + if not company: + return + + make_custom_fields() + setup_report() diff --git a/erpnext/regional/italy/__init__.py b/erpnext/regional/italy/__init__.py index d7dbddce95..22bf84e4d0 100644 --- a/erpnext/regional/italy/__init__.py +++ b/erpnext/regional/italy/__init__.py @@ -30,3 +30,34 @@ tax_exemption_reasons = [ "N6-Inversione Contabile", "N7-IVA assolta in altro stato UE" ] + +mode_of_payment_codes = [ + "MP01-Contanti", + "MP02-Assegno", + "MP03-Assegno circolare", + "MP04-Contanti presso Tesoreria", + "MP05-Bonifico", + "MP06-Vaglia cambiario", + "MP07-Bollettino bancario", + "MP08-Carta di pagamento", + "MP09-RID", + "MP10-RID utenze", + "MP11-RID veloce", + "MP12-RIBA", + "MP13-MAV", + "MP14-Quietanza erario", + "MP15-Giroconto su conti di contabilità speciale", + "MP16-Domiciliazione bancaria", + "MP17-Domiciliazione postale", + "MP18-Bollettino di c/c postale", + "MP19-SEPA Direct Debit", + "MP20-SEPA Direct Debit CORE", + "MP21-SEPA Direct Debit B2B", + "MP22-Trattenuta su somme già riscosse" +] + +vat_collectability_options = [ + "I-Immediata", + "D-Differita", + "S-Scissione dei Pagamenti" +] diff --git a/erpnext/regional/italy/e-invoice.xml b/erpnext/regional/italy/e-invoice.xml new file mode 100644 index 0000000000..84b7fffbbc --- /dev/null +++ b/erpnext/regional/italy/e-invoice.xml @@ -0,0 +1,208 @@ +{%- macro format_float(value) -%} +{{ "%.2f" % value|abs }} +{%- endmacro -%} + +{%- macro render_address(address) %} +{{ address.address_line1 }} +{{ address.pincode }} +{{ address.city }} +{%- if address.state %} +{{ address.state }} +{%- endif %} +{{ address.country_code|upper }} +{%- endmacro %} + +{%- macro render_discount_or_margin(item) -%} +{%- if item.discount_percentage > 0.0 or item.margin_type %} + + {%- if item.discount_percentage > 0.0 %} + SC + {{ format_float(item.discount_percentage) }} + {%- endif %} + {%- if item.margin_rate_or_amount > 0.0 -%} + MG + {%- if item.margin_type == "Percentage" -%} + {{ format_float(item.margin_rate_or_amount) }} + {%- elif item.margin_type == "Amount" -%} + {{ format_float(item.margin_rate_or_amount) }} + {%- endif -%} + {%- endif %} + +{%- endif -%} +{%- endmacro -%} + + + + + + + {{ doc.company_address_data.country_code|upper or "IT" }} + {{ doc.company_fiscal_code or doc.company_tax_id | replace("IT","") }} + + {{ doc.progressive_number }} + {{ doc.transmission_format_code }} + {{ doc.customer_data.recipient_code }} + {% if doc.company_data.phone or doc.company_data.email -%} + + {% if doc.company_data.phone -%}{{ doc.company_data.phone }}{%- endif %} + {% if doc.company_data.email -%}{{ doc.company_data.email }}{%- endif %} + + {% endif -%} + + + + + {{ doc.company_address_data.country_code|upper or "IT"}} + {{ doc.company_tax_id | replace("IT","") }} + + {%- if doc.company_fiscal_code %} + {{ doc.company_fiscal_code }} + {%- endif %} + + {{ doc.company }} + + {{ doc.company_fiscal_regime.split("-")[0] }} + + + {{ render_address(doc.company_address_data) }} + + {%- if doc.company_data.registration_number %} + + {{ doc.company_data.registrar_office_province }} + {{ doc.company_data.registration_number }} + {%- if doc.company_data.share_capital_amount %} + {{ format_float(doc.company_data.share_capital_amount) }} + {%- endif %} + {%- if doc.company_data.no_of_members %} + {{ doc.company_data.no_of_members.split("-")[0] }} + {%- endif %} + {%- if doc.company_data.liquidation_state %} + {{ doc.company_data.liquidation_state.split("-")[0] }} + {%- endif %} + + {%- endif %} + + + + {%- if doc.customer_data.customer_type == "Individual" %} + {{ doc.customer_data.fiscal_code }} + + {{ doc.customer_data.first_name }} + {{ doc.customer_data.last_name }} + + {%- else %} + {%- if doc.customer_data.is_public_administration %} + {{ doc.customer_data.fiscal_code }} + {%- else %} + + {{ doc.customer_address_data.country_code|upper or "IT" }} + {{ doc.tax_id | replace("IT","") }} + + {%- endif %} + + {{ doc.customer_name }} + + {%- endif %} + + {%- if doc.customer_address_data %} + + {{ render_address(doc.customer_address_data) }} + + {%- endif %} + + + + + + {{ doc.type_of_document }} + EUR + {{ doc.posting_date }} + {{ doc.unamended_name }} + {%- if doc.stamp_duty %} + + SI + {{ format_float(doc.stamp_duty) }} + + {%- endif %} + {{ format_float(doc.grand_total) }} + VENDITA + + {%- if doc.po_no %} + + {{ doc.po_no }} + {%- if doc.po_date %} + {{ doc.po_date }} + {%- endif %} + + {%- endif %} + {%- if doc.is_return and doc.return_against_unamended %} + + {{ doc.return_against_unamended }} + + {%- endif %} + {%- if doc.shipping_address_data %} + + + {{ render_address(doc.shipping_address_data) }} + + + {%- endif %} + + + {%- for item in doc.items %} + + {{ item.idx }} + + CODICE + {{ item.item_code }} + + {{ item.description or item.item_name }} + {{ format_float(item.qty) }} + {{ item.stock_uom }} + {{ format_float(item.price_list_rate or item.rate) }} + {{ render_discount_or_margin(item) }} + {{ format_float(item.amount) }} + {{ format_float(item.tax_rate) }} + {%- if item.tax_exemption_reason %} + {{ item.tax_exemption_reason.split("-")[0] }} + {%- endif %} + + {%- endfor %} + {%- for tax, data in doc.tax_data.items() %} + + {{ format_float(tax|flt) }} + {%- if data.tax_exemption_reason %} + {{ data.tax_exemption_reason.split("-")[0] }} + {%- endif %} + {{ format_float(data.taxable_amount) }} + {{ format_float(data.tax_amount) }} + {{ doc.vat_collectability.split("-")[0] }} + {%- if data.tax_exemption_law %} + {{ data.tax_exemption_law }} + {%- endif %} + + {%- endfor %} + + {%- if doc.payment_schedule %} + + {%- if payment_schedule|length > 1 %} + TP01 + {%- else %} + TP02 + {%- endif %} + {%- for payment_term in doc.payment_schedule %} + + {{ payment_term.mode_of_payment_code.split("-")[0] }} + {{ payment_term.due_date }} + {{ format_float(payment_term.payment_amount) }} + {%- if payment_term.bank_account_iban %}{{ payment_term.bank_account_iban }}{%- endif %} + + {%- endfor %} + + {%- endif %} + + diff --git a/erpnext/regional/italy/setup.py b/erpnext/regional/italy/setup.py index 1931fdc581..b4ab26f9c7 100644 --- a/erpnext/regional/italy/setup.py +++ b/erpnext/regional/italy/setup.py @@ -5,33 +5,152 @@ from __future__ import unicode_literals import frappe +from frappe import _ from frappe.custom.doctype.custom_field.custom_field import create_custom_fields -from erpnext.regional.italy import fiscal_regimes, tax_exemption_reasons +from erpnext.regional.italy import fiscal_regimes, tax_exemption_reasons, mode_of_payment_codes, vat_collectability_options def setup(company=None, patch=True): - make_custom_fields() + make_custom_fields() + setup_report() def make_custom_fields(update=True): - fiscal_code_field = dict(fieldname='fiscal_code', label='Fiscal Code', fieldtype='Data', insert_after='tax_id', print_hide=1) + invoice_item_fields = [ + dict(fieldname='tax_rate', label='Tax Rate', + fieldtype='Float', insert_after='description', + print_hide=1, hidden=1, read_only=1), + dict(fieldname='tax_amount', label='Tax Amount', + fieldtype='Currency', insert_after='tax_rate', + print_hide=1, hidden=1, read_only=1, options="currency"), + dict(fieldname='total_amount', label='Total Amount', + fieldtype='Currency', insert_after='tax_amount', + print_hide=1, hidden=1, read_only=1, options="currency") + ] + custom_fields = { 'Company': [ - fiscal_code_field, + dict(fieldname='sb_e_invoicing', label='E-Invoicing', + fieldtype='Section Break', insert_after='date_of_establishment', print_hide=1), dict(fieldname='fiscal_regime', label='Fiscal Regime', - fieldtype='Select', insert_after='fiscal_code', print_hide=1, - options="\n".join(map(lambda x: x.decode('utf-8'), fiscal_regimes))) - ], - 'Customer': [ - fiscal_code_field, - dict(fieldname='recipient_code', label='Recipient Code', - fieldtype='Data', insert_after='fiscal_code', print_hide=1, default="0000000"), - dict(fieldname='pec', label='Recipient PEC', - fieldtype='Data', insert_after='fiscal_code', print_hide=1) + fieldtype='Select', insert_after='sb_e_invoicing', print_hide=1, + options="\n".join(map(lambda x: x.decode('utf-8'), fiscal_regimes))), + dict(fieldname='fiscal_code', label='Fiscal Code', fieldtype='Data', insert_after='fiscal_regime', print_hide=1, + description=_("Applicable if the company is an Individual or a Proprietorship")), + dict(fieldname='vat_collectability', label='VAT Collectability', + fieldtype='Select', insert_after='fiscal_code', print_hide=1, + options="\n".join(map(lambda x: x.decode('utf-8'), vat_collectability_options))), + dict(fieldname='cb_e_invoicing1', fieldtype='Column Break', insert_after='vat_collectability', print_hide=1), + dict(fieldname='registrar_office_province', label='Province of the Registrar Office', + fieldtype='Data', insert_after='cb_e_invoicing1', print_hide=1, length=2), + dict(fieldname='registration_number', label='Registration Number', + fieldtype='Data', insert_after='registrar_office_province', print_hide=1, length=20), + dict(fieldname='share_capital_amount', label='Share Capital', + fieldtype='Currency', insert_after='registration_number', print_hide=1, + description=_('Applicable if the company is SpA, SApA or SRL')), + dict(fieldname='no_of_members', label='No of Members', + fieldtype='Select', insert_after='share_capital_amount', print_hide=1, + options="\nSU-Socio Unico\nSM-Piu Soci", description=_("Applicable if the company is a limited liability company")), + dict(fieldname='liquidation_state', label='Liquidation State', + fieldtype='Select', insert_after='no_of_members', print_hide=1, + options="\nLS-In Liquidazione\nLN-Non in Liquidazione") ], 'Sales Taxes and Charges': [ dict(fieldname='tax_exemption_reason', label='Tax Exemption Reason', + fieldtype='Select', insert_after='included_in_print_rate', print_hide=1, + depends_on='eval:doc.charge_type!="Actual" && doc.rate==0.0', + options="\n" + "\n".join(map(lambda x: x.decode('utf-8'), tax_exemption_reasons))), + dict(fieldname='tax_exemption_law', label='Tax Exempt Under', + fieldtype='Text', insert_after='tax_exemption_reason', print_hide=1, + depends_on='eval:doc.charge_type!="Actual" && doc.rate==0.0') + ], + 'Customer': [ + dict(fieldname='fiscal_code', label='Fiscal Code', fieldtype='Data', insert_after='tax_id', print_hide=1), + dict(fieldname='recipient_code', label='Recipient Code', + fieldtype='Data', insert_after='fiscal_code', print_hide=1, default="0000000"), + dict(fieldname='pec', label='Recipient PEC', + fieldtype='Data', insert_after='fiscal_code', print_hide=1), + dict(fieldname='is_public_administration', label='Is Public Administration', + fieldtype='Check', insert_after='is_internal_customer', print_hide=1, + description=_("Set this if the customer is a Public Administration company."), + depends_on='eval:doc.customer_type=="Company"'), + dict(fieldname='first_name', label='First Name', fieldtype='Data', + insert_after='salutation', print_hide=1, depends_on='eval:doc.customer_type!="Company"'), + dict(fieldname='last_name', label='Last Name', fieldtype='Data', + insert_after='first_name', print_hide=1, depends_on='eval:doc.customer_type!="Company"') + ], + 'Mode of Payment': [ + dict(fieldname='mode_of_payment_code', label='Code', fieldtype='Select', insert_after='included_in_print_rate', print_hide=1, - options="\n".join(map(lambda x: x.decode('utf-8'), tax_exemption_reasons))) + options="\n".join(map(lambda x: x.decode('utf-8'), mode_of_payment_codes))) + ], + 'Payment Schedule': [ + dict(fieldname='mode_of_payment_code', label='Code', + fieldtype='Select', insert_after='mode_of_payment', print_hide=1, + options="\n".join(map(lambda x: x.decode('utf-8'), mode_of_payment_codes)), + fetch_from="mode_of_payment.mode_of_payment_code", read_only=1), + dict(fieldname='bank_account', label='Bank Account', + fieldtype='Link', insert_after='mode_of_payment_code', print_hide=1, + options="Bank Account"), + dict(fieldname='bank_account_name', label='Bank Account Name', + fieldtype='Data', insert_after='bank_account', print_hide=1, + fetch_from="bank_account.account_name", read_only=1), + dict(fieldname='bank_account_no', label='Bank Account No', + fieldtype='Data', insert_after='bank_account_name', print_hide=1, + fetch_from="bank_account.bank_account_no", read_only=1), + dict(fieldname='bank_account_iban', label='IBAN', + fieldtype='Data', insert_after='bank_account_name', print_hide=1, + fetch_from="bank_account.iban", read_only=1), + ], + "Sales Invoice": [ + dict(fieldname='vat_collectability', label='VAT Collectability', + fieldtype='Select', insert_after='taxes_and_charges', print_hide=1, + options="\n".join(map(lambda x: x.decode('utf-8'), vat_collectability_options)), + fetch_from="company.vat_collectability"), + dict(fieldname='sb_e_invoicing_reference', label='E-Invoicing', + fieldtype='Section Break', insert_after='pos_total_qty', print_hide=1), + dict(fieldname='company_tax_id', label='Company Tax ID', + fieldtype='Data', insert_after='sb_e_invoicing_reference', print_hide=1, read_only=1, + fetch_from="company.tax_id"), + dict(fieldname='company_fiscal_code', label='Company Fiscal Code', + fieldtype='Data', insert_after='company_tax_id', print_hide=1, read_only=1, + fetch_from="company.fiscal_code"), + dict(fieldname='company_fiscal_regime', label='Company Fiscal Regime', + fieldtype='Data', insert_after='company_fiscal_code', print_hide=1, read_only=1, + fetch_from="company.fiscal_regime"), + dict(fieldname='cb_e_invoicing_reference', fieldtype='Column Break', + insert_after='company_fiscal_regime', print_hide=1), + dict(fieldname='customer_fiscal_code', label='Customer Fiscal Code', + fieldtype='Data', insert_after='cb_e_invoicing_reference', read_only=1, + fetch_from="customer.fiscal_code"), + ], + 'Purchase Invoice Item': invoice_item_fields, + 'Sales Order Item': invoice_item_fields, + 'Delivery Note Item': invoice_item_fields, + 'Sales Invoice Item': invoice_item_fields, + 'Quotation Item': invoice_item_fields, + 'Purchase Order Item': invoice_item_fields, + 'Purchase Receipt Item': invoice_item_fields, + 'Supplier Quotation Item': invoice_item_fields, + 'Address': [ + dict(fieldname='country_code', label='Country Code', + fieldtype='Data', insert_after='country', print_hide=1, read_only=1, + fetch_from="country.code") ] } create_custom_fields(custom_fields, ignore_validate = frappe.flags.in_patch, update=update) + +def setup_report(): + report_name = 'Electronic Invoice Register' + + frappe.db.sql(""" update `tabReport` set disabled = 0 where + name = %s """, report_name) + + if not frappe.db.get_value('Custom Role', dict(report=report_name)): + frappe.get_doc(dict( + doctype='Custom Role', + report=report_name, + roles= [ + dict(role='Accounts User'), + dict(role='Accounts Manager') + ] + )).insert() diff --git a/erpnext/regional/italy/utils.py b/erpnext/regional/italy/utils.py new file mode 100644 index 0000000000..69f7b464c9 --- /dev/null +++ b/erpnext/regional/italy/utils.py @@ -0,0 +1,251 @@ +import frappe, json, os +from frappe.utils import flt +from erpnext.controllers.taxes_and_totals import get_itemised_tax +from frappe import _ +from frappe.utils.file_manager import save_file, remove_file +from frappe.desk.form.load import get_attachments + + +def update_itemised_tax_data(doc): + if not doc.taxes: return + + itemised_tax = get_itemised_tax(doc.taxes) + + for row in doc.items: + tax_rate = 0.0 + if itemised_tax.get(row.item_code): + tax_rate = sum([tax.get('tax_rate', 0) for d, tax in itemised_tax.get(row.item_code).items()]) + + row.tax_rate = flt(tax_rate, row.precision("tax_rate")) + row.tax_amount = flt((row.net_amount * tax_rate) / 100, row.precision("net_amount")) + row.total_amount = flt((row.net_amount + row.tax_amount), row.precision("total_amount")) + +@frappe.whitelist() +def export_invoices(filters=None): + saved_xmls = [] + + invoices = frappe.get_all("Sales Invoice", filters=get_conditions(filters), fields=["*"]) + + for invoice in invoices: + attachments = get_e_invoice_attachments(invoice) + saved_xmls += [attachment.file_name for attachment in attachments] + + zip_filename = "{0}-einvoices.zip".format(frappe.utils.get_datetime().strftime("%Y%m%d_%H%M%S")) + + download_zip(saved_xmls, zip_filename) + + +@frappe.whitelist() +def prepare_invoice(invoice, progressive_number): + #set company information + company = frappe.get_doc("Company", invoice.company) + + invoice.progressive_number = progressive_number + invoice.unamended_name = get_unamended_name(invoice) + invoice.company_data = company + company_address = frappe.get_doc("Address", invoice.company_address) + invoice.company_address_data = company_address + + #Set invoice type + if invoice.is_return and invoice.return_against: + invoice.type_of_document = "TD04" #Credit Note (Nota di Credito) + invoice.return_against_unamended = get_unamended_name(frappe.get_doc("Sales Invoice", invoice.return_against)) + else: + invoice.type_of_document = "TD01" #Sales Invoice (Fattura) + + #set customer information + invoice.customer_data = frappe.get_doc("Customer", invoice.customer) + customer_address = frappe.get_doc("Address", invoice.customer_address) + invoice.customer_address_data = customer_address + + if invoice.shipping_address_name: + invoice.shipping_address_data = frappe.get_doc("Address", invoice.shipping_address_name) + + if invoice.customer_data.is_public_administration: + invoice.transmission_format_code = "FPA12" + else: + invoice.transmission_format_code = "FPR12" + + tax_data = get_invoice_summary(invoice.items, invoice.taxes) + invoice.tax_data = tax_data + + #Check if stamp duty (Bollo) of 2 EUR exists. + stamp_duty_charge_row = next((tax for tax in invoice.taxes if tax.charge_type == _("Actual") and tax.tax_amount == 2.0 ), None) + if stamp_duty_charge_row: + invoice.stamp_duty = stamp_duty_charge_row.tax_amount + + for item in invoice.items: + if item.tax_rate == 0.0: + item.tax_exemption_reason = tax_data["0.0"]["tax_exemption_reason"] + + return invoice + +def get_conditions(filters): + filters = json.loads(filters) + + conditions = {"docstatus": 1} + + if filters.get("company"): conditions["company"] = filters["company"] + if filters.get("customer"): conditions["customer"] = filters["customer"] + + if filters.get("from_date"): conditions["posting_date"] = (">=", filters["from_date"]) + if filters.get("to_date"): conditions["posting_date"] = ("<=", filters["to_date"]) + + if filters.get("from_date") and filters.get("to_date"): + conditions["posting_date"] = ("between", [filters.get("from_date"), filters.get("to_date")]) + + return conditions + +#TODO: Use function from frappe once PR #6853 is merged. +def download_zip(files, output_filename): + from zipfile import ZipFile + + input_files = [frappe.get_site_path('private', 'files', filename) for filename in files] + output_path = frappe.get_site_path('private', 'files', output_filename) + + with ZipFile(output_path, 'w') as output_zip: + for input_file in input_files: + output_zip.write(input_file, arcname=os.path.basename(input_file)) + + with open(output_path, 'rb') as fileobj: + filedata = fileobj.read() + + frappe.local.response.filename = output_filename + frappe.local.response.filecontent = filedata + frappe.local.response.type = "download" + +def get_invoice_summary(items, taxes): + summary_data = frappe._dict() + for tax in taxes: + #Include only VAT charges. + if tax.charge_type == "Actual": + continue + + #Check item tax rates if tax rate is zero. + if tax.rate == 0: + for item in items: + item_tax_rate = json.loads(item.item_tax_rate) + if tax.account_head in item_tax_rate: + key = str(item_tax_rate[tax.account_head]) + summary_data.setdefault(key, {"tax_amount": 0.0, "taxable_amount": 0.0, "tax_exemption_reason": "", "tax_exemption_law": ""}) + summary_data[key]["tax_amount"] += item.tax_amount + summary_data[key]["taxable_amount"] += item.net_amount + if key == "0.0": + summary_data[key]["tax_exemption_reason"] = tax.tax_exemption_reason + summary_data[key]["tax_exemption_law"] = tax.tax_exemption_law + + if summary_data == {}: #Implies that Zero VAT has not been set on any item. + summary_data.setdefault("0.0", {"tax_amount": 0.0, "taxable_amount": tax.total, + "tax_exemption_reason": tax.tax_exemption_reason, "tax_exemption_law": tax.tax_exemption_law}) + + else: + item_wise_tax_detail = json.loads(tax.item_wise_tax_detail) + for rate_item in [tax_item for tax_item in item_wise_tax_detail.items() if tax_item[1][0] == tax.rate]: + key = str(tax.rate) + if not summary_data.get(key): summary_data.setdefault(key, {"tax_amount": 0.0, "taxable_amount": 0.0}) + summary_data[key]["tax_amount"] += rate_item[1][1] + summary_data[key]["taxable_amount"] += sum([item.net_amount for item in items if item.item_code == rate_item[0]]) + + return summary_data + +#Preflight for successful e-invoice export. +def sales_invoice_validate(doc): + #Validate company + if not doc.company_address: + frappe.throw(_("Please set an Address on the Company '%s'" % doc.company), title=_("E-Invoicing Information Missing")) + else: + validate_address(doc.company_address, "Company") + + if not doc.company_tax_id and not doc.company_fiscal_code: + frappe.throw(_("Please set either the Tax ID or Fiscal Code on Company '%s'" % doc.company), title=_("E-Invoicing Information Missing")) + + #Validate customer details + customer_type, is_public_administration = frappe.db.get_value("Customer", doc.customer, ["customer_type", "is_public_administration"]) + if customer_type == _("Individual"): + if not doc.customer_fiscal_code: + frappe.throw(_("Please set Fiscal Code for the customer '%s'" % doc.customer), title=_("E-Invoicing Information Missing")) + else: + if is_public_administration: + if not doc.customer_fiscal_code: + frappe.throw(_("Please set Fiscal Code for the public administration '%s'" % doc.customer), title=_("E-Invoicing Information Missing")) + else: + if not doc.tax_id: + frappe.throw(_("Please set Tax ID for the customer '%s'" % doc.customer), title=_("E-Invoicing Information Missing")) + + if not doc.customer_address: + frappe.throw(_("Please set the Customer Address"), title=_("E-Invoicing Information Missing")) + else: + validate_address(doc.customer_address, "Customer") + + if not len(doc.taxes): + frappe.throw(_("Please set at least one row in the Taxes and Charges Table"), title=_("E-Invoicing Information Missing")) + else: + for row in doc.taxes: + if row.rate == 0 and row.tax_amount == 0 and not row.tax_exemption_reason: + frappe.throw(_("Row {0}: Please set at Tax Exemption Reason in Sales Taxes and Charges".format(row.idx)), + title=_("E-Invoicing Information Missing")) + + +#Ensure payment details are valid for e-invoice. +def sales_invoice_on_submit(doc): + #Validate payment details + if not len(doc.payment_schedule): + frappe.throw(_("Please set the Payment Schedule"), title=_("E-Invoicing Information Missing")) + else: + for schedule in doc.payment_schedule: + if not schedule.mode_of_payment: + frappe.throw(_("Row {0}: Please set the Mode of Payment in Payment Schedule".format(schedule.idx)), + title=_("E-Invoicing Information Missing")) + + prepare_and_attach_invoice(doc) + +def prepare_and_attach_invoice(doc): + progressive_name, progressive_number = get_progressive_name_and_number(doc) + + invoice = prepare_invoice(doc, progressive_number) + invoice_xml = frappe.render_template('erpnext/regional/italy/e-invoice.xml', context={"doc": invoice}, is_path=True) + + xml_filename = progressive_name + ".xml" + save_file(xml_filename, invoice_xml, dt=doc.doctype, dn=doc.name, is_private=True) + +#Delete e-invoice attachment on cancel. +def sales_invoice_on_cancel(doc): + for attachment in get_e_invoice_attachments(doc): + remove_file(attachment.name, attached_to_doctype=doc.doctype, attached_to_name=doc.name) + +def get_e_invoice_attachments(invoice): + out = [] + attachments = get_attachments(invoice.doctype, invoice.name) + company_tax_id = invoice.company_tax_id if invoice.company_tax_id.startswith("IT") else "IT" + invoice.company_tax_id + + for attachment in attachments: + if attachment.file_name.startswith(company_tax_id) and attachment.file_name.endswith(".xml"): + out.append(attachment) + + return out + +def validate_address(address_name, address_context): + pincode, city = frappe.db.get_value("Address", address_name, ["pincode", "city"]) + if not pincode: + frappe.throw(_("Please set pin code on %s Address" % address_context), title=_("E-Invoicing Information Missing")) + if not city: + frappe.throw(_("Please set city on %s Address" % address_context), title=_("E-Invoicing Information Missing")) + + +def get_unamended_name(doc): + attributes = ["naming_series", "amended_from"] + for attribute in attributes: + if not hasattr(doc, attribute): + return doc.name + + if doc.amended_from: + return "-".join(doc.name.split("-")[:-1]) + else: + return doc.name + +def get_progressive_name_and_number(doc): + company_tax_id = doc.company_tax_id if doc.company_tax_id.startswith("IT") else "IT" + doc.company_tax_id + progressive_name = frappe.model.naming.make_autoname(company_tax_id + "_.#####") + progressive_number = progressive_name.split("_")[1] + + return progressive_name, progressive_number \ No newline at end of file diff --git a/erpnext/regional/report/electronic_invoice_register/__init__.py b/erpnext/regional/report/electronic_invoice_register/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.js b/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.js new file mode 100644 index 0000000000..67297f757c --- /dev/null +++ b/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.js @@ -0,0 +1,53 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Electronic Invoice Register"] = { + "filters": [ + { + "fieldname":"from_date", + "label": __("From Date"), + "fieldtype": "Date", + "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1), + "width": "80" + }, + { + "fieldname":"to_date", + "label": __("To Date"), + "fieldtype": "Date", + "default": frappe.datetime.get_today() + }, + { + "fieldname":"customer", + "label": __("Customer"), + "fieldtype": "Link", + "options": "Customer" + }, + { + "fieldname":"company", + "label": __("Company"), + "fieldtype": "Link", + "options": "Company", + "default": frappe.defaults.get_user_default("Company") + }, + ], + "onload": function(reportview) { + reportview.page.add_inner_button(__("Export E-Invoices"), function() { + //TODO: refactor condition to disallow export if report has no data. + if (!reportview.data.length) { + frappe.msgprint(__("No data to export")); + return + } + + var w = window.open( + frappe.urllib.get_full_url( + "/api/method/erpnext.regional.italy.utils.export_invoices?" + + "filters=" + JSON.stringify(reportview.get_filter_values()) + ) + ); + if (!w) { + frappe.msgprint(__("Please enable pop-ups")); return; + } + }) + } +} diff --git a/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.json b/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.json new file mode 100644 index 0000000000..5470c49c57 --- /dev/null +++ b/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.json @@ -0,0 +1,21 @@ +{ + "add_total_row": 0, + "color": "green", + "creation": "2019-01-13 17:43:21.903589", + "disabled": 1, + "docstatus": 0, + "doctype": "Report", + "icon": "fa fa-file-code-o", + "idx": 0, + "is_standard": "Yes", + "modified": "2019-01-13 19:03:56.187748", + "modified_by": "Administrator", + "module": "Regional", + "name": "Electronic Invoice Register", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Sales Invoice", + "report_name": "Electronic Invoice Register", + "report_type": "Script Report", + "roles": [] +} \ No newline at end of file diff --git a/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.py b/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.py new file mode 100644 index 0000000000..376ba3ee47 --- /dev/null +++ b/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.py @@ -0,0 +1,8 @@ +# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +from erpnext.accounts.report.sales_register.sales_register import _execute + +def execute(filters=None): + return _execute(filters) diff --git a/erpnext/setup/doctype/company/test_company.py b/erpnext/setup/doctype/company/test_company.py index c3260ab906..1b08a228b6 100644 --- a/erpnext/setup/doctype/company/test_company.py +++ b/erpnext/setup/doctype/company/test_company.py @@ -46,7 +46,7 @@ class TestCompany(unittest.TestCase): def test_coa_based_on_country_template(self): countries = ["India", "Brazil", "United Arab Emirates", "Canada", "Germany", "France", - "Guatemala", "Indonesia", "Mexico", "Nicaragua", "Netherlands", "Singapore", + "Guatemala", "Indonesia", "Italy", "Mexico", "Nicaragua", "Netherlands", "Singapore", "Brazil", "Argentina", "Hungary", "Taiwan"] for country in countries: From 2670ad7eb251c78c206e0e32fad4b91300bdc9ac Mon Sep 17 00:00:00 2001 From: Gaurav Date: Tue, 19 Feb 2019 10:17:17 +0530 Subject: [PATCH 8/8] mod(regional,italy): adjusted calculation logic for charges validation for missing code on mode of payment UOM from settings Replace str with cstr --- erpnext/regional/italy/e-invoice.xml | 2 +- erpnext/regional/italy/utils.py | 46 ++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/erpnext/regional/italy/e-invoice.xml b/erpnext/regional/italy/e-invoice.xml index 84b7fffbbc..1c416eeec6 100644 --- a/erpnext/regional/italy/e-invoice.xml +++ b/erpnext/regional/italy/e-invoice.xml @@ -153,7 +153,7 @@ {%- endif %} - {%- for item in doc.items %} + {%- for item in doc.e_invoice_items %} {{ item.idx }} diff --git a/erpnext/regional/italy/utils.py b/erpnext/regional/italy/utils.py index 69f7b464c9..85f744774f 100644 --- a/erpnext/regional/italy/utils.py +++ b/erpnext/regional/italy/utils.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals + import frappe, json, os -from frappe.utils import flt +from frappe.utils import flt, cstr from erpnext.controllers.taxes_and_totals import get_itemised_tax from frappe import _ from frappe.utils.file_manager import save_file, remove_file @@ -66,7 +68,8 @@ def prepare_invoice(invoice, progressive_number): else: invoice.transmission_format_code = "FPR12" - tax_data = get_invoice_summary(invoice.items, invoice.taxes) + invoice.e_invoice_items = [item for item in invoice.items] + tax_data = get_invoice_summary(invoice.e_invoice_items, invoice.taxes) invoice.tax_data = tax_data #Check if stamp duty (Bollo) of 2 EUR exists. @@ -74,8 +77,8 @@ def prepare_invoice(invoice, progressive_number): if stamp_duty_charge_row: invoice.stamp_duty = stamp_duty_charge_row.tax_amount - for item in invoice.items: - if item.tax_rate == 0.0: + for item in invoice.e_invoice_items: + if item.tax_rate == 0.0 and item.tax_amount == 0.0: item.tax_exemption_reason = tax_data["0.0"]["tax_exemption_reason"] return invoice @@ -121,12 +124,34 @@ def get_invoice_summary(items, taxes): if tax.charge_type == "Actual": continue + #Charges to appear as items in the e-invoice. + if tax.charge_type in ["On Previous Row Total", "On Previous Row Amount"]: + reference_row = next((row for row in taxes if row.idx == int(tax.row_id or 0)), None) + if reference_row: + items.append( + frappe._dict( + idx=len(items)+1, + item_code=reference_row.description, + item_name=reference_row.description, + rate=reference_row.tax_amount, + qty=1.0, + amount=reference_row.tax_amount, + stock_uom=frappe.db.get_single_value("Stock Settings", "stock_uom") or _("Nos"), + tax_rate=tax.rate, + tax_amount=(reference_row.tax_amount * tax.rate) / 100, + net_amount=reference_row.tax_amount, + taxable_amount=reference_row.tax_amount, + item_tax_rate="{}", + charges=True + ) + ) + #Check item tax rates if tax rate is zero. if tax.rate == 0: for item in items: item_tax_rate = json.loads(item.item_tax_rate) if tax.account_head in item_tax_rate: - key = str(item_tax_rate[tax.account_head]) + key = cstr(item_tax_rate[tax.account_head]) summary_data.setdefault(key, {"tax_amount": 0.0, "taxable_amount": 0.0, "tax_exemption_reason": "", "tax_exemption_law": ""}) summary_data[key]["tax_amount"] += item.tax_amount summary_data[key]["taxable_amount"] += item.net_amount @@ -141,11 +166,17 @@ def get_invoice_summary(items, taxes): else: item_wise_tax_detail = json.loads(tax.item_wise_tax_detail) for rate_item in [tax_item for tax_item in item_wise_tax_detail.items() if tax_item[1][0] == tax.rate]: - key = str(tax.rate) + key = cstr(tax.rate) if not summary_data.get(key): summary_data.setdefault(key, {"tax_amount": 0.0, "taxable_amount": 0.0}) summary_data[key]["tax_amount"] += rate_item[1][1] summary_data[key]["taxable_amount"] += sum([item.net_amount for item in items if item.item_code == rate_item[0]]) + for item in items: + key = cstr(tax.rate) + if item.get("charges"): + if not summary_data.get(key): summary_data.setdefault(key, {"taxable_amount": 0.0}) + summary_data[key]["taxable_amount"] += item.taxable_amount + return summary_data #Preflight for successful e-invoice export. @@ -196,6 +227,9 @@ def sales_invoice_on_submit(doc): if not schedule.mode_of_payment: frappe.throw(_("Row {0}: Please set the Mode of Payment in Payment Schedule".format(schedule.idx)), title=_("E-Invoicing Information Missing")) + elif not frappe.db.get_value("Mode of Payment", schedule.mode_of_payment, "mode_of_payment_code"): + frappe.throw(_("Row {0}: Please set the correct code on Mode of Payment {1}".format(schedule.idx, schedule.mode_of_payment)), + title=_("E-Invoicing Information Missing")) prepare_and_attach_invoice(doc)