Merge branch 'develop' into dont_update_pe_title

This commit is contained in:
Ankush Menat 2021-03-08 15:44:15 +05:30 committed by GitHub
commit afc766bbf1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 114 additions and 38 deletions

View File

@ -11,15 +11,18 @@
],
"fields": [
{
"allow_in_quick_entry": 1,
"fieldname": "title",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Title",
"reqd": 1,
"unique": 1
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2020-08-30 19:41:25.783852",
"modified": "2021-03-03 11:50:38.748872",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Tax Category",

View File

@ -22,8 +22,8 @@
</p>
</div>
{% endif %}
<h5 class="font-bold" style="margin-top: 0px;">1. Transaction Details</h5>
<div class="row section-break" style="border-bottom: 1px solid #d1d8dd; padding-bottom: 10px;">
<h5 class="font-bold" style="margin-left: 15px; margin-top: 0px;">1. Transaction Details</h5>
<div class="col-xs-8 column-break">
<div class="row data-field">
<div class="col-xs-4"><label>IRN</label></div>
@ -54,8 +54,8 @@
<img src="{{ doc.qrcode_image }}" width="175px" style="float: right;">
</div>
</div>
<h5 class="font-bold" style="margin-top: 15px; margin-bottom: 10px;">2. Party Details</h5>
<div class="row section-break" style="border-bottom: 1px solid #d1d8dd; padding-bottom: 10px;">
<h5 class="font-bold" style="margin-left: 15px; margin-bottom: 0px;">2. Party Details</h5>
{%- set seller = einvoice.SellerDtls -%}
<div class="col-xs-6 column-break">
<h5 style="margin-bottom: 5px;">Seller</h5>
@ -89,7 +89,7 @@
</div>
</div>
<div style="overflow-x: auto;">
<h5 class="font-bold" style="margin-bottom: 0px;">3. Item Details</h5>
<h5 class="font-bold" style="margin-top: 15px; margin-bottom: 10px;">3. Item Details</h5>
<table class="table table-bordered">
<thead>
<tr>

View File

@ -258,7 +258,7 @@
{% } %}
{% } else { %}
{% if(data[i]["party"]|| "&nbsp;") { %}
{% if((data[i]["party"]) != __("'Total'")) { %}
{% if(!data[i]["is_total_row"]) { %}
<td>
{% if(!(filters.customer || filters.supplier)) { %}
{%= data[i]["party"] %}

View File

@ -1061,7 +1061,7 @@
"type": "Link"
}
],
"modified": "2020-12-01 13:38:35.349024",
"modified": "2021-03-04 00:38:35.349024",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting",
@ -1071,7 +1071,7 @@
"pin_to_top": 0,
"shortcuts": [
{
"label": "Chart Of Accounts",
"label": "Chart of Accounts",
"link_to": "Account",
"type": "DocType"
},
@ -1116,4 +1116,4 @@
"type": "Dashboard"
}
]
}
}

View File

