Merge branch 'develop' into update-stock-onboarding-fp
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index 439b1ed..d96bc27 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -533,8 +533,8 @@
source_exchange_rate: function(frm) {
if (frm.doc.paid_amount) {
frm.set_value("base_paid_amount", flt(frm.doc.paid_amount) * flt(frm.doc.source_exchange_rate));
- if(!frm.set_paid_amount_based_on_received_amount &&
- (frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency)) {
+ // target exchange rate should always be same as source if both account currencies is same
+ if(frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency) {
frm.set_value("target_exchange_rate", frm.doc.source_exchange_rate);
frm.set_value("base_received_amount", frm.doc.base_paid_amount);
}
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index d2dffde..abacee9 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -55,14 +55,17 @@
self.validate_mandatory()
self.validate_reference_documents()
self.set_tax_withholding()
- self.apply_taxes()
self.set_amounts()
+ self.validate_amounts()
+ self.apply_taxes()
+ self.set_amounts_after_tax()
self.clear_unallocated_reference_document_rows()
self.validate_payment_against_negative_invoice()
self.validate_transaction_reference()
self.set_title()
self.set_remarks()
self.validate_duplicate_entry()
+ self.validate_payment_type_with_outstanding()
self.validate_allocated_amount()
self.validate_paid_invoices()
self.ensure_supplier_is_not_blocked()
@@ -118,6 +121,11 @@
if not self.get(field):
self.set(field, bank_data.account)
+ def validate_payment_type_with_outstanding(self):
+ total_outstanding = sum(d.allocated_amount for d in self.get('references'))
+ if total_outstanding < 0 and self.party_type == 'Customer' and self.payment_type == 'Receive':
+ frappe.throw(_("Cannot receive from customer against negative outstanding"), title=_("Incorrect Payment Type"))
+
def validate_allocated_amount(self):
for d in self.get("references"):
if (flt(d.allocated_amount))> 0:
@@ -236,7 +244,9 @@
self.company_currency, self.posting_date)
def set_target_exchange_rate(self, ref_doc=None):
- if self.paid_to and not self.target_exchange_rate:
+ if self.paid_from_account_currency == self.paid_to_account_currency:
+ self.target_exchange_rate = self.source_exchange_rate
+ elif self.paid_to and not self.target_exchange_rate:
if ref_doc:
if self.paid_to_account_currency == ref_doc.currency:
self.target_exchange_rate = ref_doc.get("exchange_rate")
@@ -468,13 +478,22 @@
def set_amounts(self):
self.set_received_amount()
self.set_amounts_in_company_currency()
- self.set_amounts_after_tax()
self.set_total_allocated_amount()
self.set_unallocated_amount()
self.set_difference_amount()
+ def validate_amounts(self):
+ self.validate_received_amount()
+
+ def validate_received_amount(self):
+ if self.paid_from_account_currency == self.paid_to_account_currency:
+ if self.paid_amount != self.received_amount:
+ frappe.throw(_("Received Amount cannot be greater than Paid Amount"))
+
def set_received_amount(self):
self.base_received_amount = self.base_paid_amount
+ if self.paid_from_account_currency == self.paid_to_account_currency:
+ self.received_amount = self.paid_amount
def set_amounts_after_tax(self):
applicable_tax = 0
diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
index 801dadc..dac927b 100644
--- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
@@ -107,7 +107,7 @@
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
pe.reference_no = "1"
pe.reference_date = "2016-01-01"
- pe.target_exchange_rate = 50
+ pe.source_exchange_rate = 50
pe.insert()
pe.submit()
@@ -154,7 +154,7 @@
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
pe.reference_no = "1"
pe.reference_date = "2016-01-01"
- pe.target_exchange_rate = 50
+ pe.source_exchange_rate = 50
pe.insert()
pe.submit()
@@ -491,7 +491,7 @@
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
pe.reference_no = "1"
pe.reference_date = "2016-01-01"
- pe.target_exchange_rate = 55
+ pe.source_exchange_rate = 55
pe.append("deductions", {
"account": "_Test Exchange Gain/Loss - _TC",
diff --git a/erpnext/accounts/doctype/pos_closing_entry/test_pos_closing_entry.py b/erpnext/accounts/doctype/pos_closing_entry/test_pos_closing_entry.py
index b596c0c..5b18ebb 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/test_pos_closing_entry.py
+++ b/erpnext/accounts/doctype/pos_closing_entry/test_pos_closing_entry.py
@@ -85,9 +85,15 @@
pcv_doc.load_from_db()
pcv_doc.cancel()
- si_doc.load_from_db()
+
+ cancelled_invoice = frappe.db.get_value(
+ 'POS Invoice Merge Log', {'pos_closing_entry': pcv_doc.name},
+ 'consolidated_invoice'
+ )
+ docstatus = frappe.db.get_value("Sales Invoice", cancelled_invoice, 'docstatus')
+ self.assertEqual(docstatus, 2)
+
pos_inv1.load_from_db()
- self.assertEqual(si_doc.docstatus, 2)
self.assertEqual(pos_inv1.status, 'Paid')
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
index 181e9f8..15c2922 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
@@ -16,7 +16,7 @@
onload(doc) {
super.onload();
- this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice Merge Log'];
+ this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice Merge Log', 'POS Closing Entry'];
if(doc.__islocal && doc.is_pos && frappe.get_route_str() !== 'point-of-sale') {
this.frm.script_manager.trigger("is_pos");
this.frm.refresh_fields();
@@ -111,16 +111,12 @@
}
write_off_outstanding_amount_automatically() {
- if(cint(this.frm.doc.write_off_outstanding_amount_automatically)) {
+ if (cint(this.frm.doc.write_off_outstanding_amount_automatically)) {
frappe.model.round_floats_in(this.frm.doc, ["grand_total", "paid_amount"]);
// this will make outstanding amount 0
this.frm.set_value("write_off_amount",
flt(this.frm.doc.grand_total - this.frm.doc.paid_amount - this.frm.doc.total_advance, precision("write_off_amount"))
);
- this.frm.toggle_enable("write_off_amount", false);
-
- } else {
- this.frm.toggle_enable("write_off_amount", true);
}
this.calculate_outstanding_amount(false);
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
index 33c3e04..b819537 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
@@ -99,6 +99,7 @@
"loyalty_redemption_account",
"loyalty_redemption_cost_center",
"section_break_49",
+ "coupon_code",
"apply_discount_on",
"base_discount_amount",
"column_break_51",
@@ -595,7 +596,8 @@
{
"fieldname": "scan_barcode",
"fieldtype": "Data",
- "label": "Scan Barcode"
+ "label": "Scan Barcode",
+ "options": "Barcode"
},
{
"allow_bulk_edit": 1,
@@ -1182,7 +1184,8 @@
"label": "Write Off Amount",
"no_copy": 1,
"options": "currency",
- "print_hide": 1
+ "print_hide": 1,
+ "read_only_depends_on": "eval: doc.write_off_outstanding_amount_automatically"
},
{
"fieldname": "base_write_off_amount",
@@ -1548,12 +1551,20 @@
"no_copy": 1,
"options": "Sales Invoice",
"read_only": 1
+ },
+ {
+ "depends_on": "coupon_code",
+ "fieldname": "coupon_code",
+ "fieldtype": "Link",
+ "label": "Coupon Code",
+ "options": "Coupon Code",
+ "print_hide": 1
}
],
"icon": "fa fa-file-text",
"is_submittable": 1,
"links": [],
- "modified": "2021-07-29 13:37:20.636171",
+ "modified": "2021-08-18 16:13:52.080543",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice",
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
index 8ec4ef2..759cad5 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
@@ -44,6 +44,9 @@
self.validate_pos()
self.validate_payment_amount()
self.validate_loyalty_transaction()
+ if self.coupon_code:
+ from erpnext.accounts.doctype.pricing_rule.utils import validate_coupon_code
+ validate_coupon_code(self.coupon_code)
def on_submit(self):
# create the loyalty point ledger entry if the customer is enrolled in any loyalty program
@@ -58,6 +61,10 @@
self.check_phone_payments()
self.set_status(update=True)
+ if self.coupon_code:
+ from erpnext.accounts.doctype.pricing_rule.utils import update_coupon_code_count
+ update_coupon_code_count(self.coupon_code,'used')
+
def before_cancel(self):
if self.consolidated_invoice and frappe.db.get_value('Sales Invoice', self.consolidated_invoice, 'docstatus') == 1:
pos_closing_entry = frappe.get_all(
@@ -84,6 +91,10 @@
against_psi_doc.delete_loyalty_point_entry()
against_psi_doc.make_loyalty_point_entry()
+ if self.coupon_code:
+ from erpnext.accounts.doctype.pricing_rule.utils import update_coupon_code_count
+ update_coupon_code_count(self.coupon_code,'cancelled')
+
def check_phone_payments(self):
for pay in self.payments:
if pay.type == "Phone" and pay.amount >= 0:
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index 556f49d..4903c50 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -198,12 +198,19 @@
set_serial_nos_based_on_fifo = frappe.db.get_single_value("Stock Settings",
"automatically_set_serial_nos_based_on_fifo")
+ item_code_list = tuple(item.get('item_code') for item in item_list)
+ query_items = frappe.get_all('Item', fields=['item_code','has_serial_no'], filters=[['item_code','in',item_code_list]],as_list=1)
+ serialized_items = dict()
+ for item_code, val in query_items:
+ serialized_items.setdefault(item_code, val)
+
for item in item_list:
args_copy = copy.deepcopy(args)
args_copy.update(item)
data = get_pricing_rule_for_item(args_copy, item.get('price_list_rate'), doc=doc)
out.append(data)
- if not item.get("serial_no") and set_serial_nos_based_on_fifo and not args.get('is_return'):
+
+ if serialized_items.get(item.get('item_code')) and not item.get("serial_no") and set_serial_nos_based_on_fifo and not args.get('is_return'):
out[0].update(get_serial_no_for_item(args_copy))
return out
diff --git a/erpnext/accounts/doctype/promotional_scheme_price_discount/promotional_scheme_price_discount.json b/erpnext/accounts/doctype/promotional_scheme_price_discount/promotional_scheme_price_discount.json
index 795fb1c..a70d5c9 100644
--- a/erpnext/accounts/doctype/promotional_scheme_price_discount/promotional_scheme_price_discount.json
+++ b/erpnext/accounts/doctype/promotional_scheme_price_discount/promotional_scheme_price_discount.json
@@ -106,7 +106,6 @@
"depends_on": "eval:doc.rate_or_discount==\"Rate\"",
"fieldname": "rate",
"fieldtype": "Currency",
- "in_list_view": 1,
"label": "Rate"
},
{
@@ -170,7 +169,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2021-03-07 11:56:23.424137",
+ "modified": "2021-08-19 15:49:29.598727",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Promotional Scheme Price Discount",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 7025dd9..7822f74 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -668,8 +668,7 @@
"fieldname": "scan_barcode",
"fieldtype": "Data",
"label": "Scan Barcode",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Barcode"
},
{
"allow_bulk_edit": 1,
@@ -1715,7 +1714,7 @@
"idx": 204,
"is_submittable": 1,
"links": [],
- "modified": "2021-08-07 17:53:14.351439",
+ "modified": "2021-08-17 20:16:12.737743",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/regional/india.js b/erpnext/accounts/doctype/sales_invoice/regional/india.js
index f54bce8..6336db1 100644
--- a/erpnext/accounts/doctype/sales_invoice/regional/india.js
+++ b/erpnext/accounts/doctype/sales_invoice/regional/india.js
@@ -1,8 +1,6 @@
{% include "erpnext/regional/india/taxes.js" %}
-{% include "erpnext/regional/india/e_invoice/einvoice.js" %}
erpnext.setup_auto_gst_taxation('Sales Invoice');
-erpnext.setup_einvoice_actions('Sales Invoice')
frappe.ui.form.on("Sales Invoice", {
setup: function(frm) {
diff --git a/erpnext/accounts/doctype/sales_invoice/regional/india_list.js b/erpnext/accounts/doctype/sales_invoice/regional/india_list.js
index f01325d..d9d6634 100644
--- a/erpnext/accounts/doctype/sales_invoice/regional/india_list.js
+++ b/erpnext/accounts/doctype/sales_invoice/regional/india_list.js
@@ -36,139 +36,4 @@
};
list_view.page.add_actions_menu_item(__('Generate E-Way Bill JSON'), action, false);
-
- const generate_irns = () => {
- const docnames = list_view.get_checked_items(true);
- if (docnames && docnames.length) {
- frappe.call({
- method: 'erpnext.regional.india.e_invoice.utils.generate_einvoices',
- args: { docnames },
- freeze: true,
- freeze_message: __('Generating E-Invoices...')
- });
- } else {
- frappe.msgprint({
- message: __('Please select at least one sales invoice to generate IRN'),
- title: __('No Invoice Selected'),
- indicator: 'red'
- });
- }
- };
-
- const cancel_irns = () => {
- const docnames = list_view.get_checked_items(true);
-
- const fields = [
- {
- "label": "Reason",
- "fieldname": "reason",
- "fieldtype": "Select",
- "reqd": 1,
- "default": "1-Duplicate",
- "options": ["1-Duplicate", "2-Data Entry Error", "3-Order Cancelled", "4-Other"]
- },
- {
- "label": "Remark",
- "fieldname": "remark",
- "fieldtype": "Data",
- "reqd": 1
- }
- ];
-
- const d = new frappe.ui.Dialog({
- title: __("Cancel IRN"),
- fields: fields,
- primary_action: function() {
- const data = d.get_values();
- frappe.call({
- method: 'erpnext.regional.india.e_invoice.utils.cancel_irns',
- args: {
- doctype: list_view.doctype,
- docnames,
- reason: data.reason.split('-')[0],
- remark: data.remark
- },
- freeze: true,
- freeze_message: __('Cancelling E-Invoices...'),
- });
- d.hide();
- },
- primary_action_label: __('Submit')
- });
- d.show();
- };
-
- let einvoicing_enabled = false;
- frappe.db.get_single_value("E Invoice Settings", "enable").then(enabled => {
- einvoicing_enabled = enabled;
- });
-
- list_view.$result.on("change", "input[type=checkbox]", () => {
- if (einvoicing_enabled) {
- const docnames = list_view.get_checked_items(true);
- // show/hide e-invoicing actions when no sales invoices are checked
- if (docnames && docnames.length) {
- // prevent adding actions twice if e-invoicing action group already exists
- if (list_view.page.get_inner_group_button(__('E-Invoicing')).length == 0) {
- list_view.page.add_inner_button(__('Generate IRNs'), generate_irns, __('E-Invoicing'));
- list_view.page.add_inner_button(__('Cancel IRNs'), cancel_irns, __('E-Invoicing'));
- }
- } else {
- list_view.page.remove_inner_button(__('Generate IRNs'), __('E-Invoicing'));
- list_view.page.remove_inner_button(__('Cancel IRNs'), __('E-Invoicing'));
- }
- }
- });
-
- frappe.realtime.on("bulk_einvoice_generation_complete", (data) => {
- const { failures, user, invoices } = data;
-
- if (invoices.length != failures.length) {
- frappe.msgprint({
- message: __('{0} e-invoices generated successfully', [invoices.length]),
- title: __('Bulk E-Invoice Generation Complete'),
- indicator: 'orange'
- });
- }
-
- if (failures && failures.length && user == frappe.session.user) {
- let message = `
- Failed to generate IRNs for following ${failures.length} sales invoices:
- <ul style="padding-left: 20px; padding-top: 5px;">
- ${failures.map(d => `<li>${d.docname}</li>`).join('')}
- </ul>
- `;
- frappe.msgprint({
- message: message,
- title: __('Bulk E-Invoice Generation Complete'),
- indicator: 'orange'
- });
- }
- });
-
- frappe.realtime.on("bulk_einvoice_cancellation_complete", (data) => {
- const { failures, user, invoices } = data;
-
- if (invoices.length != failures.length) {
- frappe.msgprint({
- message: __('{0} e-invoices cancelled successfully', [invoices.length]),
- title: __('Bulk E-Invoice Cancellation Complete'),
- indicator: 'orange'
- });
- }
-
- if (failures && failures.length && user == frappe.session.user) {
- let message = `
- Failed to cancel IRNs for following ${failures.length} sales invoices:
- <ul style="padding-left: 20px; padding-top: 5px;">
- ${failures.map(d => `<li>${d.docname}</li>`).join('')}
- </ul>
- `;
- frappe.msgprint({
- message: message,
- title: __('Bulk E-Invoice Cancellation Complete'),
- indicator: 'orange'
- });
- }
- });
};
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 8d65101..2071827 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -324,16 +324,12 @@
}
write_off_outstanding_amount_automatically() {
- if(cint(this.frm.doc.write_off_outstanding_amount_automatically)) {
+ if (cint(this.frm.doc.write_off_outstanding_amount_automatically)) {
frappe.model.round_floats_in(this.frm.doc, ["grand_total", "paid_amount"]);
// this will make outstanding amount 0
this.frm.set_value("write_off_amount",
flt(this.frm.doc.grand_total - this.frm.doc.paid_amount - this.frm.doc.total_advance, precision("write_off_amount"))
);
- this.frm.toggle_enable("write_off_amount", false);
-
- } else {
- this.frm.toggle_enable("write_off_amount", true);
}
this.calculate_outstanding_amount(false);
@@ -787,8 +783,6 @@
if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
else hide_field(['c_form_applicable', 'c_form_no']);
- frm.toggle_enable("write_off_amount", !!!cint(doc.write_off_outstanding_amount_automatically));
-
frm.refresh_fields();
},
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index b65b101..5023c9c 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -692,6 +692,7 @@
{
"fieldname": "scan_barcode",
"fieldtype": "Data",
+ "options": "Barcode",
"hide_days": 1,
"hide_seconds": 1,
"label": "Scan Barcode"
@@ -1443,7 +1444,8 @@
"label": "Write Off Amount",
"no_copy": 1,
"options": "currency",
- "print_hide": 1
+ "print_hide": 1,
+ "read_only_depends_on": "eval:doc.write_off_outstanding_amount_automatically"
},
{
"fieldname": "base_write_off_amount",
@@ -2013,7 +2015,7 @@
"link_fieldname": "consolidated_invoice"
}
],
- "modified": "2021-08-17 19:00:32.230701",
+ "modified": "2021-08-18 16:07:45.122570",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 5fa6228..1cf0df0 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -285,8 +285,6 @@
def before_cancel(self):
self.check_if_consolidated_invoice()
-
- super(SalesInvoice, self).before_cancel()
self.update_time_sheet(None)
def on_cancel(self):
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 4d1e0c3..c3d83c7 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -26,6 +26,7 @@
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
from erpnext.stock.utils import get_incoming_rate
+from erpnext.accounts.utils import PaymentEntryUnlinkError
class TestSalesInvoice(unittest.TestCase):
def make(self):
@@ -136,7 +137,7 @@
pe.paid_to_account_currency = si.currency
pe.source_exchange_rate = 1
pe.target_exchange_rate = 1
- pe.paid_amount = si.grand_total
+ pe.paid_amount = si.outstanding_amount
pe.insert()
pe.submit()
@@ -145,6 +146,42 @@
self.assertRaises(frappe.LinkExistsError, si.cancel)
unlink_payment_on_cancel_of_invoice()
+ def test_payment_entry_unlink_against_standalone_credit_note(self):
+ from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
+ si1 = create_sales_invoice(rate=1000)
+ si2 = create_sales_invoice(rate=300)
+ si3 = create_sales_invoice(qty=-1, rate=300, is_return=1)
+
+
+ pe = get_payment_entry("Sales Invoice", si1.name, bank_account="_Test Bank - _TC")
+ pe.append('references', {
+ 'reference_doctype': 'Sales Invoice',
+ 'reference_name': si2.name,
+ 'total_amount': si2.grand_total,
+ 'outstanding_amount': si2.outstanding_amount,
+ 'allocated_amount': si2.outstanding_amount
+ })
+
+ pe.append('references', {
+ 'reference_doctype': 'Sales Invoice',
+ 'reference_name': si3.name,
+ 'total_amount': si3.grand_total,
+ 'outstanding_amount': si3.outstanding_amount,
+ 'allocated_amount': si3.outstanding_amount
+ })
+
+ pe.reference_no = 'Test001'
+ pe.reference_date = nowdate()
+ pe.save()
+ pe.submit()
+
+ si2.load_from_db()
+ si2.cancel()
+
+ si1.load_from_db()
+ self.assertRaises(PaymentEntryUnlinkError, si1.cancel)
+
+
def test_sales_invoice_calculation_export_currency(self):
si = frappe.copy_doc(test_records[2])
si.currency = "USD"
@@ -2014,7 +2051,7 @@
data = get_ewb_data("Sales Invoice", [si.name])
- self.assertEqual(data['version'], '1.0.1118')
+ self.assertEqual(data['version'], '1.0.0421')
self.assertEqual(data['billLists'][0]['fromGstin'], '27AAECE4835E1ZR')
self.assertEqual(data['billLists'][0]['fromTrdName'], '_Test Company')
self.assertEqual(data['billLists'][0]['toTrdName'], '_Test Customer')
@@ -2027,54 +2064,6 @@
self.assertEqual(data['billLists'][0]['actualFromStateCode'],7)
self.assertEqual(data['billLists'][0]['fromStateCode'],27)
- def test_einvoice_submission_without_irn(self):
- # init
- einvoice_settings = frappe.get_doc('E Invoice Settings')
- einvoice_settings.enable = 1
- einvoice_settings.applicable_from = nowdate()
- einvoice_settings.append('credentials', {
- 'company': '_Test Company',
- 'gstin': '27AAECE4835E1ZR',
- 'username': 'test',
- 'password': 'test'
- })
- einvoice_settings.save()
-
- country = frappe.flags.country
- frappe.flags.country = 'India'
-
- si = make_sales_invoice_for_ewaybill()
- self.assertRaises(frappe.ValidationError, si.submit)
-
- si.irn = 'test_irn'
- si.submit()
-
- # reset
- einvoice_settings = frappe.get_doc('E Invoice Settings')
- einvoice_settings.enable = 0
- frappe.flags.country = country
-
- def test_einvoice_json(self):
- from erpnext.regional.india.e_invoice.utils import make_einvoice, validate_totals
-
- si = get_sales_invoice_for_e_invoice()
- si.discount_amount = 100
- si.save()
-
- einvoice = make_einvoice(si)
- self.assertTrue(einvoice['EwbDtls'])
- validate_totals(einvoice)
-
- si.apply_discount_on = 'Net Total'
- si.save()
- einvoice = make_einvoice(si)
- validate_totals(einvoice)
-
- [d.set('included_in_print_rate', 1) for d in si.taxes]
- si.save()
- einvoice = make_einvoice(si)
- validate_totals(einvoice)
-
def test_item_tax_net_range(self):
item = create_item("T Shirt")
diff --git a/erpnext/accounts/print_format/gst_e_invoice/__init__.py b/erpnext/accounts/print_format/gst_e_invoice/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/accounts/print_format/gst_e_invoice/__init__.py
+++ /dev/null
diff --git a/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html b/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html
deleted file mode 100644
index 7643eca..0000000
--- a/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html
+++ /dev/null
@@ -1,162 +0,0 @@
-{%- from "templates/print_formats/standard_macros.html" import add_header, render_field, print_value -%}
-{%- set einvoice = json.loads(doc.signed_einvoice) -%}
-
-<div class="page-break">
- <div {% if print_settings.repeat_header_footer %} id="header-html" class="hidden-pdf" {% endif %}>
- {% if letter_head and not no_letterhead %}
- <div class="letter-head">{{ letter_head }}</div>
- {% endif %}
- <div class="print-heading">
- <h2>E Invoice<br><small>{{ doc.name }}</small></h2>
- </div>
- </div>
- {% if print_settings.repeat_header_footer %}
- <div id="footer-html" class="visible-pdf">
- {% if not no_letterhead and footer %}
- <div class="letter-head-footer">
- {{ footer }}
- </div>
- {% endif %}
- <p class="text-center small page-number visible-pdf">
- {{ _("Page {0} of {1}").format('<span class="page"></span>', '<span class="topage"></span>') }}
- </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;">
- <div class="col-xs-8 column-break">
- <div class="row data-field">
- <div class="col-xs-4"><label>IRN</label></div>
- <div class="col-xs-8 value">{{ einvoice.Irn }}</div>
- </div>
- <div class="row data-field">
- <div class="col-xs-4"><label>Ack. No</label></div>
- <div class="col-xs-8 value">{{ einvoice.AckNo }}</div>
- </div>
- <div class="row data-field">
- <div class="col-xs-4"><label>Ack. Date</label></div>
- <div class="col-xs-8 value">{{ frappe.utils.format_datetime(einvoice.AckDt, "dd/MM/yyyy hh:mm:ss") }}</div>
- </div>
- <div class="row data-field">
- <div class="col-xs-4"><label>Category</label></div>
- <div class="col-xs-8 value">{{ einvoice.TranDtls.SupTyp }}</div>
- </div>
- <div class="row data-field">
- <div class="col-xs-4"><label>Document Type</label></div>
- <div class="col-xs-8 value">{{ einvoice.DocDtls.Typ }}</div>
- </div>
- <div class="row data-field">
- <div class="col-xs-4"><label>Document No</label></div>
- <div class="col-xs-8 value">{{ einvoice.DocDtls.No }}</div>
- </div>
- </div>
- <div class="col-xs-4 column-break">
- <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;">
- {%- set seller = einvoice.SellerDtls -%}
- <div class="col-xs-6 column-break">
- <h5 style="margin-bottom: 5px;">Seller</h5>
- <p>{{ seller.Gstin }}</p>
- <p>{{ seller.LglNm }}</p>
- <p>{{ seller.Addr1 }}</p>
- {%- if seller.Addr2 -%} <p>{{ seller.Addr2 }}</p> {% endif %}
- <p>{{ seller.Loc }}</p>
- <p>{{ frappe.db.get_value("Address", doc.company_address, "gst_state") }} - {{ seller.Pin }}</p>
-
- {%- if einvoice.ShipDtls -%}
- {%- set shipping = einvoice.ShipDtls -%}
- <h5 style="margin-bottom: 5px;">Shipping</h5>
- <p>{{ shipping.Gstin }}</p>
- <p>{{ shipping.LglNm }}</p>
- <p>{{ shipping.Addr1 }}</p>
- {%- if shipping.Addr2 -%} <p>{{ shipping.Addr2 }}</p> {% endif %}
- <p>{{ shipping.Loc }}</p>
- <p>{{ frappe.db.get_value("Address", doc.shipping_address_name, "gst_state") }} - {{ shipping.Pin }}</p>
- {% endif %}
- </div>
- {%- set buyer = einvoice.BuyerDtls -%}
- <div class="col-xs-6 column-break">
- <h5 style="margin-bottom: 5px;">Buyer</h5>
- <p>{{ buyer.Gstin }}</p>
- <p>{{ buyer.LglNm }}</p>
- <p>{{ buyer.Addr1 }}</p>
- {%- if buyer.Addr2 -%} <p>{{ buyer.Addr2 }}</p> {% endif %}
- <p>{{ buyer.Loc }}</p>
- <p>{{ frappe.db.get_value("Address", doc.customer_address, "gst_state") }} - {{ buyer.Pin }}</p>
- </div>
- </div>
- <div style="overflow-x: auto;">
- <h5 class="font-bold" style="margin-top: 15px; margin-bottom: 10px;">3. Item Details</h5>
- <table class="table table-bordered">
- <thead>
- <tr>
- <th class="text-left" style="width: 3%;">Sr. No.</th>
- <th class="text-left">Item</th>
- <th class="text-left" style="width: 10%;">HSN Code</th>
- <th class="text-left" style="width: 5%;">Qty</th>
- <th class="text-left" style="width: 5%;">UOM</th>
- <th class="text-left">Rate</th>
- <th class="text-left" style="width: 5%;">Discount</th>
- <th class="text-left">Taxable Amount</th>
- <th class="text-left" style="width: 7%;">Tax Rate</th>
- <th class="text-left" style="width: 5%;">Other Charges</th>
- <th class="text-left">Total</th>
- </tr>
- </thead>
- <tbody>
- {% for item in einvoice.ItemList %}
- <tr>
- <td class="text-left" style="width: 3%;">{{ item.SlNo }}</td>
- <td class="text-left">{{ item.PrdDesc }}</td>
- <td class="text-left" style="width: 10%;">{{ item.HsnCd }}</td>
- <td class="text-right" style="width: 5%;">{{ item.Qty }}</td>
- <td class="text-left" style="width: 5%;">{{ item.Unit }}</td>
- <td class="text-right">{{ frappe.utils.fmt_money(item.UnitPrice, None, "INR") }}</td>
- <td class="text-right" style="width: 5%;">{{ frappe.utils.fmt_money(item.Discount, None, "INR") }}</td>
- <td class="text-right">{{ frappe.utils.fmt_money(item.AssAmt, None, "INR") }}</td>
- <td class="text-right" style="width: 7%;">{{ item.GstRt + item.CesRt }} %</td>
- <td class="text-right" style="width: 5%;">{{ frappe.utils.fmt_money(0, None, "INR") }}</td>
- <td class="text-right">{{ frappe.utils.fmt_money(item.TotItemVal, None, "INR") }}</td>
- </tr>
- {% endfor %}
- </tbody>
- </table>
- </div>
- <div style="overflow-x: auto;">
- <h5 class="font-bold" style="margin-bottom: 0px;">4. Value Details</h5>
- <table class="table table-bordered">
- <thead>
- <tr>
- <th class="text-left">Taxable Amount</th>
- <th class="text-left">CGST</th>
- <th class="text-left"">SGST</th>
- <th class="text-left">IGST</th>
- <th class="text-left">CESS</th>
- <th class="text-left" style="width: 10%;">State CESS</th>
- <th class="text-left">Discount</th>
- <th class="text-left" style="width: 10%;">Other Charges</th>
- <th class="text-left" style="width: 10%;">Round Off</th>
- <th class="text-left">Total Value</th>
- </tr>
- </thead>
- <tbody>
- {%- set value_details = einvoice.ValDtls -%}
- <tr>
- <td class="text-right">{{ frappe.utils.fmt_money(value_details.AssVal, None, "INR") }}</td>
- <td class="text-right">{{ frappe.utils.fmt_money(value_details.CgstVal, None, "INR") }}</td>
- <td class="text-right">{{ frappe.utils.fmt_money(value_details.SgstVal, None, "INR") }}</td>
- <td class="text-right">{{ frappe.utils.fmt_money(value_details.IgstVal, None, "INR") }}</td>
- <td class="text-right">{{ frappe.utils.fmt_money(value_details.CesVal, None, "INR") }}</td>
- <td class="text-right">{{ frappe.utils.fmt_money(0, None, "INR") }}</td>
- <td class="text-right">{{ frappe.utils.fmt_money(value_details.Discount, None, "INR") }}</td>
- <td class="text-right">{{ frappe.utils.fmt_money(value_details.OthChrg, None, "INR") }}</td>
- <td class="text-right">{{ frappe.utils.fmt_money(value_details.RndOffAmt, None, "INR") }}</td>
- <td class="text-right">{{ frappe.utils.fmt_money(value_details.TotInvVal, None, "INR") }}</td>
- </tr>
- </tbody>
- </table>
- </div>
-</div>
diff --git a/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.json b/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.json
deleted file mode 100644
index 1001199..0000000
--- a/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "align_labels_right": 1,
- "creation": "2020-10-10 18:01:21.032914",
- "custom_format": 0,
- "default_print_language": "en-US",
- "disabled": 1,
- "doc_type": "Sales Invoice",
- "docstatus": 0,
- "doctype": "Print Format",
- "font": "Default",
- "html": "",
- "idx": 0,
- "line_breaks": 1,
- "modified": "2020-10-23 19:54:40.634936",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "GST E-Invoice",
- "owner": "Administrator",
- "print_format_builder": 0,
- "print_format_type": "Jinja",
- "raw_printing": 0,
- "show_section_headings": 1,
- "standard": "Yes"
-}
\ No newline at end of file
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index b54646f..cedfc0f 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -535,6 +535,8 @@
if getdate(entry_date) > getdate(self.filters.report_date):
row.range1 = row.range2 = row.range3 = row.range4 = row.range5 = 0.0
+ row.total_due = row.range1 + row.range2 + row.range3 + row.range4 + row.range5
+
def get_ageing_data(self, entry_date, row):
# [0-30, 30-60, 60-90, 90-120, 120-above]
row.range1 = row.range2 = row.range3 = row.range4 = row.range5 = 0.0
diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
index e94b309..4bfb022 100644
--- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
+++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
@@ -82,6 +82,7 @@
"range3": 0.0,
"range4": 0.0,
"range5": 0.0,
+ "total_due": 0.0,
"sales_person": []
}))
@@ -135,3 +136,6 @@
"{range3}-{range4}".format(range3=cint(self.filters["range3"])+ 1, range4=self.filters["range4"]),
"{range4}-{above}".format(range4=cint(self.filters["range4"])+ 1, above=_("Above"))]):
self.add_column(label=label, fieldname='range' + str(i+1))
+
+ # Add column for total due amount
+ self.add_column(label="Total Amount Due", fieldname='total_due')
diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
index 56a67bb..fc42127 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
@@ -210,10 +210,10 @@
company_currency = get_company_currency(filters)
if filters.filter_based_on == 'Fiscal Year':
- start_date = fiscal_year.year_start_date
+ start_date = fiscal_year.year_start_date if filters.report != 'Balance Sheet' else None
end_date = fiscal_year.year_end_date
else:
- start_date = filters.period_start_date
+ start_date = filters.period_start_date if filters.report != 'Balance Sheet' else None
end_date = filters.period_end_date
gl_entries_by_account = {}
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index eca1e26..118f628 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -19,6 +19,7 @@
class StockValueAndAccountBalanceOutOfSync(frappe.ValidationError): pass
class FiscalYearError(frappe.ValidationError): pass
+class PaymentEntryUnlinkError(frappe.ValidationError): pass
@frappe.whitelist()
def get_fiscal_year(date=None, fiscal_year=None, label="Date", verbose=1, company=None, as_dict=False):
@@ -555,10 +556,16 @@
and docstatus < 2""", (now(), frappe.session.user, ref_type, ref_no))
for pe in linked_pe:
- pe_doc = frappe.get_doc("Payment Entry", pe)
- pe_doc.set_total_allocated_amount()
- pe_doc.set_unallocated_amount()
- pe_doc.clear_unallocated_reference_document_rows()
+ try:
+ pe_doc = frappe.get_doc("Payment Entry", pe)
+ pe_doc.set_amounts()
+ pe_doc.clear_unallocated_reference_document_rows()
+ pe_doc.validate_payment_type_with_outstanding()
+ except Exception as e:
+ msg = _("There were issues unlinking payment entry {0}.").format(pe_doc.name)
+ msg += '<br>'
+ msg += _("Please cancel payment entry manually first")
+ frappe.throw(msg, exc=PaymentEntryUnlinkError, title=_("Payment Unlink Error"))
frappe.db.sql("""update `tabPayment Entry` set total_allocated_amount=%s,
base_total_allocated_amount=%s, unallocated_amount=%s, modified=%s, modified_by=%s
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index bb0ad60..a55a0b7 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -565,6 +565,7 @@
"fieldname": "scan_barcode",
"fieldtype": "Data",
"label": "Scan Barcode",
+ "options": "Barcode",
"show_days": 1,
"show_seconds": 1
},
@@ -1378,7 +1379,7 @@
"idx": 105,
"is_submittable": 1,
"links": [],
- "modified": "2021-05-30 15:17:53.663648",
+ "modified": "2021-08-17 20:16:12.737743",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 4c243d0..01d354d 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -135,14 +135,9 @@
validate_regional(self)
- validate_einvoice_fields(self)
-
if self.doctype != 'Material Request':
apply_pricing_rule_on_transaction(self)
- def before_cancel(self):
- validate_einvoice_fields(self)
-
def on_trash(self):
# delete sl and gl entries on deletion of transaction
if frappe.db.get_single_value('Accounts Settings', 'delete_linked_ledger_entries'):
@@ -1841,6 +1836,11 @@
for d in data:
new_child_flag = False
+
+ if not d.get("item_code"):
+ # ignore empty rows
+ continue
+
if not d.get("docname"):
new_child_flag = True
check_doc_permissions(parent, 'create')
@@ -1975,7 +1975,3 @@
@erpnext.allow_regional
def validate_regional(doc):
pass
-
-@erpnext.allow_regional
-def validate_einvoice_fields(doc):
- pass
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 05edb25..7c6d355 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -595,7 +595,8 @@
self.doc.precision("outstanding_amount"))
if self.doc.doctype == 'Sales Invoice' and self.doc.get('is_pos') and self.doc.get('is_return'):
- self.update_paid_amount_for_return(total_amount_to_pay)
+ self.set_total_amount_to_default_mop(total_amount_to_pay)
+ self.calculate_paid_amount()
def calculate_paid_amount(self):
@@ -675,7 +676,7 @@
def set_item_wise_tax_breakup(self):
self.doc.other_charges_calculation = get_itemised_tax_breakup_html(self.doc)
- def update_paid_amount_for_return(self, total_amount_to_pay):
+ def set_total_amount_to_default_mop(self, total_amount_to_pay):
default_mode_of_payment = frappe.db.get_value('POS Payment Method',
{'parent': self.doc.pos_profile, 'default': 1}, ['mode_of_payment'], as_dict=1)
@@ -685,9 +686,7 @@
'mode_of_payment': default_mode_of_payment.mode_of_payment,
'amount': total_amount_to_pay,
'default': 1
- })
-
- self.calculate_paid_amount()
+ })
def get_itemised_tax_breakup_html(doc):
if not doc.taxes:
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 8f7c7db..74977cd 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -251,7 +251,7 @@
"erpnext.support.doctype.issue.issue.set_first_response_time"
]
},
- ("Sales Taxes and Charges Template", 'Price List'): {
+ "Sales Taxes and Charges Template": {
"on_update": "erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings.validate_cart_settings"
},
"Website Settings": {
@@ -308,6 +308,9 @@
},
('Quotation', 'Sales Order', 'Sales Invoice'): {
'validate': ["erpnext.erpnext_integrations.taxjar_integration.set_sales_tax"]
+ },
+ "Company": {
+ "on_trash": "erpnext.regional.india.utils.delete_gst_settings_for_company"
}
}
@@ -436,7 +439,6 @@
'erpnext.controllers.taxes_and_totals.get_regional_round_off_accounts': 'erpnext.regional.india.utils.get_regional_round_off_accounts',
'erpnext.hr.utils.calculate_annual_eligible_hra_exemption': 'erpnext.regional.india.utils.calculate_annual_eligible_hra_exemption',
'erpnext.hr.utils.calculate_hra_exemption_for_period': 'erpnext.regional.india.utils.calculate_hra_exemption_for_period',
- 'erpnext.controllers.accounts_controller.validate_einvoice_fields': 'erpnext.regional.india.e_invoice.utils.validate_einvoice_fields',
'erpnext.assets.doctype.asset.asset.get_depreciation_amount': 'erpnext.regional.india.utils.get_depreciation_amount',
'erpnext.stock.doctype.item.item.set_item_tax_from_hsn_code': 'erpnext.regional.india.utils.set_item_tax_from_hsn_code'
},
diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js
index 3f50b41..e72c8eb 100644
--- a/erpnext/manufacturing/doctype/bom/bom.js
+++ b/erpnext/manufacturing/doctype/bom/bom.js
@@ -235,7 +235,7 @@
reqd: 1,
},
{
- fieldname: "varint_item_code",
+ fieldname: "variant_item_code",
options: "Item",
label: __("Variant Item"),
fieldtype: "Link",
@@ -287,7 +287,7 @@
let variant_items = data.items || [];
variant_items.forEach(d => {
- if (!d.varint_item_code) {
+ if (!d.variant_item_code) {
frappe.throw(__("Select variant item code for the template item {0}", [d.item_code]));
}
})
@@ -299,7 +299,7 @@
has_template_rm.forEach(d => {
dialog.fields_dict.items.df.data.push({
"item_code": d.item_code,
- "varint_item_code": "",
+ "variant_item_code": "",
"qty": d.qty,
"source_warehouse": d.source_warehouse,
"operation": d.operation
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 8c27d6c..b4c6635 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -297,7 +297,7 @@
if self.total_produced_qty > 0:
self.status = "In Process"
- if self.total_produced_qty == self.total_planned_qty:
+ if self.total_produced_qty >= self.total_planned_qty:
self.status = "Completed"
if self.status != 'Completed':
@@ -346,6 +346,7 @@
"production_plan" : self.name,
"production_plan_item" : d.name,
"product_bundle_item" : d.product_bundle_item,
+ "planned_start_date" : d.planned_start_date,
"make_work_order_for_sub_assembly_items": d.get("make_work_order_for_sub_assembly_items", 0)
}
diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
index af8de8e..a5b9ff8 100644
--- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
@@ -5,7 +5,7 @@
import frappe
import unittest
-from frappe.utils import nowdate, now_datetime, flt
+from frappe.utils import nowdate, now_datetime, flt, add_to_date
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.manufacturing.doctype.production_plan.production_plan import get_sales_orders
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
@@ -61,6 +61,21 @@
pln = frappe.get_doc('Production Plan', pln.name)
pln.cancel()
+ def test_production_plan_start_date(self):
+ planned_date = add_to_date(date=None, days=3)
+ plan = create_production_plan(item_code='Test Production Item 1', planned_start_date=planned_date)
+ plan.make_work_order()
+
+ work_orders = frappe.get_all('Work Order', fields = ['name', 'planned_start_date'],
+ filters = {'production_plan': plan.name})
+
+ self.assertEqual(work_orders[0].planned_start_date, planned_date)
+
+ for wo in work_orders:
+ frappe.delete_doc('Work Order', wo.name)
+
+ frappe.get_doc('Production Plan', plan.name).cancel()
+
def test_production_plan_for_existing_ordered_qty(self):
sr1 = create_stock_reconciliation(item_code="Raw Material Item 1",
target="_Test Warehouse - _TC", qty=1, rate=110)
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index 282b5d0..5fe9fec 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -602,7 +602,7 @@
if self.docstatus==1:
# calculate transferred qty based on submitted stock entries
- self.update_transaferred_qty_for_required_items()
+ self.update_transferred_qty_for_required_items()
# update in bin
self.update_reserved_qty_for_production()
@@ -671,7 +671,7 @@
self.set_available_qty()
- def update_transaferred_qty_for_required_items(self):
+ def update_transferred_qty_for_required_items(self):
'''update transferred qty from submitted stock entries for that item against
the work order'''
@@ -838,7 +838,7 @@
for item in variant_items:
args = frappe._dict({
- "item_code": item.get("varint_item_code"),
+ "item_code": item.get("variant_item_code"),
"required_qty": item.get("qty"),
"qty": item.get("qty"), # for bom
"source_warehouse": item.get("source_warehouse"),
@@ -859,7 +859,7 @@
}, bom_doc)
if not args.source_warehouse:
- args["source_warehouse"] = get_item_defaults(item.get("varint_item_code"),
+ args["source_warehouse"] = get_item_defaults(item.get("variant_item_code"),
wo_doc.company).default_warehouse
args["amount"] = flt(args.get("required_qty")) * flt(args.get("rate"))
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 776b41d..b86c236 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -214,7 +214,6 @@
execute:frappe.delete_doc_if_exists("DocType", "Bank Reconciliation")
erpnext.patches.v13_0.move_doctype_reports_and_notification_from_hr_to_payroll #22-06-2020
erpnext.patches.v13_0.move_payroll_setting_separately_from_hr_settings #22-06-2020
-execute:frappe.reload_doc("regional", "doctype", "e_invoice_settings")
erpnext.patches.v13_0.check_is_income_tax_component #22-06-2020
erpnext.patches.v13_0.loyalty_points_entry_for_pos_invoice #22-07-2020
erpnext.patches.v12_0.add_taxjar_integration_field
@@ -237,7 +236,6 @@
erpnext.patches.v13_0.print_uom_after_quantity_patch
erpnext.patches.v13_0.set_payment_channel_in_payment_gateway_account
erpnext.patches.v13_0.create_healthcare_custom_fields_in_stock_entry_detail
-erpnext.patches.v12_0.setup_einvoice_fields #2020-12-02
erpnext.patches.v13_0.updates_for_multi_currency_payroll
erpnext.patches.v13_0.update_reason_for_resignation_in_employee
execute:frappe.delete_doc("Report", "Quoted Item Comparison")
@@ -259,14 +257,11 @@
erpnext.patches.v13_0.item_reposting_for_incorrect_sl_and_gl
erpnext.patches.v13_0.delete_old_bank_reconciliation_doctypes
erpnext.patches.v12_0.update_vehicle_no_reqd_condition
-erpnext.patches.v12_0.add_einvoice_status_field #2021-03-17
-erpnext.patches.v12_0.add_einvoice_summary_report_permissions
erpnext.patches.v13_0.setup_fields_for_80g_certificate_and_donation
erpnext.patches.v13_0.rename_membership_settings_to_non_profit_settings
erpnext.patches.v13_0.setup_gratuity_rule_for_india_and_uae
erpnext.patches.v13_0.setup_uae_vat_fields
execute:frappe.db.set_value('System Settings', None, 'app_name', 'ERPNext')
-erpnext.patches.v12_0.add_company_link_to_einvoice_settings
erpnext.patches.v13_0.rename_discharge_date_in_ip_record
erpnext.patches.v12_0.create_taxable_value_field
erpnext.patches.v12_0.add_gst_category_in_delivery_note
@@ -277,7 +272,6 @@
erpnext.patches.v13_0.make_non_standard_user_type #13-04-2021
erpnext.patches.v13_0.update_shipment_status
erpnext.patches.v13_0.remove_attribute_field_from_item_variant_setting
-erpnext.patches.v12_0.add_ewaybill_validity_field
erpnext.patches.v13_0.germany_make_custom_fields
erpnext.patches.v13_0.germany_fill_debtor_creditor_number
erpnext.patches.v13_0.set_pos_closing_as_failed
@@ -294,10 +288,11 @@
erpnext.patches.v13_0.add_missing_fg_item_for_stock_entry
erpnext.patches.v13_0.update_subscription_status_in_memberships
erpnext.patches.v13_0.update_amt_in_work_order_required_items
-erpnext.patches.v12_0.show_einvoice_irn_cancelled_field
erpnext.patches.v13_0.delete_orphaned_tables
erpnext.patches.v13_0.update_export_type_for_gst #2021-08-16
erpnext.patches.v13_0.update_tds_check_field #3
erpnext.patches.v13_0.add_custom_field_for_south_africa #2
erpnext.patches.v13_0.update_recipient_email_digest
erpnext.patches.v13_0.shopify_deprecation_warning
+erpnext.patches.v13_0.einvoicing_deprecation_warning
+erpnext.patches.v14_0.delete_einvoicing_doctypes
diff --git a/erpnext/patches/v12_0/add_company_link_to_einvoice_settings.py b/erpnext/patches/v12_0/add_company_link_to_einvoice_settings.py
deleted file mode 100644
index c2ed6c2..0000000
--- a/erpnext/patches/v12_0/add_company_link_to_einvoice_settings.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from __future__ import unicode_literals
-import frappe
-
-def execute():
- company = frappe.get_all('Company', filters = {'country': 'India'})
- if not company or not frappe.db.count('E Invoice User'):
- return
-
- frappe.reload_doc("regional", "doctype", "e_invoice_user")
- for creds in frappe.db.get_all('E Invoice User', fields=['name', 'gstin']):
- company_name = frappe.db.sql("""
- select dl.link_name from `tabAddress` a, `tabDynamic Link` dl
- where a.gstin = %s and dl.parent = a.name and dl.link_doctype = 'Company'
- """, (creds.get('gstin')))
- if company_name and len(company_name) > 0:
- frappe.db.set_value('E Invoice User', creds.get('name'), 'company', company_name[0][0])
diff --git a/erpnext/patches/v12_0/add_einvoice_status_field.py b/erpnext/patches/v12_0/add_einvoice_status_field.py
deleted file mode 100644
index 2dfd307..0000000
--- a/erpnext/patches/v12_0/add_einvoice_status_field.py
+++ /dev/null
@@ -1,69 +0,0 @@
-from __future__ import unicode_literals
-import json
-import frappe
-from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
-
-def execute():
- company = frappe.get_all('Company', filters = {'country': 'India'})
- if not company:
- return
-
- # move hidden einvoice fields to a different section
- custom_fields = {
- 'Sales Invoice': [
- dict(fieldname='einvoice_section', label='E-Invoice Fields', fieldtype='Section Break', insert_after='gst_vehicle_type',
- print_hide=1, hidden=1),
-
- dict(fieldname='ack_no', label='Ack. No.', fieldtype='Data', read_only=1, hidden=1, insert_after='einvoice_section',
- no_copy=1, print_hide=1),
-
- dict(fieldname='ack_date', label='Ack. Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_no', no_copy=1, print_hide=1),
-
- dict(fieldname='irn_cancel_date', label='Cancel Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_date',
- no_copy=1, print_hide=1),
-
- dict(fieldname='signed_einvoice', label='Signed E-Invoice', fieldtype='Code', options='JSON', hidden=1, insert_after='irn_cancel_date',
- no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='signed_qr_code', label='Signed QRCode', fieldtype='Code', options='JSON', hidden=1, insert_after='signed_einvoice',
- no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='qrcode_image', label='QRCode', fieldtype='Attach Image', hidden=1, insert_after='signed_qr_code',
- no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='einvoice_status', label='E-Invoice Status', fieldtype='Select', insert_after='qrcode_image',
- options='\nPending\nGenerated\nCancelled\nFailed', default=None, hidden=1, no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='failure_description', label='E-Invoice Failure Description', fieldtype='Code', options='JSON',
- hidden=1, insert_after='einvoice_status', no_copy=1, print_hide=1, read_only=1)
- ]
- }
- create_custom_fields(custom_fields, update=True)
-
- if frappe.db.exists('E Invoice Settings') and frappe.db.get_single_value('E Invoice Settings', 'enable'):
- frappe.db.sql('''
- UPDATE `tabSales Invoice` SET einvoice_status = 'Pending'
- WHERE
- posting_date >= '2021-04-01'
- AND ifnull(irn, '') = ''
- AND ifnull(`billing_address_gstin`, '') != ifnull(`company_gstin`, '')
- AND ifnull(gst_category, '') in ('Registered Regular', 'SEZ', 'Overseas', 'Deemed Export')
- ''')
-
- # set appropriate statuses
- frappe.db.sql('''UPDATE `tabSales Invoice` SET einvoice_status = 'Generated'
- WHERE ifnull(irn, '') != '' AND ifnull(irn_cancelled, 0) = 0''')
-
- frappe.db.sql('''UPDATE `tabSales Invoice` SET einvoice_status = 'Cancelled'
- WHERE ifnull(irn_cancelled, 0) = 1''')
-
- # set correct acknowledgement in e-invoices
- einvoices = frappe.get_all('Sales Invoice', {'irn': ['is', 'set']}, ['name', 'signed_einvoice'])
-
- if einvoices:
- for inv in einvoices:
- signed_einvoice = inv.get('signed_einvoice')
- if signed_einvoice:
- signed_einvoice = json.loads(signed_einvoice)
- frappe.db.set_value('Sales Invoice', inv.get('name'), 'ack_no', signed_einvoice.get('AckNo'), update_modified=False)
- frappe.db.set_value('Sales Invoice', inv.get('name'), 'ack_date', signed_einvoice.get('AckDt'), update_modified=False)
diff --git a/erpnext/patches/v12_0/add_einvoice_summary_report_permissions.py b/erpnext/patches/v12_0/add_einvoice_summary_report_permissions.py
deleted file mode 100644
index c1c11e2..0000000
--- a/erpnext/patches/v12_0/add_einvoice_summary_report_permissions.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from __future__ import unicode_literals
-import frappe
-
-def execute():
- company = frappe.get_all('Company', filters = {'country': 'India'})
- if not company:
- return
-
- if frappe.db.exists('Report', 'E-Invoice Summary') and \
- not frappe.db.get_value('Custom Role', dict(report='E-Invoice Summary')):
- frappe.get_doc(dict(
- doctype='Custom Role',
- report='E-Invoice Summary',
- roles= [
- dict(role='Accounts User'),
- dict(role='Accounts Manager')
- ]
- )).insert()
diff --git a/erpnext/patches/v12_0/add_ewaybill_validity_field.py b/erpnext/patches/v12_0/add_ewaybill_validity_field.py
deleted file mode 100644
index f29b714..0000000
--- a/erpnext/patches/v12_0/add_ewaybill_validity_field.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from __future__ import unicode_literals
-import frappe
-from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
-
-def execute():
- company = frappe.get_all('Company', filters = {'country': 'India'})
- if not company:
- return
-
- custom_fields = {
- 'Sales Invoice': [
- dict(fieldname='eway_bill_validity', label='E-Way Bill Validity', fieldtype='Data', no_copy=1, print_hide=1,
- depends_on='ewaybill', read_only=1, allow_on_submit=1, insert_after='ewaybill')
- ]
- }
- create_custom_fields(custom_fields, update=True)
diff --git a/erpnext/patches/v12_0/setup_einvoice_fields.py b/erpnext/patches/v12_0/setup_einvoice_fields.py
deleted file mode 100644
index 82b14fc..0000000
--- a/erpnext/patches/v12_0/setup_einvoice_fields.py
+++ /dev/null
@@ -1,56 +0,0 @@
-from __future__ import unicode_literals
-import frappe
-from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
-from erpnext.regional.india.setup import add_permissions, add_print_formats
-
-def execute():
- company = frappe.get_all('Company', filters = {'country': 'India'})
- if not company:
- return
-
- frappe.reload_doc("custom", "doctype", "custom_field")
- frappe.reload_doc("regional", "doctype", "e_invoice_settings")
- custom_fields = {
- 'Sales Invoice': [
- dict(fieldname='irn', label='IRN', fieldtype='Data', read_only=1, insert_after='customer', no_copy=1, print_hide=1,
- depends_on='eval:in_list(["Registered Regular", "SEZ", "Overseas", "Deemed Export"], doc.gst_category) && doc.irn_cancelled === 0'),
-
- dict(fieldname='ack_no', label='Ack. No.', fieldtype='Data', read_only=1, hidden=1, insert_after='irn', no_copy=1, print_hide=1),
-
- dict(fieldname='ack_date', label='Ack. Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_no', no_copy=1, print_hide=1),
-
- dict(fieldname='irn_cancelled', label='IRN Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
- depends_on='eval:(doc.irn_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
-
- dict(fieldname='eway_bill_cancelled', label='E-Way Bill Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
- depends_on='eval:(doc.eway_bill_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
-
- dict(fieldname='signed_einvoice', fieldtype='Code', options='JSON', hidden=1, no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='signed_qr_code', fieldtype='Code', options='JSON', hidden=1, no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='qrcode_image', label='QRCode', fieldtype='Attach Image', hidden=1, no_copy=1, print_hide=1, read_only=1)
- ]
- }
- create_custom_fields(custom_fields, update=True)
- add_permissions()
- add_print_formats()
-
- einvoice_cond = 'in_list(["Registered Regular", "SEZ", "Overseas", "Deemed Export"], doc.gst_category)'
- t = {
- 'mode_of_transport': [{'default': None}],
- 'distance': [{'mandatory_depends_on': f'eval:{einvoice_cond} && doc.transporter'}],
- 'gst_vehicle_type': [{'mandatory_depends_on': f'eval:{einvoice_cond} && doc.mode_of_transport == "Road"'}],
- 'lr_date': [{'mandatory_depends_on': f'eval:{einvoice_cond} && in_list(["Air", "Ship", "Rail"], doc.mode_of_transport)'}],
- 'lr_no': [{'mandatory_depends_on': f'eval:{einvoice_cond} && in_list(["Air", "Ship", "Rail"], doc.mode_of_transport)'}],
- 'vehicle_no': [{'mandatory_depends_on': f'eval:{einvoice_cond} && doc.mode_of_transport == "Road"'}],
- 'ewaybill': [
- {'read_only_depends_on': 'eval:doc.irn && doc.ewaybill'},
- {'depends_on': 'eval:((doc.docstatus === 1 || doc.ewaybill) && doc.eway_bill_cancelled === 0)'}
- ]
- }
-
- for field, conditions in t.items():
- for c in conditions:
- [(prop, value)] = c.items()
- frappe.db.set_value('Custom Field', { 'fieldname': field }, prop, value)
diff --git a/erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py b/erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py
deleted file mode 100644
index 2319c17..0000000
--- a/erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from __future__ import unicode_literals
-import frappe
-
-def execute():
- company = frappe.get_all('Company', filters = {'country': 'India'})
- if not company:
- return
-
- irn_cancelled_field = frappe.db.exists('Custom Field', {'dt': 'Sales Invoice', 'fieldname': 'irn_cancelled'})
- if irn_cancelled_field:
- frappe.db.set_value('Custom Field', irn_cancelled_field, 'depends_on', 'eval: doc.irn')
- frappe.db.set_value('Custom Field', irn_cancelled_field, 'read_only', 0)
diff --git a/erpnext/patches/v13_0/einvoicing_deprecation_warning.py b/erpnext/patches/v13_0/einvoicing_deprecation_warning.py
new file mode 100644
index 0000000..e123a55
--- /dev/null
+++ b/erpnext/patches/v13_0/einvoicing_deprecation_warning.py
@@ -0,0 +1,9 @@
+import click
+
+
+def execute():
+ click.secho(
+ "Indian E-Invoicing integration is moved to a separate app and will be removed from ERPNext in version-14.\n"
+ "Please install the app to continue using the integration: https://github.com/frappe/erpnext_gst_compliance",
+ fg="yellow",
+ )
diff --git a/erpnext/regional/india/e_invoice/__init__.py b/erpnext/patches/v14_0/__init__.py
similarity index 100%
rename from erpnext/regional/india/e_invoice/__init__.py
rename to erpnext/patches/v14_0/__init__.py
diff --git a/erpnext/patches/v14_0/delete_einvoicing_doctypes.py b/erpnext/patches/v14_0/delete_einvoicing_doctypes.py
new file mode 100644
index 0000000..b77d244
--- /dev/null
+++ b/erpnext/patches/v14_0/delete_einvoicing_doctypes.py
@@ -0,0 +1,9 @@
+import frappe
+
+def execute():
+ frappe.delete_doc('DocType', 'E Invoice Settings', ignore_missing=True)
+ frappe.delete_doc('DocType', 'E Invoice User', ignore_missing=True)
+ frappe.delete_doc('Report', 'E-Invoice Summary', ignore_missing=True)
+ frappe.delete_doc('Print Format', 'GST E-Invoice', ignore_missing=True)
+ frappe.delete_doc('Custom Field', 'Sales Invoice-eway_bill_cancelled', ignore_missing=True)
+ frappe.delete_doc('Custom Field', 'Sales Invoice-irn_cancelled', ignore_missing=True)
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/salary_component/salary_component.js b/erpnext/payroll/doctype/salary_component/salary_component.js
index e9e6f81..dbf7514 100644
--- a/erpnext/payroll/doctype/salary_component/salary_component.js
+++ b/erpnext/payroll/doctype/salary_component/salary_component.js
@@ -4,18 +4,11 @@
frappe.ui.form.on('Salary Component', {
setup: function(frm) {
frm.set_query("account", "accounts", function(doc, cdt, cdn) {
- let d = frappe.get_doc(cdt, cdn);
-
- let root_type = "Liability";
- if (frm.doc.type == "Deduction") {
- root_type = "Expense";
- }
-
+ var d = locals[cdt][cdn];
return {
filters: {
"is_group": 0,
- "company": d.company,
- "root_type": root_type
+ "company": d.company
}
};
});
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index e8f3122..702064f 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -754,8 +754,6 @@
}
});
this.frm.refresh_fields();
-
- this.calculate_paid_amount();
}
set_default_payment(total_amount_to_pay, update_paid_amount) {
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 3c6c347..2538852 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -342,30 +342,6 @@
this.set_dynamic_labels();
this.setup_sms();
this.setup_quality_inspection();
- let scan_barcode_field = this.frm.get_field('scan_barcode');
- if (scan_barcode_field && scan_barcode_field.get_value()) {
- scan_barcode_field.set_value("");
- scan_barcode_field.set_new_description("");
-
- if (frappe.is_mobile()) {
- if (scan_barcode_field.$input_wrapper.find('.input-group').length) return;
-
- let $input_group = $('<div class="input-group">');
- scan_barcode_field.$input_wrapper.find('.control-input').append($input_group);
- $input_group.append(scan_barcode_field.$input);
- $(`<span class="input-group-btn" style="vertical-align: top">
- <button class="btn btn-default border" type="button">
- <i class="fa fa-camera text-muted"></i>
- </button>
- </span>`)
- .on('click', '.btn', () => {
- frappe.barcode.scan_barcode().then(barcode => {
- scan_barcode_field.set_value(barcode);
- });
- })
- .appendTo($input_group);
- }
- }
}
scan_barcode() {
@@ -2266,12 +2242,19 @@
coupon_code() {
var me = this;
- frappe.run_serially([
- () => this.frm.doc.ignore_pricing_rule=1,
- () => me.ignore_pricing_rule(),
- () => this.frm.doc.ignore_pricing_rule=0,
- () => me.apply_pricing_rule()
- ]);
+ if (this.frm.doc.coupon_code) {
+ frappe.run_serially([
+ () => this.frm.doc.ignore_pricing_rule=1,
+ () => me.ignore_pricing_rule(),
+ () => this.frm.doc.ignore_pricing_rule=0,
+ () => me.apply_pricing_rule()
+ ]);
+ } else {
+ frappe.run_serially([
+ () => this.frm.doc.ignore_pricing_rule=1,
+ () => me.ignore_pricing_rule()
+ ]);
+ }
}
};
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index f1b9235..f240b8c 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -563,7 +563,7 @@
},
],
primary_action: function() {
- const trans_items = this.get_values()["trans_items"];
+ const trans_items = this.get_values()["trans_items"].filter((item) => !!item.item_code);
frappe.call({
method: 'erpnext.controllers.accounts_controller.update_child_qty_rate',
freeze: true,
diff --git a/erpnext/public/scss/point-of-sale.scss b/erpnext/public/scss/point-of-sale.scss
index c77b2ce..1677e9b 100644
--- a/erpnext/public/scss/point-of-sale.scss
+++ b/erpnext/public/scss/point-of-sale.scss
@@ -860,6 +860,8 @@
.invoice-fields {
overflow-y: scroll;
+ height: 100%;
+ padding-right: var(--padding-sm);
}
}
diff --git a/erpnext/regional/doctype/e_invoice_request_log/__init__.py b/erpnext/regional/doctype/e_invoice_request_log/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/regional/doctype/e_invoice_request_log/__init__.py
+++ /dev/null
diff --git a/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.js b/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.js
deleted file mode 100644
index 7b7ba96..0000000
--- a/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('E Invoice Request Log', {
- // refresh: function(frm) {
-
- // }
-});
diff --git a/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.json b/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.json
deleted file mode 100644
index 3034370..0000000
--- a/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.json
+++ /dev/null
@@ -1,102 +0,0 @@
-{
- "actions": [],
- "autoname": "EINV-REQ-.#####",
- "creation": "2020-12-08 12:54:08.175992",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "user",
- "url",
- "headers",
- "response",
- "column_break_7",
- "timestamp",
- "reference_invoice",
- "data"
- ],
- "fields": [
- {
- "fieldname": "user",
- "fieldtype": "Link",
- "label": "User",
- "options": "User"
- },
- {
- "fieldname": "reference_invoice",
- "fieldtype": "Data",
- "label": "Reference Invoice"
- },
- {
- "fieldname": "headers",
- "fieldtype": "Code",
- "label": "Headers",
- "options": "JSON"
- },
- {
- "fieldname": "data",
- "fieldtype": "Code",
- "label": "Data",
- "options": "JSON"
- },
- {
- "default": "Now",
- "fieldname": "timestamp",
- "fieldtype": "Datetime",
- "label": "Timestamp"
- },
- {
- "fieldname": "response",
- "fieldtype": "Code",
- "label": "Response",
- "options": "JSON"
- },
- {
- "fieldname": "url",
- "fieldtype": "Data",
- "label": "URL"
- },
- {
- "fieldname": "column_break_7",
- "fieldtype": "Column Break"
- }
- ],
- "index_web_pages_for_search": 1,
- "links": [],
- "modified": "2021-01-13 12:06:57.253111",
- "modified_by": "Administrator",
- "module": "Regional",
- "name": "E Invoice Request Log",
- "owner": "Administrator",
- "permissions": [
- {
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "share": 1
- },
- {
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts User",
- "share": 1
- },
- {
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts Manager",
- "share": 1
- }
- ],
- "sort_field": "modified",
- "sort_order": "DESC"
-}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.py b/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.py
deleted file mode 100644
index 9150bdd..0000000
--- a/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-# import frappe
-from frappe.model.document import Document
-
-class EInvoiceRequestLog(Document):
- pass
diff --git a/erpnext/regional/doctype/e_invoice_request_log/test_e_invoice_request_log.py b/erpnext/regional/doctype/e_invoice_request_log/test_e_invoice_request_log.py
deleted file mode 100644
index c84e9a2..0000000
--- a/erpnext/regional/doctype/e_invoice_request_log/test_e_invoice_request_log.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-# import frappe
-import unittest
-
-class TestEInvoiceRequestLog(unittest.TestCase):
- pass
diff --git a/erpnext/regional/doctype/e_invoice_settings/__init__.py b/erpnext/regional/doctype/e_invoice_settings/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/regional/doctype/e_invoice_settings/__init__.py
+++ /dev/null
diff --git a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.js b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.js
deleted file mode 100644
index 54e4886..0000000
--- a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('E Invoice Settings', {
- refresh(frm) {
- const docs_link = 'https://docs.erpnext.com/docs/v13/user/manual/en/regional/india/setup-e-invoicing';
- frm.dashboard.set_headline(
- __("Read {0} for more information on E Invoicing features.", [`<a href='${docs_link}'>documentation</a>`])
- );
- }
-});
diff --git a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.json b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.json
deleted file mode 100644
index 68ed339..0000000
--- a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.json
+++ /dev/null
@@ -1,73 +0,0 @@
-{
- "actions": [],
- "creation": "2020-09-24 16:23:16.235722",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "enable",
- "section_break_2",
- "sandbox_mode",
- "applicable_from",
- "credentials",
- "auth_token",
- "token_expiry"
- ],
- "fields": [
- {
- "default": "0",
- "fieldname": "enable",
- "fieldtype": "Check",
- "label": "Enable"
- },
- {
- "depends_on": "enable",
- "fieldname": "section_break_2",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "auth_token",
- "fieldtype": "Data",
- "hidden": 1,
- "read_only": 1
- },
- {
- "fieldname": "token_expiry",
- "fieldtype": "Datetime",
- "hidden": 1,
- "read_only": 1
- },
- {
- "fieldname": "credentials",
- "fieldtype": "Table",
- "label": "Credentials",
- "mandatory_depends_on": "enable",
- "options": "E Invoice User"
- },
- {
- "default": "0",
- "fieldname": "sandbox_mode",
- "fieldtype": "Check",
- "label": "Sandbox Mode"
- },
- {
- "fieldname": "applicable_from",
- "fieldtype": "Date",
- "in_list_view": 1,
- "label": "Applicable From",
- "reqd": 1
- }
- ],
- "index_web_pages_for_search": 1,
- "issingle": 1,
- "links": [],
- "modified": "2021-03-30 12:26:25.538294",
- "modified_by": "Administrator",
- "module": "Regional",
- "name": "E Invoice Settings",
- "owner": "Administrator",
- "permissions": [],
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py
deleted file mode 100644
index 4f6b3ec..0000000
--- a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-from __future__ import unicode_literals
-
-import frappe
-from frappe import _
-from frappe.model.document import Document
-
-class EInvoiceSettings(Document):
- def validate(self):
- if self.enable and not self.credentials:
- frappe.throw(_('You must add atleast one credentials to be able to use E Invoicing.'))
diff --git a/erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py b/erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py
deleted file mode 100644
index a11ce63..0000000
--- a/erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-# import frappe
-import unittest
-
-class TestEInvoiceSettings(unittest.TestCase):
- pass
diff --git a/erpnext/regional/doctype/e_invoice_user/__init__.py b/erpnext/regional/doctype/e_invoice_user/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/regional/doctype/e_invoice_user/__init__.py
+++ /dev/null
diff --git a/erpnext/regional/doctype/e_invoice_user/e_invoice_user.json b/erpnext/regional/doctype/e_invoice_user/e_invoice_user.json
deleted file mode 100644
index a65b1ca..0000000
--- a/erpnext/regional/doctype/e_invoice_user/e_invoice_user.json
+++ /dev/null
@@ -1,57 +0,0 @@
-{
- "actions": [],
- "creation": "2020-12-22 15:02:46.229474",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "company",
- "gstin",
- "username",
- "password"
- ],
- "fields": [
- {
- "fieldname": "gstin",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "GSTIN",
- "reqd": 1
- },
- {
- "fieldname": "username",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "Username",
- "reqd": 1
- },
- {
- "fieldname": "password",
- "fieldtype": "Password",
- "in_list_view": 1,
- "label": "Password",
- "reqd": 1
- },
- {
- "fieldname": "company",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Company",
- "options": "Company",
- "reqd": 1
- }
- ],
- "index_web_pages_for_search": 1,
- "istable": 1,
- "links": [],
- "modified": "2021-03-22 12:16:56.365616",
- "modified_by": "Administrator",
- "module": "Regional",
- "name": "E Invoice User",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/e_invoice_user/e_invoice_user.py b/erpnext/regional/doctype/e_invoice_user/e_invoice_user.py
deleted file mode 100644
index 056c54f..0000000
--- a/erpnext/regional/doctype/e_invoice_user/e_invoice_user.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-# import frappe
-from frappe.model.document import Document
-
-class EInvoiceUser(Document):
- pass
diff --git a/erpnext/regional/india/e_invoice/einv_item_template.json b/erpnext/regional/india/e_invoice/einv_item_template.json
deleted file mode 100644
index 78e5651..0000000
--- a/erpnext/regional/india/e_invoice/einv_item_template.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{{
- "SlNo": "{item.sr_no}",
- "PrdDesc": "{item.description}",
- "IsServc": "{item.is_service_item}",
- "HsnCd": "{item.gst_hsn_code}",
- "Barcde": "{item.barcode}",
- "Unit": "{item.uom}",
- "Qty": "{item.qty}",
- "FreeQty": "{item.free_qty}",
- "UnitPrice": "{item.unit_rate}",
- "TotAmt": "{item.gross_amount}",
- "Discount": "{item.discount_amount}",
- "AssAmt": "{item.taxable_value}",
- "PrdSlNo": "{item.serial_no}",
- "GstRt": "{item.tax_rate}",
- "IgstAmt": "{item.igst_amount}",
- "CgstAmt": "{item.cgst_amount}",
- "SgstAmt": "{item.sgst_amount}",
- "CesRt": "{item.cess_rate}",
- "CesAmt": "{item.cess_amount}",
- "CesNonAdvlAmt": "{item.cess_nadv_amount}",
- "StateCesRt": "{item.state_cess_rate}",
- "StateCesAmt": "{item.state_cess_amount}",
- "StateCesNonAdvlAmt": "{item.state_cess_nadv_amount}",
- "OthChrg": "{item.other_charges}",
- "TotItemVal": "{item.total_value}",
- "BchDtls": {{
- "Nm": "{item.batch_no}",
- "ExpDt": "{item.batch_expiry_date}"
- }}
-}}
\ No newline at end of file
diff --git a/erpnext/regional/india/e_invoice/einv_template.json b/erpnext/regional/india/e_invoice/einv_template.json
deleted file mode 100644
index 60f490d..0000000
--- a/erpnext/regional/india/e_invoice/einv_template.json
+++ /dev/null
@@ -1,110 +0,0 @@
-{{
- "Version": "1.1",
- "TranDtls": {{
- "TaxSch": "{transaction_details.tax_scheme}",
- "SupTyp": "{transaction_details.supply_type}",
- "RegRev": "{transaction_details.reverse_charge}",
- "EcmGstin": "{transaction_details.ecom_gstin}",
- "IgstOnIntra": "{transaction_details.igst_on_intra}"
- }},
- "DocDtls": {{
- "Typ": "{doc_details.invoice_type}",
- "No": "{doc_details.invoice_name}",
- "Dt": "{doc_details.invoice_date}"
- }},
- "SellerDtls": {{
- "Gstin": "{seller_details.gstin}",
- "LglNm": "{seller_details.legal_name}",
- "TrdNm": "{seller_details.trade_name}",
- "Loc": "{seller_details.location}",
- "Pin": "{seller_details.pincode}",
- "Stcd": "{seller_details.state_code}",
- "Addr1": "{seller_details.address_line1}",
- "Addr2": "{seller_details.address_line2}",
- "Ph": "{seller_details.phone}",
- "Em": "{seller_details.email}"
- }},
- "BuyerDtls": {{
- "Gstin": "{buyer_details.gstin}",
- "LglNm": "{buyer_details.legal_name}",
- "TrdNm": "{buyer_details.trade_name}",
- "Addr1": "{buyer_details.address_line1}",
- "Addr2": "{buyer_details.address_line2}",
- "Loc": "{buyer_details.location}",
- "Pin": "{buyer_details.pincode}",
- "Stcd": "{buyer_details.state_code}",
- "Ph": "{buyer_details.phone}",
- "Em": "{buyer_details.email}",
- "Pos": "{buyer_details.place_of_supply}"
- }},
- "DispDtls": {{
- "Nm": "{dispatch_details.company_name}",
- "Addr1": "{dispatch_details.address_line1}",
- "Addr2": "{dispatch_details.address_line2}",
- "Loc": "{dispatch_details.location}",
- "Pin": "{dispatch_details.pincode}",
- "Stcd": "{dispatch_details.state_code}"
- }},
- "ShipDtls": {{
- "Gstin": "{shipping_details.gstin}",
- "LglNm": "{shipping_details.legal_name}",
- "TrdNm": "{shipping_details.trader_name}",
- "Addr1": "{shipping_details.address_line1}",
- "Addr2": "{shipping_details.address_line2}",
- "Loc": "{shipping_details.location}",
- "Pin": "{shipping_details.pincode}",
- "Stcd": "{shipping_details.state_code}"
- }},
- "ItemList": [
- {item_list}
- ],
- "ValDtls": {{
- "AssVal": "{invoice_value_details.base_total}",
- "CgstVal": "{invoice_value_details.total_cgst_amt}",
- "SgstVal": "{invoice_value_details.total_sgst_amt}",
- "IgstVal": "{invoice_value_details.total_igst_amt}",
- "CesVal": "{invoice_value_details.total_cess_amt}",
- "Discount": "{invoice_value_details.invoice_discount_amt}",
- "RndOffAmt": "{invoice_value_details.round_off}",
- "OthChrg": "{invoice_value_details.total_other_charges}",
- "TotInvVal": "{invoice_value_details.base_grand_total}",
- "TotInvValFc": "{invoice_value_details.grand_total}"
- }},
- "PayDtls": {{
- "Nm": "{payment_details.payee_name}",
- "AccDet": "{payment_details.account_no}",
- "Mode": "{payment_details.mode_of_payment}",
- "FinInsBr": "{payment_details.ifsc_code}",
- "PayTerm": "{payment_details.terms}",
- "PaidAmt": "{payment_details.paid_amount}",
- "PaymtDue": "{payment_details.outstanding_amount}"
- }},
- "RefDtls": {{
- "DocPerdDtls": {{
- "InvStDt": "{period_details.start_date}",
- "InvEndDt": "{period_details.end_date}"
- }},
- "PrecDocDtls": [{{
- "InvNo": "{prev_doc_details.invoice_name}",
- "InvDt": "{prev_doc_details.invoice_date}"
- }}]
- }},
- "ExpDtls": {{
- "ShipBNo": "{export_details.bill_no}",
- "ShipBDt": "{export_details.bill_date}",
- "Port": "{export_details.port}",
- "ForCur": "{export_details.foreign_curr_code}",
- "CntCode": "{export_details.country_code}",
- "ExpDuty": "{export_details.export_duty}"
- }},
- "EwbDtls": {{
- "TransId": "{eway_bill_details.gstin}",
- "TransName": "{eway_bill_details.name}",
- "TransMode": "{eway_bill_details.mode_of_transport}",
- "Distance": "{eway_bill_details.distance}",
- "TransDocNo": "{eway_bill_details.document_name}",
- "TransDocDt": "{eway_bill_details.document_date}",
- "VehNo": "{eway_bill_details.vehicle_no}",
- "VehType": "{eway_bill_details.vehicle_type}"
- }}
-}}
\ No newline at end of file
diff --git a/erpnext/regional/india/e_invoice/einv_validation.json b/erpnext/regional/india/e_invoice/einv_validation.json
deleted file mode 100644
index f4a3542..0000000
--- a/erpnext/regional/india/e_invoice/einv_validation.json
+++ /dev/null
@@ -1,957 +0,0 @@
-{
- "Version": {
- "type": "string",
- "minLength": 1,
- "maxLength": 6,
- "description": "Version of the schema"
- },
- "Irn": {
- "type": "string",
- "minLength": 64,
- "maxLength": 64,
- "description": "Invoice Reference Number"
- },
- "TranDtls": {
- "type": "object",
- "properties": {
- "TaxSch": {
- "type": "string",
- "minLength": 3,
- "maxLength": 10,
- "enum": ["GST"],
- "description": "GST- Goods and Services Tax Scheme"
- },
- "SupTyp": {
- "type": "string",
- "minLength": 3,
- "maxLength": 10,
- "enum": ["B2B", "SEZWP", "SEZWOP", "EXPWP", "EXPWOP", "DEXP"],
- "description": "Type of Supply: B2B-Business to Business, SEZWP - SEZ with payment, SEZWOP - SEZ without payment, EXPWP - Export with Payment, EXPWOP - Export without payment,DEXP - Deemed Export"
- },
- "RegRev": {
- "type": "string",
- "minLength": 1,
- "maxLength": 1,
- "enum": ["Y", "N"],
- "description": "Y- whether the tax liability is payable under reverse charge"
- },
- "EcmGstin": {
- "type": "string",
- "minLength": 15,
- "maxLength": 15,
- "pattern": "([0-9]{2}[0-9A-Z]{13})",
- "description": "E-Commerce GSTIN",
- "validationMsg": "E-Commerce GSTIN is invalid"
- },
- "IgstOnIntra": {
- "type": "string",
- "minLength": 1,
- "maxLength": 1,
- "enum": ["Y", "N"],
- "description": "Y- indicates the supply is intra state but chargeable to IGST"
- }
- },
- "required": ["TaxSch", "SupTyp"]
- },
- "DocDtls": {
- "type": "object",
- "properties": {
- "Typ": {
- "type": "string",
- "minLength": 3,
- "maxLength": 3,
- "enum": ["INV", "CRN", "DBN"],
- "description": "Document Type"
- },
- "No": {
- "type": "string",
- "minLength": 1,
- "maxLength": 16,
- "pattern": "^([A-Z1-9]{1}[A-Z0-9/-]{0,15})$",
- "description": "Document Number",
- "validationMsg": "Document Number should not be starting with 0, / and -"
- },
- "Dt": {
- "type": "string",
- "minLength": 10,
- "maxLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "Document Date"
- }
- },
- "required": ["Typ", "No", "Dt"]
- },
- "SellerDtls": {
- "type": "object",
- "properties": {
- "Gstin": {
- "type": "string",
- "minLength": 15,
- "maxLength": 15,
- "pattern": "([0-9]{2}[0-9A-Z]{13})",
- "description": "Supplier GSTIN",
- "validationMsg": "Company GSTIN is invalid"
- },
- "LglNm": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Legal Name"
- },
- "TrdNm": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Tradename"
- },
- "Addr1": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Address Line 1"
- },
- "Addr2": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Address Line 2"
- },
- "Loc": {
- "type": "string",
- "minLength": 3,
- "maxLength": 50,
- "description": "Location"
- },
- "Pin": {
- "type": "number",
- "minimum": 100000,
- "maximum": 999999,
- "description": "Pincode"
- },
- "Stcd": {
- "type": "string",
- "minLength": 1,
- "maxLength": 2,
- "description": "Supplier State Code"
- },
- "Ph": {
- "type": "string",
- "minLength": 6,
- "maxLength": 12,
- "description": "Phone"
- },
- "Em": {
- "type": "string",
- "minLength": 6,
- "maxLength": 100,
- "description": "Email-Id"
- }
- },
- "required": ["Gstin", "LglNm", "Addr1", "Loc", "Pin", "Stcd"]
- },
- "BuyerDtls": {
- "type": "object",
- "properties": {
- "Gstin": {
- "type": "string",
- "minLength": 3,
- "maxLength": 15,
- "pattern": "^(([0-9]{2}[0-9A-Z]{13})|URP)$",
- "description": "Buyer GSTIN",
- "validationMsg": "Customer GSTIN is invalid"
- },
- "LglNm": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Legal Name"
- },
- "TrdNm": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Trade Name"
- },
- "Pos": {
- "type": "string",
- "minLength": 1,
- "maxLength": 2,
- "description": "Place of Supply State code"
- },
- "Addr1": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Address Line 1"
- },
- "Addr2": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Address Line 2"
- },
- "Loc": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Location"
- },
- "Pin": {
- "type": "number",
- "minimum": 100000,
- "maximum": 999999,
- "description": "Pincode"
- },
- "Stcd": {
- "type": "string",
- "minLength": 1,
- "maxLength": 2,
- "description": "Buyer State Code"
- },
- "Ph": {
- "type": "string",
- "minLength": 6,
- "maxLength": 12,
- "description": "Phone"
- },
- "Em": {
- "type": "string",
- "minLength": 6,
- "maxLength": 100,
- "description": "Email-Id"
- }
- },
- "required": ["Gstin", "LglNm", "Pos", "Addr1", "Loc", "Stcd"]
- },
- "DispDtls": {
- "type": "object",
- "properties": {
- "Nm": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Dispatch Address Name"
- },
- "Addr1": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Address Line 1"
- },
- "Addr2": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Address Line 2"
- },
- "Loc": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Location"
- },
- "Pin": {
- "type": "number",
- "minimum": 100000,
- "maximum": 999999,
- "description": "Pincode"
- },
- "Stcd": {
- "type": "string",
- "minLength": 1,
- "maxLength": 2,
- "description": "State Code"
- }
- },
- "required": ["Nm", "Addr1", "Loc", "Pin", "Stcd"]
- },
- "ShipDtls": {
- "type": "object",
- "properties": {
- "Gstin": {
- "type": "string",
- "maxLength": 15,
- "minLength": 3,
- "pattern": "^(([0-9]{2}[0-9A-Z]{13})|URP)$",
- "description": "Shipping Address GSTIN",
- "validationMsg": "Shipping Address GSTIN is invalid"
- },
- "LglNm": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Legal Name"
- },
- "TrdNm": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Trade Name"
- },
- "Addr1": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Address Line 1"
- },
- "Addr2": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Address Line 2"
- },
- "Loc": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Location"
- },
- "Pin": {
- "type": "number",
- "minimum": 100000,
- "maximum": 999999,
- "description": "Pincode"
- },
- "Stcd": {
- "type": "string",
- "minLength": 1,
- "maxLength": 2,
- "description": "State Code"
- }
- },
- "required": ["LglNm", "Addr1", "Loc", "Pin", "Stcd"]
- },
- "ItemList": {
- "type": "Array",
- "properties": {
- "SlNo": {
- "type": "string",
- "minLength": 1,
- "maxLength": 6,
- "description": "Serial No. of Item"
- },
- "PrdDesc": {
- "type": "string",
- "minLength": 3,
- "maxLength": 300,
- "description": "Item Name"
- },
- "IsServc": {
- "type": "string",
- "minLength": 1,
- "maxLength": 1,
- "enum": ["Y", "N"],
- "description": "Is Service Item"
- },
- "HsnCd": {
- "type": "string",
- "minLength": 4,
- "maxLength": 8,
- "description": "HSN Code"
- },
- "Barcde": {
- "type": "string",
- "minLength": 3,
- "maxLength": 30,
- "description": "Barcode"
- },
- "Qty": {
- "type": "number",
- "minimum": 0,
- "maximum": 9999999999.999,
- "description": "Quantity"
- },
- "FreeQty": {
- "type": "number",
- "minimum": 0,
- "maximum": 9999999999.999,
- "description": "Free Quantity"
- },
- "Unit": {
- "type": "string",
- "minLength": 3,
- "maxLength": 8,
- "description": "UOM"
- },
- "UnitPrice": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.999,
- "description": "Rate"
- },
- "TotAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "Gross Amount"
- },
- "Discount": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "Discount"
- },
- "PreTaxVal": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "Pre tax value"
- },
- "AssAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "Taxable Value"
- },
- "GstRt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999.999,
- "description": "GST Rate"
- },
- "IgstAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "IGST Amount"
- },
- "CgstAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "CGST Amount"
- },
- "SgstAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "SGST Amount"
- },
- "CesRt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999.999,
- "description": "Cess Rate"
- },
- "CesAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "Cess Amount (Advalorem)"
- },
- "CesNonAdvlAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "Cess Amount (Non-Advalorem)"
- },
- "StateCesRt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999.999,
- "description": "State CESS Rate"
- },
- "StateCesAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "State CESS Amount"
- },
- "StateCesNonAdvlAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "State CESS Amount (Non Advalorem)"
- },
- "OthChrg": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "Other Charges"
- },
- "TotItemVal": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "Total Item Value"
- },
- "OrdLineRef": {
- "type": "string",
- "minLength": 1,
- "maxLength": 50,
- "description": "Order line reference"
- },
- "OrgCntry": {
- "type": "string",
- "minLength": 2,
- "maxLength": 2,
- "description": "Origin Country"
- },
- "PrdSlNo": {
- "type": "string",
- "minLength": 1,
- "maxLength": 20,
- "description": "Serial number"
- },
- "BchDtls": {
- "type": "object",
- "properties": {
- "Nm": {
- "type": "string",
- "minLength": 3,
- "maxLength": 20,
- "description": "Batch number"
- },
- "ExpDt": {
- "type": "string",
- "maxLength": 10,
- "minLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "Batch Expiry Date"
- },
- "WrDt": {
- "type": "string",
- "maxLength": 10,
- "minLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "Warranty Date"
- }
- },
- "required": ["Nm"]
- },
- "AttribDtls": {
- "type": "Array",
- "Attribute": {
- "type": "object",
- "properties": {
- "Nm": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Attribute name of the item"
- },
- "Val": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Attribute value of the item"
- }
- }
- }
- }
- },
- "required": [
- "SlNo",
- "IsServc",
- "HsnCd",
- "UnitPrice",
- "TotAmt",
- "AssAmt",
- "GstRt",
- "TotItemVal"
- ]
- },
- "ValDtls": {
- "type": "object",
- "properties": {
- "AssVal": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Total Assessable value of all items"
- },
- "CgstVal": {
- "type": "number",
- "maximum": 99999999999999.99,
- "minimum": 0,
- "description": "Total CGST value of all items"
- },
- "SgstVal": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Total SGST value of all items"
- },
- "IgstVal": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Total IGST value of all items"
- },
- "CesVal": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Total CESS value of all items"
- },
- "StCesVal": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Total State CESS value of all items"
- },
- "Discount": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Invoice Discount"
- },
- "OthChrg": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Other Charges"
- },
- "RndOffAmt": {
- "type": "number",
- "minimum": -99.99,
- "maximum": 99.99,
- "description": "Rounded off Amount"
- },
- "TotInvVal": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Final Invoice Value "
- },
- "TotInvValFc": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Final Invoice value in Foreign Currency"
- }
- },
- "required": ["AssVal", "TotInvVal"]
- },
- "PayDtls": {
- "type": "object",
- "properties": {
- "Nm": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Payee Name"
- },
- "AccDet": {
- "type": "string",
- "minLength": 1,
- "maxLength": 18,
- "description": "Bank Account Number of Payee"
- },
- "Mode": {
- "type": "string",
- "minLength": 1,
- "maxLength": 18,
- "description": "Mode of Payment"
- },
- "FinInsBr": {
- "type": "string",
- "minLength": 1,
- "maxLength": 11,
- "description": "Branch or IFSC code"
- },
- "PayTerm": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Terms of Payment"
- },
- "PayInstr": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Payment Instruction"
- },
- "CrTrn": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Credit Transfer"
- },
- "DirDr": {
- "type": "string",
- "minLength": 1,
- "maxLength": 100,
- "description": "Direct Debit"
- },
- "CrDay": {
- "type": "number",
- "minimum": 0,
- "maximum": 9999,
- "description": "Credit Days"
- },
- "PaidAmt": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Advance Amount"
- },
- "PaymtDue": {
- "type": "number",
- "minimum": 0,
- "maximum": 99999999999999.99,
- "description": "Outstanding Amount"
- }
- }
- },
- "RefDtls": {
- "type": "object",
- "properties": {
- "InvRm": {
- "type": "string",
- "maxLength": 100,
- "minLength": 3,
- "pattern": "^[0-9A-Za-z/-]{3,100}$",
- "description": "Remarks/Note"
- },
- "DocPerdDtls": {
- "type": "object",
- "properties": {
- "InvStDt": {
- "type": "string",
- "maxLength": 10,
- "minLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "Invoice Period Start Date"
- },
- "InvEndDt": {
- "type": "string",
- "maxLength": 10,
- "minLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "Invoice Period End Date"
- }
- },
- "required": ["InvStDt ", "InvEndDt "]
- },
- "PrecDocDtls": {
- "type": "object",
- "properties": {
- "InvNo": {
- "type": "string",
- "minLength": 1,
- "maxLength": 16,
- "pattern": "^[1-9A-Z]{1}[0-9A-Z/-]{1,15}$",
- "description": "Reference of Original Invoice"
- },
- "InvDt": {
- "type": "string",
- "maxLength": 10,
- "minLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "Date of Orginal Invoice"
- },
- "OthRefNo": {
- "type": "string",
- "minLength": 1,
- "maxLength": 20,
- "description": "Other Reference"
- }
- }
- },
- "required": ["InvNo", "InvDt"],
- "ContrDtls": {
- "type": "object",
- "properties": {
- "RecAdvRefr": {
- "type": "string",
- "minLength": 1,
- "maxLength": 20,
- "pattern": "^([0-9A-Za-z/-]){1,20}$",
- "description": "Receipt Advice No."
- },
- "RecAdvDt": {
- "type": "string",
- "minLength": 10,
- "maxLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "Date of receipt advice"
- },
- "TendRefr": {
- "type": "string",
- "minLength": 1,
- "maxLength": 20,
- "pattern": "^([0-9A-Za-z/-]){1,20}$",
- "description": "Lot/Batch Reference No."
- },
- "ContrRefr": {
- "type": "string",
- "minLength": 1,
- "maxLength": 20,
- "pattern": "^([0-9A-Za-z/-]){1,20}$",
- "description": "Contract Reference Number"
- },
- "ExtRefr": {
- "type": "string",
- "minLength": 1,
- "maxLength": 20,
- "pattern": "^([0-9A-Za-z/-]){1,20}$",
- "description": "Any other reference"
- },
- "ProjRefr": {
- "type": "string",
- "minLength": 1,
- "maxLength": 20,
- "pattern": "^([0-9A-Za-z/-]){1,20}$",
- "description": "Project Reference Number"
- },
- "PORefr": {
- "type": "string",
- "minLength": 1,
- "maxLength": 16,
- "pattern": "^([0-9A-Za-z/-]){1,16}$",
- "description": "PO Reference Number"
- },
- "PORefDt": {
- "type": "string",
- "minLength": 10,
- "maxLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "PO Reference date"
- }
- }
- }
- }
- },
- "AddlDocDtls": {
- "type": "Array",
- "properties": {
- "Url": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Supporting document URL"
- },
- "Docs": {
- "type": "string",
- "minLength": 3,
- "maxLength": 1000,
- "description": "Supporting document in Base64 Format"
- },
- "Info": {
- "type": "string",
- "minLength": 3,
- "maxLength": 1000,
- "description": "Any additional information"
- }
- }
- },
-
- "ExpDtls": {
- "type": "object",
- "properties": {
- "ShipBNo": {
- "type": "string",
- "minLength": 1,
- "maxLength": 20,
- "description": "Shipping Bill No."
- },
- "ShipBDt": {
- "type": "string",
- "minLength": 10,
- "maxLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "Shipping Bill Date"
- },
- "Port": {
- "type": "string",
- "minLength": 2,
- "maxLength": 10,
- "pattern": "^[0-9A-Za-z]{2,10}$",
- "description": "Port Code. Refer the master"
- },
- "RefClm": {
- "type": "string",
- "minLength": 1,
- "maxLength": 1,
- "description": "Claiming Refund. Y/N"
- },
- "ForCur": {
- "type": "string",
- "minLength": 3,
- "maxLength": 16,
- "description": "Additional Currency Code. Refer the master"
- },
- "CntCode": {
- "type": "string",
- "minLength": 2,
- "maxLength": 2,
- "description": "Country Code. Refer the master"
- },
- "ExpDuty": {
- "type": "number",
- "minimum": 0,
- "maximum": 999999999999.99,
- "description": "Export Duty"
- }
- }
- },
- "EwbDtls": {
- "type": "object",
- "properties": {
- "TransId": {
- "type": "string",
- "minLength": 15,
- "maxLength": 15,
- "description": "Transporter GSTIN"
- },
- "TransName": {
- "type": "string",
- "minLength": 3,
- "maxLength": 100,
- "description": "Transporter Name"
- },
- "TransMode": {
- "type": "string",
- "maxLength": 1,
- "minLength": 1,
- "enum": ["1", "2", "3", "4"],
- "description": "Mode of Transport"
- },
- "Distance": {
- "type": "number",
- "minimum": 1,
- "maximum": 9999,
- "description": "Distance"
- },
- "TransDocNo": {
- "type": "string",
- "minLength": 1,
- "maxLength": 15,
- "pattern": "^([0-9A-Z/-]){1,15}$",
- "description": "Tranport Document Number",
- "validationMsg": "Transport Receipt No is invalid"
- },
- "TransDocDt": {
- "type": "string",
- "minLength": 10,
- "maxLength": 10,
- "pattern": "[0-3][0-9]/[0-1][0-9]/[2][0][1-2][0-9]",
- "description": "Transport Document Date"
- },
- "VehNo": {
- "type": "string",
- "minLength": 4,
- "maxLength": 20,
- "description": "Vehicle Number"
- },
- "VehType": {
- "type": "string",
- "minLength": 1,
- "maxLength": 1,
- "enum": ["O", "R"],
- "description": "Vehicle Type"
- }
- },
- "required": ["Distance"]
- },
- "required": [
- "Version",
- "TranDtls",
- "DocDtls",
- "SellerDtls",
- "BuyerDtls",
- "ItemList",
- "ValDtls"
- ]
-}
diff --git a/erpnext/regional/india/e_invoice/einvoice.js b/erpnext/regional/india/e_invoice/einvoice.js
deleted file mode 100644
index 348f0c6..0000000
--- a/erpnext/regional/india/e_invoice/einvoice.js
+++ /dev/null
@@ -1,292 +0,0 @@
-erpnext.setup_einvoice_actions = (doctype) => {
- frappe.ui.form.on(doctype, {
- async refresh(frm) {
- if (frm.doc.docstatus == 2) return;
-
- const res = await frappe.call({
- method: 'erpnext.regional.india.e_invoice.utils.validate_eligibility',
- args: { doc: frm.doc }
- });
- const invoice_eligible = res.message;
-
- if (!invoice_eligible) return;
-
- const { doctype, irn, irn_cancelled, ewaybill, eway_bill_cancelled, name, __unsaved } = frm.doc;
-
- const add_custom_button = (label, action) => {
- if (!frm.custom_buttons[label]) {
- frm.add_custom_button(label, action, __('E Invoicing'));
- }
- };
-
- if (!irn && !__unsaved) {
- const action = () => {
- if (frm.doc.__unsaved) {
- frappe.throw(__('Please save the document to generate IRN.'));
- }
- frappe.call({
- method: 'erpnext.regional.india.e_invoice.utils.get_einvoice',
- args: { doctype, docname: name },
- freeze: true,
- callback: (res) => {
- const einvoice = res.message;
- show_einvoice_preview(frm, einvoice);
- }
- });
- };
-
- add_custom_button(__("Generate IRN"), action);
- }
-
- if (irn && !irn_cancelled && !ewaybill) {
- const fields = [
- {
- "label": "Reason",
- "fieldname": "reason",
- "fieldtype": "Select",
- "reqd": 1,
- "default": "1-Duplicate",
- "options": ["1-Duplicate", "2-Data Entry Error", "3-Order Cancelled", "4-Other"]
- },
- {
- "label": "Remark",
- "fieldname": "remark",
- "fieldtype": "Data",
- "reqd": 1
- }
- ];
- const action = () => {
- const d = new frappe.ui.Dialog({
- title: __("Cancel IRN"),
- fields: fields,
- primary_action: function() {
- const data = d.get_values();
- frappe.call({
- method: 'erpnext.regional.india.e_invoice.utils.cancel_irn',
- args: {
- doctype,
- docname: name,
- irn: irn,
- reason: data.reason.split('-')[0],
- remark: data.remark
- },
- freeze: true,
- callback: () => frm.reload_doc() || d.hide(),
- error: () => d.hide()
- });
- },
- primary_action_label: __('Submit')
- });
- d.show();
- };
- add_custom_button(__("Cancel IRN"), action);
- }
-
- if (irn && !irn_cancelled && !ewaybill) {
- const action = () => {
- const d = new frappe.ui.Dialog({
- title: __('Generate E-Way Bill'),
- size: "large",
- fields: get_ewaybill_fields(frm),
- primary_action: function() {
- const data = d.get_values();
- frappe.call({
- method: 'erpnext.regional.india.e_invoice.utils.generate_eway_bill',
- args: {
- doctype,
- docname: name,
- irn,
- ...data
- },
- freeze: true,
- callback: () => frm.reload_doc() || d.hide(),
- error: () => d.hide()
- });
- },
- primary_action_label: __('Submit')
- });
- d.show();
- };
-
- add_custom_button(__("Generate E-Way Bill"), action);
- }
-
- if (irn && ewaybill && !irn_cancelled && !eway_bill_cancelled) {
- const action = () => {
- let message = __('Cancellation of e-way bill is currently not supported.') + ' ';
- message += '<br><br>';
- message += __('You must first use the portal to cancel the e-way bill and then update the cancelled status in the ERPNext system.');
-
- const dialog = frappe.msgprint({
- title: __('Update E-Way Bill Cancelled Status?'),
- message: message,
- indicator: 'orange',
- primary_action: {
- action: function() {
- frappe.call({
- method: 'erpnext.regional.india.e_invoice.utils.cancel_eway_bill',
- args: { doctype, docname: name },
- freeze: true,
- callback: () => frm.reload_doc() || dialog.hide()
- });
- }
- },
- primary_action_label: __('Yes')
- });
- };
- add_custom_button(__("Cancel E-Way Bill"), action);
- }
- }
- });
-};
-
-const get_ewaybill_fields = (frm) => {
- return [
- {
- 'fieldname': 'transporter',
- 'label': 'Transporter',
- 'fieldtype': 'Link',
- 'options': 'Supplier',
- 'default': frm.doc.transporter
- },
- {
- 'fieldname': 'gst_transporter_id',
- 'label': 'GST Transporter ID',
- 'fieldtype': 'Data',
- 'fetch_from': 'transporter.gst_transporter_id',
- 'default': frm.doc.gst_transporter_id
- },
- {
- 'fieldname': 'driver',
- 'label': 'Driver',
- 'fieldtype': 'Link',
- 'options': 'Driver',
- 'default': frm.doc.driver
- },
- {
- 'fieldname': 'lr_no',
- 'label': 'Transport Receipt No',
- 'fieldtype': 'Data',
- 'default': frm.doc.lr_no
- },
- {
- 'fieldname': 'vehicle_no',
- 'label': 'Vehicle No',
- 'fieldtype': 'Data',
- 'default': frm.doc.vehicle_no
- },
- {
- 'fieldname': 'distance',
- 'label': 'Distance (in km)',
- 'fieldtype': 'Float',
- 'default': frm.doc.distance
- },
- {
- 'fieldname': 'transporter_col_break',
- 'fieldtype': 'Column Break',
- },
- {
- 'fieldname': 'transporter_name',
- 'label': 'Transporter Name',
- 'fieldtype': 'Data',
- 'fetch_from': 'transporter.name',
- 'read_only': 1,
- 'default': frm.doc.transporter_name
- },
- {
- 'fieldname': 'mode_of_transport',
- 'label': 'Mode of Transport',
- 'fieldtype': 'Select',
- 'options': `\nRoad\nAir\nRail\nShip`,
- 'default': frm.doc.mode_of_transport
- },
- {
- 'fieldname': 'driver_name',
- 'label': 'Driver Name',
- 'fieldtype': 'Data',
- 'fetch_from': 'driver.full_name',
- 'read_only': 1,
- 'default': frm.doc.driver_name
- },
- {
- 'fieldname': 'lr_date',
- 'label': 'Transport Receipt Date',
- 'fieldtype': 'Date',
- 'default': frm.doc.lr_date
- },
- {
- 'fieldname': 'gst_vehicle_type',
- 'label': 'GST Vehicle Type',
- 'fieldtype': 'Select',
- 'options': `Regular\nOver Dimensional Cargo (ODC)`,
- 'depends_on': 'eval:(doc.mode_of_transport === "Road")',
- 'default': frm.doc.gst_vehicle_type
- }
- ];
-};
-
-const request_irn_generation = (frm) => {
- frappe.call({
- method: 'erpnext.regional.india.e_invoice.utils.generate_irn',
- args: { doctype: frm.doc.doctype, docname: frm.doc.name },
- freeze: true,
- callback: () => frm.reload_doc()
- });
-};
-
-const get_preview_dialog = (frm, action) => {
- const dialog = new frappe.ui.Dialog({
- title: __("Preview"),
- size: "large",
- fields: [
- {
- "label": "Preview",
- "fieldname": "preview_html",
- "fieldtype": "HTML"
- }
- ],
- primary_action: () => action(frm) || dialog.hide(),
- primary_action_label: __('Generate IRN')
- });
- return dialog;
-};
-
-const show_einvoice_preview = (frm, einvoice) => {
- const preview_dialog = get_preview_dialog(frm, request_irn_generation);
-
- // initialize e-invoice fields
- einvoice["Irn"] = einvoice["AckNo"] = ''; einvoice["AckDt"] = frappe.datetime.nowdate();
- frm.doc.signed_einvoice = JSON.stringify(einvoice);
-
- // initialize preview wrapper
- const $preview_wrapper = preview_dialog.get_field("preview_html").$wrapper;
- $preview_wrapper.html(
- `<div>
- <div class="print-preview">
- <div class="print-format"></div>
- </div>
- <div class="page-break-message text-muted text-center text-medium margin-top"></div>
- </div>`
- );
-
- frappe.call({
- method: "frappe.www.printview.get_html_and_style",
- args: {
- doc: frm.doc,
- print_format: "GST E-Invoice",
- no_letterhead: 1
- },
- callback: function (r) {
- if (!r.exc) {
- $preview_wrapper.find(".print-format").html(r.message.html);
- const style = `
- .print-format { box-shadow: 0px 0px 5px rgba(0,0,0,0.2); padding: 0.30in; min-height: 80vh; }
- .print-preview { min-height: 0px; }
- .modal-dialog { width: 720px; }`;
-
- frappe.dom.set_style(style, "custom-print-style");
- preview_dialog.show();
- }
- }
- });
-};
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 2d6b913..a6ab6ab 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -61,7 +61,7 @@
def add_custom_roles_for_reports():
for report_name in ('GST Sales Register', 'GST Purchase Register',
- 'GST Itemised Sales Register', 'GST Itemised Purchase Register', 'Eway Bill', 'E-Invoice Summary'):
+ 'GST Itemised Sales Register', 'GST Itemised Purchase Register', 'Eway Bill'):
if not frappe.db.get_value('Custom Role', dict(report=report_name)):
frappe.get_doc(dict(
@@ -100,7 +100,7 @@
)).insert()
def add_permissions():
- for doctype in ('GST HSN Code', 'GST Settings', 'GSTR 3B Report', 'Lower Deduction Certificate', 'E Invoice Settings'):
+ for doctype in ('GST HSN Code', 'GST Settings', 'GSTR 3B Report', 'Lower Deduction Certificate'):
add_permission(doctype, 'All', 0)
for role in ('Accounts Manager', 'Accounts User', 'System Manager'):
add_permission(doctype, role, 0)
@@ -116,11 +116,9 @@
def add_print_formats():
frappe.reload_doc("regional", "print_format", "gst_tax_invoice")
frappe.reload_doc("accounts", "print_format", "gst_pos_invoice")
- frappe.reload_doc("accounts", "print_format", "GST E-Invoice")
frappe.db.set_value("Print Format", "GST POS Invoice", "disabled", 0)
frappe.db.set_value("Print Format", "GST Tax Invoice", "disabled", 0)
- frappe.db.set_value("Print Format", "GST E-Invoice", "disabled", 0)
def make_property_setters(patch=False):
# GST rules do not allow for an invoice no. bigger than 16 characters
@@ -445,53 +443,13 @@
'fieldname': 'ewaybill',
'label': 'E-Way Bill No.',
'fieldtype': 'Data',
- 'depends_on': 'eval:((doc.docstatus === 1 || doc.ewaybill) && doc.eway_bill_cancelled === 0)',
+ 'depends_on': 'eval:(doc.docstatus === 1)',
'allow_on_submit': 1,
'insert_after': 'tax_id',
'translatable': 0
}
]
- si_einvoice_fields = [
- dict(fieldname='irn', label='IRN', fieldtype='Data', read_only=1, insert_after='customer', no_copy=1, print_hide=1,
- depends_on='eval:in_list(["Registered Regular", "SEZ", "Overseas", "Deemed Export"], doc.gst_category) && doc.irn_cancelled === 0'),
-
- dict(fieldname='irn_cancelled', label='IRN Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
- depends_on='eval: doc.irn', allow_on_submit=1, insert_after='customer'),
-
- dict(fieldname='eway_bill_validity', label='E-Way Bill Validity', fieldtype='Data', no_copy=1, print_hide=1,
- depends_on='ewaybill', read_only=1, allow_on_submit=1, insert_after='ewaybill'),
-
- dict(fieldname='eway_bill_cancelled', label='E-Way Bill Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
- depends_on='eval:(doc.eway_bill_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
-
- dict(fieldname='einvoice_section', label='E-Invoice Fields', fieldtype='Section Break', insert_after='gst_vehicle_type',
- print_hide=1, hidden=1),
-
- dict(fieldname='ack_no', label='Ack. No.', fieldtype='Data', read_only=1, hidden=1, insert_after='einvoice_section',
- no_copy=1, print_hide=1),
-
- dict(fieldname='ack_date', label='Ack. Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_no', no_copy=1, print_hide=1),
-
- dict(fieldname='irn_cancel_date', label='Cancel Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_date',
- no_copy=1, print_hide=1),
-
- dict(fieldname='signed_einvoice', label='Signed E-Invoice', fieldtype='Code', options='JSON', hidden=1, insert_after='irn_cancel_date',
- no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='signed_qr_code', label='Signed QRCode', fieldtype='Code', options='JSON', hidden=1, insert_after='signed_einvoice',
- no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='qrcode_image', label='QRCode', fieldtype='Attach Image', hidden=1, insert_after='signed_qr_code',
- no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='einvoice_status', label='E-Invoice Status', fieldtype='Select', insert_after='qrcode_image',
- options='\nPending\nGenerated\nCancelled\nFailed', default=None, hidden=1, no_copy=1, print_hide=1, read_only=1),
-
- dict(fieldname='failure_description', label='E-Invoice Failure Description', fieldtype='Code', options='JSON',
- hidden=1, insert_after='einvoice_status', no_copy=1, print_hide=1, read_only=1)
- ]
-
custom_fields = {
'Address': [
dict(fieldname='gstin', label='Party GSTIN', fieldtype='Data',
@@ -504,7 +462,7 @@
'Purchase Invoice': purchase_invoice_gst_category + invoice_gst_fields + purchase_invoice_itc_fields + purchase_invoice_gst_fields,
'Purchase Order': purchase_invoice_gst_fields,
'Purchase Receipt': purchase_invoice_gst_fields,
- 'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields + si_einvoice_fields,
+ 'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields,
'Delivery Note': sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields + delivery_note_gst_category,
'Journal Entry': journal_entry_fields,
'Sales Order': sales_invoice_gst_fields,
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 949733e..ce5aa10 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -475,7 +475,7 @@
ewaybills.append(data)
data = {
- 'version': '1.0.1118',
+ 'version': '1.0.0421',
'billLists': ewaybills
}
@@ -871,3 +871,20 @@
'tax_category': tax.tax_category,
'valid_from': tax.valid_from
})
+
+def delete_gst_settings_for_company(doc, method):
+ if doc.country != 'India':
+ return
+
+ gst_settings = frappe.get_doc("GST Settings")
+ records_to_delete = []
+
+ for d in reversed(gst_settings.get('gst_accounts')):
+ if d.company == doc.name:
+ records_to_delete.append(d)
+
+ for d in records_to_delete:
+ gst_settings.remove(d)
+
+ gst_settings.save()
+
diff --git a/erpnext/regional/italy/utils.py b/erpnext/regional/italy/utils.py
index ba1aeaf..56f609e 100644
--- a/erpnext/regional/italy/utils.py
+++ b/erpnext/regional/italy/utils.py
@@ -6,9 +6,8 @@
from frappe.utils import flt, cstr
from erpnext.controllers.taxes_and_totals import get_itemised_tax
from frappe import _
-from frappe.core.doctype.file.file import remove_file
+from frappe.utils.file_manager import remove_file
from six import string_types
-from frappe.desk.form.load import get_attachments
from erpnext.regional.italy import state_codes
diff --git a/erpnext/regional/report/e_invoice_summary/__init__.py b/erpnext/regional/report/e_invoice_summary/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/regional/report/e_invoice_summary/__init__.py
+++ /dev/null
diff --git a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.js b/erpnext/regional/report/e_invoice_summary/e_invoice_summary.js
deleted file mode 100644
index 4713217..0000000
--- a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.js
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-/* eslint-disable */
-
-frappe.query_reports["E-Invoice Summary"] = {
- "filters": [
- {
- "fieldtype": "Link",
- "options": "Company",
- "reqd": 1,
- "fieldname": "company",
- "label": __("Company"),
- "default": frappe.defaults.get_user_default("Company"),
- },
- {
- "fieldtype": "Link",
- "options": "Customer",
- "fieldname": "customer",
- "label": __("Customer")
- },
- {
- "fieldtype": "Date",
- "reqd": 1,
- "fieldname": "from_date",
- "label": __("From Date"),
- "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),
- },
- {
- "fieldtype": "Date",
- "reqd": 1,
- "fieldname": "to_date",
- "label": __("To Date"),
- "default": frappe.datetime.get_today(),
- },
- {
- "fieldtype": "Select",
- "fieldname": "status",
- "label": __("Status"),
- "options": "\nPending\nGenerated\nCancelled\nFailed"
- }
- ],
-
- "formatter": function (value, row, column, data, default_formatter) {
- value = default_formatter(value, row, column, data);
-
- if (column.fieldname == "einvoice_status" && value) {
- if (value == 'Pending') value = `<span class="bold" style="color: var(--text-on-orange)">${value}</span>`;
- else if (value == 'Generated') value = `<span class="bold" style="color: var(--text-on-green)">${value}</span>`;
- else if (value == 'Cancelled') value = `<span class="bold" style="color: var(--text-on-red)">${value}</span>`;
- else if (value == 'Failed') value = `<span class="bold" style="color: var(--text-on-red)">${value}</span>`;
- }
-
- return value;
- }
-};
diff --git a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.json b/erpnext/regional/report/e_invoice_summary/e_invoice_summary.json
deleted file mode 100644
index d0000ad..0000000
--- a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "add_total_row": 0,
- "columns": [],
- "creation": "2021-03-12 11:23:37.312294",
- "disable_prepared_report": 0,
- "disabled": 0,
- "docstatus": 0,
- "doctype": "Report",
- "filters": [],
- "idx": 0,
- "is_standard": "Yes",
- "json": "{}",
- "letter_head": "Logo",
- "modified": "2021-03-13 12:36:48.689413",
- "modified_by": "Administrator",
- "module": "Regional",
- "name": "E-Invoice Summary",
- "owner": "Administrator",
- "prepared_report": 0,
- "ref_doctype": "Sales Invoice",
- "report_name": "E-Invoice Summary",
- "report_type": "Script Report",
- "roles": [
- {
- "role": "Administrator"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.py b/erpnext/regional/report/e_invoice_summary/e_invoice_summary.py
deleted file mode 100644
index 66ffcea..0000000
--- a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe import _
-
-def execute(filters=None):
- validate_filters(filters)
-
- columns = get_columns()
- data = get_data(filters)
-
- return columns, data
-
-def validate_filters(filters={}):
- filters = frappe._dict(filters)
-
- if not filters.company:
- frappe.throw(_('{} is mandatory for generating E-Invoice Summary Report').format(_('Company')), title=_('Invalid Filter'))
- if filters.company:
- # validate if company has e-invoicing enabled
- pass
- if not filters.from_date or not filters.to_date:
- frappe.throw(_('From Date & To Date is mandatory for generating E-Invoice Summary Report'), title=_('Invalid Filter'))
- if filters.from_date > filters.to_date:
- frappe.throw(_('From Date must be before To Date'), title=_('Invalid Filter'))
-
-def get_data(filters={}):
- query_filters = {
- 'posting_date': ['between', [filters.from_date, filters.to_date]],
- 'einvoice_status': ['is', 'set'],
- 'company': filters.company
- }
- if filters.customer:
- query_filters['customer'] = filters.customer
- if filters.status:
- query_filters['einvoice_status'] = filters.status
-
- data = frappe.get_all(
- 'Sales Invoice',
- filters=query_filters,
- fields=[d.get('fieldname') for d in get_columns()]
- )
-
- return data
-
-def get_columns():
- return [
- {
- "fieldtype": "Date",
- "fieldname": "posting_date",
- "label": _("Posting Date"),
- "width": 0
- },
- {
- "fieldtype": "Link",
- "fieldname": "name",
- "label": _("Sales Invoice"),
- "options": "Sales Invoice",
- "width": 140
- },
- {
- "fieldtype": "Data",
- "fieldname": "einvoice_status",
- "label": _("Status"),
- "width": 100
- },
- {
- "fieldtype": "Link",
- "fieldname": "customer",
- "options": "Customer",
- "label": _("Customer")
- },
- {
- "fieldtype": "Check",
- "fieldname": "is_return",
- "label": _("Is Return"),
- "width": 85
- },
- {
- "fieldtype": "Data",
- "fieldname": "ack_no",
- "label": "Ack. No.",
- "width": 145
- },
- {
- "fieldtype": "Data",
- "fieldname": "ack_date",
- "label": "Ack. Date",
- "width": 165
- },
- {
- "fieldtype": "Data",
- "fieldname": "irn",
- "label": _("IRN No."),
- "width": 250
- },
- {
- "fieldtype": "Currency",
- "options": "Company:company:default_currency",
- "fieldname": "base_grand_total",
- "label": _("Grand Total"),
- "width": 120
- }
- ]
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index d31db82..38ea5c8 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -571,7 +571,8 @@
"fieldtype": "Data",
"hide_days": 1,
"hide_seconds": 1,
- "label": "Scan Barcode"
+ "label": "Scan Barcode",
+ "options": "Barcode"
},
{
"allow_bulk_edit": 1,
@@ -1510,7 +1511,7 @@
"idx": 105,
"is_submittable": 1,
"links": [],
- "modified": "2021-07-08 21:37:44.177493",
+ "modified": "2021-08-17 20:15:26.531553",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order",
diff --git a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py
index 89cfa16..24ca666 100644
--- a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py
+++ b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py
@@ -44,6 +44,18 @@
if d.item_group not in item_groups:
item_groups.append(d.item_group)
+ if item_groups:
+ child_items = []
+ for item_group in item_groups:
+ if frappe.db.get_value("Item Group", {"name":item_group}, "is_group"):
+ for child_item_group in frappe.get_all("Item Group", {"parent_item_group":item_group}):
+ if child_item_group['name'] not in child_items:
+ child_items.append(child_item_group['name'])
+
+ for item in child_items:
+ if item not in item_groups:
+ item_groups.append(item)
+
date_field = ("transaction_date"
if filters.get('doctype') == "Sales Order" else "posting_date")
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index 22bf3fc..2de57c8 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -394,6 +394,10 @@
}
_set_batch_number(doc) {
+ if (doc.batch_no) {
+ return
+ }
+
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
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 54c6753..45d5ce0 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -393,6 +393,10 @@
frappe.db.sql("delete from `tabPurchase Taxes and Charges Template` where company=%s", self.name)
frappe.db.sql("delete from `tabItem Tax Template` where company=%s", self.name)
+ # delete Process Deferred Accounts if no GL Entry found
+ if not frappe.db.get_value('GL Entry', {'company': self.name}):
+ frappe.db.sql("delete from `tabProcess Deferred Accounting` where company=%s", self.name)
+
@frappe.whitelist()
def enqueue_replace_abbr(company, old, new):
kwargs = dict(queue="long", company=company, old=old, new=new)
diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py
index 56afe95..e9f4bd5 100644
--- a/erpnext/shopping_cart/cart.py
+++ b/erpnext/shopping_cart/cart.py
@@ -308,7 +308,7 @@
party = get_party()
party.customer_name = company_name or fullname
- party.customer_type == "Company" if company_name else "Individual"
+ party.customer_type = "Company" if company_name else "Individual"
contact_name = frappe.db.get_value("Contact", {"email_id": frappe.session.user})
contact = frappe.get_doc("Contact", contact_name)
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py
index 2a49722..efed196 100644
--- a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py
+++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py
@@ -6,7 +6,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _, msgprint
-from frappe.utils import comma_and
+from frappe.utils import flt
from frappe.model.document import Document
from frappe.utils import get_datetime, get_datetime_str, now_datetime
@@ -18,46 +18,35 @@
def validate(self):
if self.enabled:
- self.validate_exchange_rates_exist()
+ self.validate_price_list_exchange_rate()
- def validate_exchange_rates_exist(self):
- """check if exchange rates exist for all Price List currencies (to company's currency)"""
- company_currency = frappe.get_cached_value('Company', self.company, "default_currency")
+ def validate_price_list_exchange_rate(self):
+ "Check if exchange rate exists for Price List currency (to Company's currency)."
+ from erpnext.setup.utils import get_exchange_rate
+
+ if not self.enabled or not self.company or not self.price_list:
+ return # this function is also called from hooks, check values again
+
+ company_currency = frappe.get_cached_value("Company", self.company, "default_currency")
+ price_list_currency = frappe.db.get_value("Price List", self.price_list, "currency")
+
if not company_currency:
- msgprint(_("Please specify currency in Company") + ": " + self.company,
- raise_exception=ShoppingCartSetupError)
+ msg = f"Please specify currency in Company {self.company}"
+ frappe.throw(_(msg), title=_("Missing Currency"), exc=ShoppingCartSetupError)
- price_list_currency_map = frappe.db.get_values("Price List",
- [self.price_list], "currency")
+ if not price_list_currency:
+ msg = f"Please specify currency in Price List {frappe.bold(self.price_list)}"
+ frappe.throw(_(msg), title=_("Missing Currency"), exc=ShoppingCartSetupError)
- price_list_currency_map = dict(price_list_currency_map)
+ if price_list_currency != company_currency:
+ from_currency, to_currency = price_list_currency, company_currency
- # check if all price lists have a currency
- for price_list, currency in price_list_currency_map.items():
- if not currency:
- frappe.throw(_("Currency is required for Price List {0}").format(price_list))
+ # Get exchange rate checks Currency Exchange Records too
+ exchange_rate = get_exchange_rate(from_currency, to_currency, args="for_selling")
- expected_to_exist = [currency + "-" + company_currency
- for currency in price_list_currency_map.values()
- if currency != company_currency]
-
- # manqala 20/09/2016: set up selection parameters for query from tabCurrency Exchange
- from_currency = [currency for currency in price_list_currency_map.values() if currency != company_currency]
- to_currency = company_currency
- # manqala end
-
- if expected_to_exist:
- # manqala 20/09/2016: modify query so that it uses date in the selection from Currency Exchange.
- # exchange rates defined with date less than the date on which this document is being saved will be selected
- exists = frappe.db.sql_list("""select CONCAT(from_currency,'-',to_currency) from `tabCurrency Exchange`
- where from_currency in (%s) and to_currency = "%s" and date <= curdate()""" % (", ".join(["%s"]*len(from_currency)), to_currency), tuple(from_currency))
- # manqala end
-
- missing = list(set(expected_to_exist).difference(exists))
-
- if missing:
- msgprint(_("Missing Currency Exchange Rates for {0}").format(comma_and(missing)),
- raise_exception=ShoppingCartSetupError)
+ if not flt(exchange_rate):
+ msg = f"Missing Currency Exchange Rates for {from_currency}-{to_currency}"
+ frappe.throw(_(msg), title=_("Missing"), exc=ShoppingCartSetupError)
def validate_tax_rule(self):
if not frappe.db.get_value("Tax Rule", {"use_for_shopping_cart" : 1}, "name"):
@@ -71,7 +60,7 @@
def get_shipping_rules(self, shipping_territory):
return self.get_name_from_territory(shipping_territory, "shipping_rules", "shipping_rule")
-def validate_cart_settings(doc, method):
+def validate_cart_settings(doc=None, method=None):
frappe.get_doc("Shopping Cart Settings", "Shopping Cart Settings").run_method("validate")
def get_shopping_cart_settings():
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py b/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py
index 008751e..9965e1a 100644
--- a/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py
+++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py
@@ -16,17 +16,25 @@
return frappe.get_doc({"doctype": "Shopping Cart Settings",
"company": "_Test Company"})
- def test_exchange_rate_exists(self):
- frappe.db.sql("""delete from `tabCurrency Exchange`""")
+ # NOTE: Exchangrate API has all enabled currencies that ERPNext supports.
+ # We aren't checking just currency exchange record anymore
+ # while validating price list currency exchange rate to that of company.
+ # The API is being used to fetch the rate which again almost always
+ # gives back a valid value (for valid currencies).
+ # This makes the test obsolete.
+ # Commenting because im not sure if there's a better test we can write
- cart_settings = self.get_cart_settings()
- cart_settings.price_list = "_Test Price List Rest of the World"
- self.assertRaises(ShoppingCartSetupError, cart_settings.validate_exchange_rates_exist)
+ # def test_exchange_rate_exists(self):
+ # frappe.db.sql("""delete from `tabCurrency Exchange`""")
- from erpnext.setup.doctype.currency_exchange.test_currency_exchange import test_records as \
- currency_exchange_records
- frappe.get_doc(currency_exchange_records[0]).insert()
- cart_settings.validate_exchange_rates_exist()
+ # cart_settings = self.get_cart_settings()
+ # cart_settings.price_list = "_Test Price List Rest of the World"
+ # self.assertRaises(ShoppingCartSetupError, cart_settings.validate_price_list_exchange_rate)
+
+ # from erpnext.setup.doctype.currency_exchange.test_currency_exchange import test_records as \
+ # currency_exchange_records
+ # frappe.get_doc(currency_exchange_records[0]).insert()
+ # cart_settings.validate_price_list_exchange_rate()
def test_tax_rule_validation(self):
frappe.db.sql("update `tabTax Rule` set use_for_shopping_cart = 0")
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json
index dbfeb4a..9581896 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.json
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.json
@@ -515,7 +515,8 @@
{
"fieldname": "scan_barcode",
"fieldtype": "Data",
- "label": "Scan Barcode"
+ "label": "Scan Barcode",
+ "options": "Barcode"
},
{
"allow_bulk_edit": 1,
@@ -1305,7 +1306,7 @@
"idx": 146,
"is_submittable": 1,
"links": [],
- "modified": "2021-07-08 21:37:20.802652",
+ "modified": "2021-08-17 20:15:50.574966",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note",
diff --git a/erpnext/stock/doctype/material_request/material_request.json b/erpnext/stock/doctype/material_request/material_request.json
index 4e2d9e6..cb46a6c 100644
--- a/erpnext/stock/doctype/material_request/material_request.json
+++ b/erpnext/stock/doctype/material_request/material_request.json
@@ -133,7 +133,8 @@
{
"fieldname": "scan_barcode",
"fieldtype": "Data",
- "label": "Scan Barcode"
+ "label": "Scan Barcode",
+ "options": "Barcode"
},
{
"allow_bulk_edit": 1,
@@ -181,7 +182,7 @@
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
- "options": "\nDraft\nSubmitted\nStopped\nCancelled\nPending\nPartially Ordered\nPartially Received\nOrdered\nIssued\nTransferred\nReceived",
+ "options": "\nDraft\nSubmitted\nStopped\nCancelled\nPending\nPartially Ordered\nOrdered\nIssued\nTransferred\nReceived",
"print_hide": 1,
"print_width": "100px",
"read_only": 1,
@@ -314,7 +315,7 @@
"idx": 70,
"is_submittable": 1,
"links": [],
- "modified": "2021-03-31 23:52:55.392512",
+ "modified": "2021-08-17 20:16:12.737743",
"modified_by": "Administrator",
"module": "Stock",
"name": "Material Request",
diff --git a/erpnext/stock/doctype/price_list/price_list.py b/erpnext/stock/doctype/price_list/price_list.py
index 10abde1..002d3d8 100644
--- a/erpnext/stock/doctype/price_list/price_list.py
+++ b/erpnext/stock/doctype/price_list/price_list.py
@@ -13,6 +13,9 @@
if not cint(self.buying) and not cint(self.selling):
throw(_("Price List must be applicable for Buying or Selling"))
+ if not self.is_new():
+ self.check_impact_on_shopping_cart()
+
def on_update(self):
self.set_default_if_missing()
self.update_item_price()
@@ -32,6 +35,17 @@
buying=%s, selling=%s, modified=NOW() where price_list=%s""",
(self.currency, cint(self.buying), cint(self.selling), self.name))
+ def check_impact_on_shopping_cart(self):
+ "Check if Price List currency change impacts Shopping Cart."
+ from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings import validate_cart_settings
+
+ doc_before_save = self.get_doc_before_save()
+ currency_changed = self.currency != doc_before_save.currency
+ affects_cart = self.name == frappe.get_cached_value("Shopping Cart Settings", None, "price_list")
+
+ if currency_changed and affects_cart:
+ validate_cart_settings()
+
def on_trash(self):
self.delete_price_list_details_key()
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
index 44fb736..1a59734 100755
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
@@ -1098,7 +1098,8 @@
{
"fieldname": "scan_barcode",
"fieldtype": "Data",
- "label": "Scan Barcode"
+ "label": "Scan Barcode",
+ "options": "Barcode"
},
{
"fieldname": "billing_address",
@@ -1148,7 +1149,7 @@
"idx": 261,
"is_submittable": 1,
"links": [],
- "modified": "2021-05-25 00:15:12.239017",
+ "modified": "2021-08-17 20:16:40.849885",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt",
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json
index 523d332..2f37778 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.json
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.json
@@ -84,8 +84,6 @@
"oldfieldtype": "Section Break"
},
{
- "allow_on_submit": 1,
- "default": "{purpose}",
"fieldname": "title",
"fieldtype": "Data",
"hidden": 1,
@@ -355,6 +353,7 @@
},
{
"fieldname": "scan_barcode",
+ "options": "Barcode",
"fieldtype": "Data",
"label": "Scan Barcode"
},
@@ -629,7 +628,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-05-26 17:07:58.015737",
+ "modified": "2021-08-20 19:19:31.514846",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Entry",
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 7b31d2f..0b4592c 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -58,6 +58,7 @@
self.validate_posting_time()
self.validate_purpose()
+ self.set_title()
self.validate_item()
self.validate_customer_provided_item()
self.validate_qty()
@@ -317,9 +318,6 @@
d.s_warehouse = self.from_warehouse
d.t_warehouse = self.to_warehouse
- if not (d.s_warehouse or d.t_warehouse):
- frappe.throw(_("Atleast one warehouse is mandatory"))
-
if self.purpose in source_mandatory and not d.s_warehouse:
if self.from_warehouse:
d.s_warehouse = self.from_warehouse
@@ -332,6 +330,7 @@
else:
frappe.throw(_("Target warehouse is mandatory for row {0}").format(d.idx))
+
if self.purpose == "Manufacture":
if validate_for_manufacture:
if d.is_finished_item or d.is_scrap_item:
@@ -346,6 +345,9 @@
if cstr(d.s_warehouse) == cstr(d.t_warehouse) and not self.purpose == "Material Transfer for Manufacture":
frappe.throw(_("Source and target warehouse cannot be same for row {0}").format(d.idx))
+ if not (d.s_warehouse or d.t_warehouse):
+ frappe.throw(_("Atleast one warehouse is mandatory"))
+
def validate_work_order(self):
if self.purpose in ("Manufacture", "Material Transfer for Manufacture", "Material Consumption for Manufacture"):
# check if work order is entered
@@ -1607,6 +1609,14 @@
return sorted(list(set(get_serial_nos(self.pro_doc.serial_no)) - set(used_serial_nos)))
+ def set_title(self):
+ if frappe.flags.in_import and self.title:
+ # Allow updating title during data import/update
+ return
+
+ self.title = self.purpose
+
+
@frappe.whitelist()
def move_sample_to_retention_warehouse(company, items):
if isinstance(items, string_types):
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index a0fbcec..c72073c 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -278,6 +278,10 @@
else:
args.uom = item.stock_uom
+ if (args.get("batch_no") and
+ item.name != frappe.get_cached_value('Batch', args.get("batch_no"), 'item')):
+ args['batch_no'] = ''
+
out = frappe._dict({
"item_code": item.name,
"item_name": item.item_name,
diff --git a/erpnext/stock/report/stock_analytics/stock_analytics.js b/erpnext/stock/report/stock_analytics/stock_analytics.js
index 6b384e2..78afe6d 100644
--- a/erpnext/stock/report/stock_analytics/stock_analytics.js
+++ b/erpnext/stock/report/stock_analytics/stock_analytics.js
@@ -37,11 +37,25 @@
default: "",
},
{
+ fieldname: "company",
+ label: __("Company"),
+ fieldtype: "Link",
+ options: "Company",
+ default: frappe.defaults.get_user_default("Company"),
+ reqd: 1,
+ },
+ {
fieldname: "warehouse",
label: __("Warehouse"),
fieldtype: "Link",
- options:"Warehouse",
+ options: "Warehouse",
default: "",
+ get_query: function() {
+ const company = frappe.query_report.get_filter_value('company');
+ return {
+ filters: { 'company': company }
+ }
+ }
},
{
fieldname: "from_date",
diff --git a/erpnext/stock/report/stock_analytics/stock_analytics.py b/erpnext/stock/report/stock_analytics/stock_analytics.py
index d62abed..a1e1e7f 100644
--- a/erpnext/stock/report/stock_analytics/stock_analytics.py
+++ b/erpnext/stock/report/stock_analytics/stock_analytics.py
@@ -1,14 +1,15 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
+import datetime
-from __future__ import unicode_literals
import frappe
from frappe import _, scrub
-from frappe.utils import getdate, flt
+from frappe.utils import getdate, get_quarter_start, get_first_day_of_week
+from frappe.utils import get_first_day as get_first_day_of_month
+
from erpnext.stock.report.stock_balance.stock_balance import (get_items, get_stock_ledger_entries, get_item_details)
from erpnext.accounts.utils import get_fiscal_year
from erpnext.stock.utils import is_reposting_item_valuation_in_progress
-from six import iteritems
def execute(filters=None):
is_reposting_item_valuation_in_progress()
@@ -71,7 +72,8 @@
def get_period_date_ranges(filters):
from dateutil.relativedelta import relativedelta
- from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)
+ from_date = round_down_to_nearest_frequency(filters.from_date, filters.range)
+ to_date = getdate(filters.to_date)
increment = {
"Monthly": 1,
@@ -97,6 +99,31 @@
return periodic_daterange
+
+def round_down_to_nearest_frequency(date: str, frequency: str) -> datetime.datetime:
+ """Rounds down the date to nearest frequency unit.
+ example:
+
+ >>> round_down_to_nearest_frequency("2021-02-21", "Monthly")
+ datetime.datetime(2021, 2, 1)
+
+ >>> round_down_to_nearest_frequency("2021-08-21", "Yearly")
+ datetime.datetime(2021, 1, 1)
+ """
+
+ def _get_first_day_of_fiscal_year(date):
+ fiscal_year = get_fiscal_year(date)
+ return fiscal_year and fiscal_year[1] or date
+
+ round_down_function = {
+ "Monthly": get_first_day_of_month,
+ "Quarterly": get_quarter_start,
+ "Weekly": get_first_day_of_week,
+ "Yearly": _get_first_day_of_fiscal_year,
+ }.get(frequency, getdate)
+ return round_down_function(date)
+
+
def get_period(posting_date, filters):
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
@@ -177,7 +204,7 @@
periodic_data = get_periodic_data(sle, filters)
ranges = get_period_date_ranges(filters)
- for dummy, item_data in iteritems(item_details):
+ for dummy, item_data in item_details.items():
row = {
"name": item_data.name,
"item_name": item_data.item_name,
diff --git a/erpnext/stock/report/stock_analytics/test_stock_analytics.py b/erpnext/stock/report/stock_analytics/test_stock_analytics.py
new file mode 100644
index 0000000..00e268b
--- /dev/null
+++ b/erpnext/stock/report/stock_analytics/test_stock_analytics.py
@@ -0,0 +1,35 @@
+import datetime
+import unittest
+
+from frappe import _dict
+from erpnext.accounts.utils import get_fiscal_year
+
+from erpnext.stock.report.stock_analytics.stock_analytics import get_period_date_ranges
+
+
+class TestStockAnalyticsReport(unittest.TestCase):
+ def test_get_period_date_ranges(self):
+
+ filters = _dict(range="Monthly", from_date="2020-12-28", to_date="2021-02-06")
+
+ ranges = get_period_date_ranges(filters)
+
+ expected_ranges = [
+ [datetime.date(2020, 12, 1), datetime.date(2020, 12, 31)],
+ [datetime.date(2021, 1, 1), datetime.date(2021, 1, 31)],
+ [datetime.date(2021, 2, 1), datetime.date(2021, 2, 6)],
+ ]
+
+ self.assertEqual(ranges, expected_ranges)
+
+ def test_get_period_date_ranges_yearly(self):
+
+ filters = _dict(range="Yearly", from_date="2021-01-28", to_date="2021-02-06")
+
+ ranges = get_period_date_ranges(filters)
+ first_date = get_fiscal_year("2021-01-28")[1]
+ expected_ranges = [
+ [first_date, datetime.date(2021, 2, 6)],
+ ]
+
+ self.assertEqual(ranges, expected_ranges)
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py
index 8909f21..b6923e9 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.py
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.py
@@ -23,6 +23,7 @@
conversion_factors = []
if opening_row:
data.append(opening_row)
+ conversion_factors.append(0)
actual_qty = stock_value = 0
diff --git a/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
index a81516e..d9c671e 100644
--- a/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
@@ -267,11 +267,15 @@
)
creation = datetime.datetime(2019, 3, 4, 12, 0)
lead = make_lead(creation=creation, index=4)
- self.assertFalse(lead.service_level_agreement)
+ applied_sla = frappe.db.get_value('Lead', lead.name, 'service_level_agreement')
+ self.assertFalse(applied_sla)
+ source = frappe.get_doc(doctype='Lead Source', source_name='Test Source')
+ source.insert(ignore_if_duplicate=True)
lead.source = "Test Source"
lead.save()
- self.assertEqual(lead.service_level_agreement, lead_sla.name)
+ applied_sla = frappe.db.get_value('Lead', lead.name, 'service_level_agreement')
+ self.assertEqual(applied_sla, lead_sla.name)
def tearDown(self):
for d in frappe.get_all("Service Level Agreement"):