@ -96,7 +96,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2020-10-13 12:00:23.276329",
"modified": "2021-03-02 17:34:04.190677",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying Settings",
@ -113,5 +113,6 @@
}
],
"sort_field": "modified",
"sort_order": "DESC"
}
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -103,7 +103,7 @@
}
],
"links": [],
"modified": "2021-01-29 12:02:16.106942",
"modified": "2021-03-02 17:35:14.084342",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "Mpesa Settings",
@ -147,5 +147,6 @@
}
],
"sort_field": "modified",
"sort_order": "DESC"
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -70,7 +70,7 @@
],
"issingle": 1,
"links": [],
"modified": "2020-10-29 20:24:56.916104",
"modified": "2021-03-02 17:35:27.544259",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "Plaid Settings",
@ -88,5 +88,6 @@
}
],
"sort_field": "modified",
"sort_order": "DESC"
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -330,7 +330,7 @@
],
"issingle": 1,
"links": [],
"modified": "2020-11-05 20:44:03.664891",
"modified": "2021-03-02 17:35:41.953317",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "Shopify Settings",
@ -348,5 +348,6 @@
}
],
"sort_field": "modified",
"sort_order": "DESC"
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -278,6 +278,9 @@ doc_events = {
('Sales Invoice', 'Sales Order', 'Delivery Note', 'Purchase Invoice', 'Purchase Order', 'Purchase Receipt'): {
'validate': ['erpnext.regional.india.utils.set_place_of_supply']
},
('Sales Invoice', 'Purchase Invoice'): {
'validate': ['erpnext.regional.india.utils.validate_document_name']
},
"Contact": {
"on_trash": "erpnext.support.doctype.issue.issue.update_issue",
"after_insert": "erpnext.telephony.doctype.call_log.call_log.link_existing_conversations",

View File

@ -528,6 +528,10 @@ class WorkOrder(Document):
if not reset_only_qty:
self.required_items = []
operation = None
if self.get('operations') and len(self.operations) == 1:
operation = self.operations[0].operation
if self.bom_no and self.qty:
item_dict = get_bom_items_as_dict(self.bom_no, self.company, qty=self.qty,
fetch_exploded = self.use_multi_level_bom)
@ -536,6 +540,9 @@ class WorkOrder(Document):
for d in self.get("required_items"):
if item_dict.get(d.item_code):
d.required_qty = item_dict.get(d.item_code).get("qty")
if not d.operation:
d.operation = operation
else:
# Attribute a big number (999) to idx for sorting putpose in case idx is NULL
# For instance in BOM Explosion Item child table, the items coming from sub assembly items
@ -543,7 +550,7 @@ class WorkOrder(Document):
self.append('required_items', {
'rate': item.rate,
'amount': item.amount,
'operation': item.operation,
'operation': item.operation or operation,
'item_code': item.item_code,
'item_name': item.item_name,
'description': item.description,
@ -879,7 +886,7 @@ def create_job_card(work_order, row, qty=0, enable_capacity_planning=False, auto
doc.schedule_time_logs(row)
doc.insert()
frappe.msgprint(_("Job card {0} created").format(get_link_to_form("Job Card", doc.name)))
frappe.msgprint(_("Job card {0} created").format(get_link_to_form("Job Card", doc.name)), alert=True)
return doc

View File

@ -97,7 +97,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2021-02-19 11:07:55.873991",
"modified": "2021-03-03 17:49:59.579723",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Payroll Settings",
@ -114,5 +114,6 @@
}
],
"sort_field": "modified",
"sort_order": "ASC"
"sort_order": "ASC",
"track_changes": 1
}

View File

@ -1,12 +1,12 @@
erpnext.setup_einvoice_actions = (doctype) => {
frappe.ui.form.on(doctype, {
refresh(frm) {
const einvoicing_enabled = frappe.db.get_value("E Invoice Settings", "E Invoice Settings", "enable");
async refresh(frm) {
const einvoicing_enabled = await frappe.db.get_single_value("E Invoice Settings", "enable");
const supply_type = frm.doc.gst_category;
const valid_supply_type = ['Registered Regular', 'SEZ', 'Overseas', 'Deemed Export'].includes(supply_type);
const company_transaction = frm.doc.billing_address_gstin == frm.doc.company_gstin;
if (!einvoicing_enabled || !valid_supply_type || company_transaction) return;
if (cint(einvoicing_enabled) == 0 || !valid_supply_type || company_transaction) return;
const { doctype, irn, irn_cancelled, ewaybill, eway_bill_cancelled, name, __unsaved } = frm.doc;
@ -83,7 +83,7 @@ erpnext.setup_einvoice_actions = (doctype) => {
const action = () => {
const d = new frappe.ui.Dialog({
title: __('Generate E-Way Bill'),
wide: 1,
size: "large",
fields: get_ewaybill_fields(frm),
primary_action: function() {
const data = d.get_values();
@ -252,7 +252,7 @@ const request_irn_generation = (frm) => {
const get_preview_dialog = (frm, action) => {
const dialog = new frappe.ui.Dialog({
title: __("Preview"),
wide: 1,
size: "large",
fields: [
{
"label": "Preview",

View File

@ -0,0 +1,38 @@
from __future__ import unicode_literals
import unittest
import frappe
from unittest.mock import patch
from erpnext.regional.india.utils import validate_document_name
class TestIndiaUtils(unittest.TestCase):
@patch("frappe.get_cached_value")
def test_validate_document_name(self, mock_get_cached):
mock_get_cached.return_value = "India" # mock country
posting_date = "2021-05-01"
invalid_names = [ "SI$1231", "012345678901234567", "SI 2020 05",
"SI.2020.0001", "PI2021 - 001" ]
for name in invalid_names:
doc = frappe._dict(name=name, posting_date=posting_date)
self.assertRaises(frappe.ValidationError, validate_document_name, doc)
valid_names = [ "012345678901236", "SI/2020/0001", "SI/2020-0001",
"2020-PI-0001", "PI2020-0001" ]
for name in valid_names:
doc = frappe._dict(name=name, posting_date=posting_date)
try:
validate_document_name(doc)
except frappe.ValidationError:
self.fail("Valid name {} throwing error".format(name))
@patch("frappe.get_cached_value")
def test_validate_document_name_not_india(self, mock_get_cached):
mock_get_cached.return_value = "Not India"
doc = frappe._dict(name="SI$123", posting_date="2021-05-01")
try:
validate_document_name(doc)
except frappe.ValidationError:
self.fail("Regional validation related to India are being applied to other countries")

View File

@ -2,7 +2,7 @@ from __future__ import unicode_literals
import frappe, re, json
from frappe import _
import erpnext
from frappe.utils import cstr, flt, date_diff, nowdate, round_based_on_smallest_currency_fraction, money_in_words
from frappe.utils import cstr, flt, date_diff, nowdate, round_based_on_smallest_currency_fraction, money_in_words, getdate
from erpnext.regional.india import states, state_numbers
from erpnext.controllers.taxes_and_totals import get_itemised_tax, get_itemised_taxable_amount
from erpnext.controllers.accounts_controller import get_taxes_and_charges
@ -14,6 +14,13 @@ from erpnext.accounts.general_ledger import make_gl_entries
from erpnext.accounts.utils import get_account_currency
from frappe.model.utils import get_fetch_values
GST_INVOICE_NUMBER_FORMAT = re.compile(r"^[a-zA-Z0-9\-/]+$") #alphanumeric and - /
GSTIN_FORMAT = re.compile("^[0-9]{2}[A-Z]{4}[0-9A-Z]{1}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}[1-9A-Z]{1}[0-9A-Z]{1}$")
GSTIN_UIN_FORMAT = re.compile("^[0-9]{4}[A-Z]{3}[0-9]{5}[0-9A-Z]{3}")
PAN_NUMBER_FORMAT = re.compile("[A-Z]{5}[0-9]{4}[A-Z]{1}")
def validate_gstin_for_india(doc, method):
if hasattr(doc, 'gst_state') and doc.gst_state:
doc.gst_state_number = state_numbers[doc.gst_state]
@ -37,12 +44,10 @@ def validate_gstin_for_india(doc, method):
frappe.throw(_("Invalid GSTIN! A GSTIN must have 15 characters."))
if gst_category and gst_category == 'UIN Holders':
p = re.compile("^[0-9]{4}[A-Z]{3}[0-9]{5}[0-9A-Z]{3}")
if not p.match(doc.gstin):
if not GSTIN_UIN_FORMAT.match(doc.gstin):
frappe.throw(_("Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers"))
else:
p = re.compile("^[0-9]{2}[A-Z]{4}[0-9A-Z]{1}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}[1-9A-Z]{1}[0-9A-Z]{1}$")
if not p.match(doc.gstin):
if not GSTIN_FORMAT.match(doc.gstin):
frappe.throw(_("Invalid GSTIN! The input you've entered doesn't match the format of GSTIN."))
validate_gstin_check_digit(doc.gstin)
@ -59,8 +64,7 @@ def validate_pan_for_india(doc, method):
if doc.get('country') != 'India' or not doc.pan:
return
p = re.compile("[A-Z]{5}[0-9]{4}[A-Z]{1}")
if not p.match(doc.pan):
if not PAN_NUMBER_FORMAT.match(doc.pan):
frappe.throw(_("Invalid PAN No. The input you've entered doesn't match the format of PAN."))
def validate_tax_category(doc, method):
@ -148,6 +152,20 @@ def get_itemised_tax_breakup_data(doc, account_wise=False):
def set_place_of_supply(doc, method=None):
doc.place_of_supply = get_place_of_supply(doc, doc.doctype)
def validate_document_name(doc, method=None):
"""Validate GST invoice number requirements."""
country = frappe.get_cached_value("Company", doc.company, "country")
# Date was chosen as start of next FY to avoid irritating current users.
if country != "India" or getdate(doc.posting_date) < getdate("2021-04-01"):
return
if len(doc.name) > 16:
frappe.throw(_("Maximum length of document number should be 16 characters as per GST rules. Please change the naming series."))
if not GST_INVOICE_NUMBER_FORMAT.match(doc.name):
frappe.throw(_("Document name should only contain alphanumeric values, dash(-) and slash(/) characters as per GST rules. Please change the naming series."))
# don't remove this function it is used in tests
def test_method():
'''test function'''
@ -800,4 +818,4 @@ def get_regional_round_off_accounts(company, account_list):
account_list.extend(gst_account_list)
return account_list
return account_list

View File

@ -140,7 +140,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2020-10-13 12:12:56.784014",
"modified": "2021-03-02 17:35:53.603607",
"modified_by": "Administrator",
"module": "Selling",
"name": "Selling Settings",
@ -157,5 +157,6 @@
}
],
"sort_field": "modified",
"sort_order": "DESC"
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -190,7 +190,7 @@
"idx": 1,
"issingle": 1,
"links": [],
"modified": "2021-02-11 18:48:30.433058",
"modified": "2021-03-02 17:34:57.642565",
"modified_by": "Administrator",
"module": "Shopping Cart",
"name": "Shopping Cart Settings",
@ -207,5 +207,6 @@
}
],
"sort_field": "modified",
"sort_order": "ASC"
"sort_order": "ASC",
"track_changes": 1
}