Merge branch 'develop' into item_group_on_update_items
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 67c7fd2..60d1e20 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -82,7 +82,7 @@
error_msg = _("""{0} {1} is not in any active Fiscal Year""").format(label, formatdate(transaction_date))
if company:
error_msg = _("""{0} for {1}""").format(error_msg, frappe.bold(company))
-
+
if verbose==1: frappe.msgprint(error_msg)
raise FiscalYearError(error_msg)
@@ -888,17 +888,22 @@
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
warehouse_account=None, company=None):
+ stock_vouchers = get_future_stock_vouchers(posting_date, posting_time, for_warehouses, for_items, company)
+ repost_gle_for_stock_vouchers(stock_vouchers, posting_date, company, warehouse_account)
+
+
+def repost_gle_for_stock_vouchers(stock_vouchers, posting_date, company=None, warehouse_account=None):
def _delete_gl_entries(voucher_type, voucher_no):
frappe.db.sql("""delete from `tabGL Entry`
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
+
if not warehouse_account:
warehouse_account = get_warehouse_account_map(company)
- future_stock_vouchers = get_future_stock_vouchers(posting_date, posting_time, for_warehouses, for_items)
- gle = get_voucherwise_gl_entries(future_stock_vouchers, posting_date)
+ gle = get_voucherwise_gl_entries(stock_vouchers, posting_date)
- for voucher_type, voucher_no in future_stock_vouchers:
+ for voucher_type, voucher_no in stock_vouchers:
existing_gle = gle.get((voucher_type, voucher_no), [])
voucher_obj = frappe.get_doc(voucher_type, voucher_no)
expected_gle = voucher_obj.get_gl_entries(warehouse_account)
@@ -909,7 +914,7 @@
else:
_delete_gl_entries(voucher_type, voucher_no)
-def get_future_stock_vouchers(posting_date, posting_time, for_warehouses=None, for_items=None):
+def get_future_stock_vouchers(posting_date, posting_time, for_warehouses=None, for_items=None, company=None):
future_stock_vouchers = []
values = []
@@ -922,6 +927,10 @@
condition += " and warehouse in ({})".format(", ".join(["%s"] * len(for_warehouses)))
values += for_warehouses
+ if company:
+ condition += " and company = %s"
+ values.append(company)
+
for d in frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no
from `tabStock Ledger Entry` sle
where
@@ -982,7 +991,7 @@
error_reason = _("Stock Value ({0}) and Account Balance ({1}) are out of sync for account {2} and it's linked warehouses as on {3}.").format(
stock_bal, account_bal, frappe.bold(account), posting_date)
error_resolution = _("Please create an adjustment Journal Entry for amount {0} on {1}")\
- .format(frappe.bold(diff), frappe.bold(posting_date))
+ .format(frappe.bold(diff), frappe.bold(posting_date))
frappe.msgprint(
msg="""{0}<br></br>{1}<br></br>""".format(error_reason, error_resolution),
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 70e8d8c..ea9659c 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -488,13 +488,12 @@
"voucher_no": self.name,
"company": self.company
})
-
if check_if_future_sle_exists(args):
create_repost_item_valuation_entry(args)
elif not is_reposting_pending():
check_if_stock_and_account_balance_synced(self.posting_date,
self.company, self.doctype, self.name)
-
+
def is_reposting_pending():
return frappe.db.exists("Repost Item Valuation",
{'docstatus': 1, 'status': ['in', ['Queued','In Progress']]})
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
index 66d0e5f..5f990cd 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
@@ -20,7 +20,7 @@
client_id=self.settings.plaid_client_id,
secret=self.settings.get_password("plaid_secret"),
environment=self.settings.plaid_env,
- api_version="2019-05-29"
+ api_version="2020-09-14"
)
def get_access_token(self, public_token):
@@ -29,7 +29,7 @@
response = self.client.Item.public_token.exchange(public_token)
access_token = response["access_token"]
return access_token
-
+
def get_token_request(self, update_mode=False):
country_codes = ["US", "CA", "FR", "IE", "NL", "ES", "GB"] if self.settings.enable_european_access else ["US", "CA"]
args = {
diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
index c324228..325c209 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
+++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
@@ -121,6 +121,7 @@
stock_entry.stock_entry_type = 'Material Receipt'
stock_entry.to_warehouse = self.warehouse
+ stock_entry.company = self.company
expense_account = get_account(None, 'expense_account', 'Healthcare Settings', self.company)
for item in self.items:
if item.qty > item.actual_qty:
diff --git a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
index 4ee5f6b..fb72073 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
+++ b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+ # -*- coding: utf-8 -*-
# Copyright (c) 2017, ESS LLP and Contributors
# See license.txt
from __future__ import unicode_literals
@@ -60,6 +60,7 @@
procedure.practitioner = practitioner
procedure.consume_stock = procedure_template.allow_stock_consumption
procedure.items = procedure_template.items
- procedure.warehouse = frappe.db.get_single_value('Stock Settings', 'default_warehouse')
+ procedure.company = "_Test Company"
+ procedure.warehouse = "_Test Warehouse - _TC"
procedure.submit()
return procedure
\ No newline at end of file
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 3b7c6ab..e5ee551 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -752,3 +752,5 @@
erpnext.patches.v13_0.convert_qi_parameter_to_link_field
erpnext.patches.v13_0.setup_patient_history_settings_for_standard_doctypes
erpnext.patches.v13_0.add_naming_series_to_old_projects # 1-02-2021
+erpnext.patches.v12_0.add_state_code_for_ladakh
+erpnext.patches.v13_0.item_reposting_for_incorrect_sl_and_gl
diff --git a/erpnext/patches/v12_0/add_state_code_for_ladakh.py b/erpnext/patches/v12_0/add_state_code_for_ladakh.py
new file mode 100644
index 0000000..d41101c
--- /dev/null
+++ b/erpnext/patches/v12_0/add_state_code_for_ladakh.py
@@ -0,0 +1,16 @@
+import frappe
+from erpnext.regional.india import states
+
+def execute():
+
+ company = frappe.get_all('Company', filters = {'country': 'India'})
+ if not company:
+ return
+
+ custom_fields = ['Address-gst_state', 'Tax Category-gst_state']
+
+ # Update options in gst_state custom fields
+ for field in custom_fields:
+ gst_state_field = frappe.get_doc('Custom Field', field)
+ gst_state_field.options = '\n'.join(states)
+ gst_state_field.save()
diff --git a/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py b/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py
new file mode 100644
index 0000000..f60e0d3
--- /dev/null
+++ b/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py
@@ -0,0 +1,27 @@
+import frappe
+from frappe import _
+from erpnext.stock.stock_ledger import update_entries_after
+from erpnext.accounts.utils import update_gl_entries_after
+
+def execute():
+ data = frappe.db.sql(''' SELECT name, item_code, warehouse, voucher_type, voucher_no, posting_date, posting_time
+ from `tabStock Ledger Entry` where creation > '2020-12-26 12:58:55.903836' and is_cancelled = 0
+ order by timestamp(posting_date, posting_time) asc, creation asc''', as_dict=1)
+
+ for index, d in enumerate(data):
+ update_entries_after({
+ "item_code": d.item_code,
+ "warehouse": d.warehouse,
+ "posting_date": d.posting_date,
+ "posting_time": d.posting_time,
+ "voucher_type": d.voucher_type,
+ "voucher_no": d.voucher_no,
+ "sle_id": d.name
+ }, allow_negative_stock=True)
+
+ frappe.db.auto_commit_on_many_writes = 1
+
+ for row in frappe.get_all('Company', filters= {'enable_perpetual_inventory': 1}):
+ update_gl_entries_after('2020-12-25', '01:58:55', company=row.name)
+
+ frappe.db.auto_commit_on_many_writes = 0
\ No newline at end of file
diff --git a/erpnext/public/images/erpnext-logo.png b/erpnext/public/images/erpnext-logo.png
new file mode 100644
index 0000000..3090727
--- /dev/null
+++ b/erpnext/public/images/erpnext-logo.png
Binary files differ
diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js
index 2623c3c..d49a813 100644
--- a/erpnext/public/js/utils/serial_no_batch_selector.js
+++ b/erpnext/public/js/utils/serial_no_batch_selector.js
@@ -140,6 +140,7 @@
() => me.update_batch_serial_no_items(),
() => {
refresh_field("items");
+ refresh_field("packed_items");
if (me.callback) {
return me.callback(me.item);
}
@@ -154,7 +155,7 @@
if (this.item.serial_no) {
this.dialog.fields_dict.serial_no.set_value(this.item.serial_no);
}
-
+
if (this.has_batch && !this.has_serial_no && d.batch_no) {
this.frm.doc.items.forEach(data => {
if(data.item_code == d.item_code) {
@@ -231,7 +232,7 @@
this.map_row_values(row, batch, 'batch_no',
'selected_qty', this.values.warehouse);
});
- }
+ }
},
update_serial_no_item() {
@@ -250,7 +251,7 @@
filters: { 'name': ["in", selected_serial_nos]},
fields: ["batch_no", "name"]
}).then((data) => {
- // data = [{batch_no: 'batch-1', name: "SR-001"},
+ // data = [{batch_no: 'batch-1', name: "SR-001"},
// {batch_no: 'batch-2', name: "SR-003"}, {batch_no: 'batch-2', name: "SR-004"}]
const batch_serial_map = data.reduce((acc, d) => {
if (!acc[d['batch_no']]) acc[d['batch_no']] = [];
@@ -298,6 +299,8 @@
} else {
row.warehouse = values.warehouse || warehouse;
}
+
+ this.frm.dirty();
},
update_total_qty: function() {
diff --git a/erpnext/public/less/hub.less b/erpnext/public/less/hub.less
index 8cb7a9c..29deada 100644
--- a/erpnext/public/less/hub.less
+++ b/erpnext/public/less/hub.less
@@ -32,7 +32,12 @@
}
.hub-image-loading, .hub-image-broken {
- .img-background();
+ content: " ";
+ position: absolute;
+ left: 0;
+ height: 100%;
+ width: 100%;
+ background-color: var(--bg-light-gray);
display: flex;
align-items: center;
justify-content: center;
diff --git a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
index e8a8ed8..ad60db0 100644
--- a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
+++ b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
@@ -5,12 +5,16 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import getdate
+from frappe.utils import getdate, get_link_to_form
from frappe.model.document import Document
from erpnext.accounts.utils import get_fiscal_year
class LowerDeductionCertificate(Document):
def validate(self):
+ self.validate_dates()
+ self.validate_supplier_against_section_code()
+
+ def validate_dates(self):
if getdate(self.valid_upto) < getdate(self.valid_from):
frappe.throw(_("Valid Upto date cannot be before Valid From date"))
@@ -24,3 +28,20 @@
<= fiscal_year.year_end_date):
frappe.throw(_("Valid Upto date not in Fiscal Year {0}").format(frappe.bold(self.fiscal_year)))
+ def validate_supplier_against_section_code(self):
+ duplicate_certificate = frappe.db.get_value('Lower Deduction Certificate', {'supplier': self.supplier, 'section_code': self.section_code}, ['name', 'valid_from', 'valid_upto'], as_dict=True)
+ if duplicate_certificate and self.are_dates_overlapping(duplicate_certificate):
+ certificate_link = get_link_to_form('Lower Deduction Certificate', duplicate_certificate.name)
+ frappe.throw(_("There is already a valid Lower Deduction Certificate {0} for Supplier {1} against Section Code {2} for this time period.")
+ .format(certificate_link, frappe.bold(self.supplier), frappe.bold(self.section_code)))
+
+ def are_dates_overlapping(self,duplicate_certificate):
+ valid_from = duplicate_certificate.valid_from
+ valid_upto = duplicate_certificate.valid_upto
+ if valid_from <= getdate(self.valid_from) <= valid_upto:
+ return True
+ elif valid_from <= getdate(self.valid_upto) <= valid_upto:
+ return True
+ elif getdate(self.valid_from) <= valid_from and valid_upto <= getdate(self.valid_upto):
+ return True
+ return False
\ No newline at end of file
diff --git a/erpnext/regional/india/__init__.py b/erpnext/regional/india/__init__.py
index d6221a8..378b735 100644
--- a/erpnext/regional/india/__init__.py
+++ b/erpnext/regional/india/__init__.py
@@ -20,6 +20,7 @@
'Jharkhand',
'Karnataka',
'Kerala',
+ 'Ladakh',
'Lakshadweep Islands',
'Madhya Pradesh',
'Maharashtra',
@@ -59,6 +60,7 @@
"Jharkhand": "20",
"Karnataka": "29",
"Kerala": "32",
+ "Ladakh": "38",
"Lakshadweep Islands": "31",
"Madhya Pradesh": "23",
"Maharashtra": "27",
@@ -80,4 +82,4 @@
"West Bengal": "19",
}
-number_state_mapping = {v: k for k, v in iteritems(state_numbers)}
\ No newline at end of file
+number_state_mapping = {v: k for k, v in iteritems(state_numbers)}
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index e016c81..2043f49 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -23,7 +23,7 @@
invalid_doctype = doc.doctype != 'Sales Invoice'
invalid_supply_type = doc.get('gst_category') not in ['Registered Regular', 'SEZ', 'Overseas', 'Deemed Export']
company_transaction = doc.get('billing_address_gstin') == doc.get('company_gstin')
- no_taxes_applied = len(doc.get('taxes', [])) == 0
+ no_taxes_applied = not doc.get('taxes')
if not einvoicing_enabled or invalid_doctype or invalid_supply_type or company_transaction or no_taxes_applied:
return
@@ -63,7 +63,7 @@
elif invoice.gst_category == 'Overseas': supply_type = 'EXPWOP'
elif invoice.gst_category == 'Deemed Export': supply_type = 'DEXP'
- if not supply_type:
+ if not supply_type:
rr, sez, overseas, export = bold('Registered Regular'), bold('SEZ'), bold('Overseas'), bold('Deemed Export')
frappe.throw(_('GST category should be one of {}, {}, {}, {}').format(rr, sez, overseas, export),
title=_('Invalid Supply Type'))
@@ -128,7 +128,7 @@
if details:
frappe.local.gstin_cache[key] = details
return details
-
+
if not details:
return GSPConnector.get_gstin_details(gstin)
@@ -174,7 +174,7 @@
item.serial_no = ""
item = update_item_taxes(invoice, item)
-
+
item.total_value = abs(
item.taxable_value + item.igst_amount + item.sgst_amount +
item.cgst_amount + item.cess_amount + item.cess_nadv_amount + item.other_charges
@@ -232,9 +232,9 @@
invoice_value_details.round_off = invoice.base_rounding_adjustment
invoice_value_details.base_grand_total = abs(invoice.base_rounded_total) or abs(invoice.base_grand_total)
invoice_value_details.grand_total = abs(invoice.rounded_total) or abs(invoice.grand_total)
-
+
invoice_value_details = update_invoice_taxes(invoice, invoice_value_details)
-
+
return invoice_value_details
def update_invoice_taxes(invoice, invoice_value_details):
@@ -251,13 +251,13 @@
if t.account_head in gst_accounts.cess_account:
# using after discount amt since item also uses after discount amt for cess calc
invoice_value_details.total_cess_amt += abs(t.base_tax_amount_after_discount_amount)
-
+
for tax_type in ['igst', 'cgst', 'sgst']:
if t.account_head in gst_accounts[f'{tax_type}_account']:
invoice_value_details[f'total_{tax_type}_amt'] += abs(t.base_tax_amount_after_discount_amount)
else:
invoice_value_details.total_other_charges += abs(t.base_tax_amount_after_discount_amount)
-
+
return invoice_value_details
def get_payment_details(invoice):
@@ -329,23 +329,23 @@
place_of_supply = get_place_of_supply(invoice, invoice.doctype) or invoice.billing_address_gstin
place_of_supply = place_of_supply[:2]
buyer_details.update(dict(place_of_supply=place_of_supply))
-
+
shipping_details = payment_details = prev_doc_details = eway_bill_details = frappe._dict({})
if invoice.shipping_address_name and invoice.customer_address != invoice.shipping_address_name:
if invoice.gst_category == 'Overseas':
shipping_details = get_overseas_address_details(invoice.shipping_address_name)
else:
shipping_details = get_party_details(invoice.shipping_address_name)
-
+
if invoice.is_pos and invoice.base_paid_amount:
payment_details = get_payment_details(invoice)
-
+
if invoice.is_return and invoice.return_against:
prev_doc_details = get_return_doc_reference(invoice)
-
+
if invoice.transporter:
eway_bill_details = get_eway_bill_details(invoice)
-
+
# not yet implemented
dispatch_details = period_details = export_details = frappe._dict({})
@@ -357,7 +357,7 @@
export_details=export_details, eway_bill_details=eway_bill_details
)
einvoice = json.loads(einvoice)
-
+
validations = json.loads(read_json('einv_validation'))
errors = validate_einvoice(validations, einvoice)
if errors:
@@ -419,7 +419,7 @@
errors.append(_('{} {} should be between {} and {}').format(label, value, minimum, maximum))
if pattern_str and not pattern.match(value):
errors.append(field_validation.get('validationMsg'))
-
+
return errors
class RequestFailed(Exception): pass
@@ -452,19 +452,19 @@
else:
credentials = self.e_invoice_settings.credentials[0] if self.e_invoice_settings.credentials else None
return credentials
-
+
def get_seller_gstin(self):
gstin = self.invoice.company_gstin or frappe.db.get_value('Address', self.invoice.company_address, 'gstin')
if not gstin:
frappe.throw(_('Cannot retrieve Company GSTIN. Please select company address with valid GSTIN.'))
return gstin
-
+
def get_auth_token(self):
if time_diff_in_seconds(self.e_invoice_settings.token_expiry, now_datetime()) < 150.0:
self.fetch_auth_token()
-
+
return self.e_invoice_settings.auth_token
-
+
def make_request(self, request_type, url, headers=None, data=None):
if request_type == 'post':
res = make_post_request(url, headers=headers, data=data)
@@ -473,7 +473,7 @@
self.log_request(url, headers, data, res)
return res
-
+
def log_request(self, url, headers, data, res):
headers.update({ 'password': self.credentials.password })
request_log = frappe.get_doc({
@@ -504,7 +504,7 @@
except Exception:
self.log_error(res)
self.raise_error(True)
-
+
def get_headers(self):
return {
'content-type': 'application/json',
@@ -526,7 +526,7 @@
else:
self.log_error(res)
raise RequestFailed
-
+
except RequestFailed:
self.raise_error()
@@ -571,7 +571,7 @@
else:
raise RequestFailed
-
+
except RequestFailed:
errors = self.sanitize_error_message(res.get('message'))
self.raise_error(errors=errors)
@@ -579,7 +579,7 @@
except Exception:
self.log_error(data)
self.raise_error(True)
-
+
def get_irn_details(self, irn):
headers = self.get_headers()
@@ -590,7 +590,7 @@
return res.get('result')
else:
raise RequestFailed
-
+
except RequestFailed:
errors = self.sanitize_error_message(res.get('message'))
self.raise_error(errors=errors)
@@ -598,7 +598,7 @@
except Exception:
self.log_error()
self.raise_error(True)
-
+
def cancel_irn(self, irn, reason, remark):
headers = self.get_headers()
data = json.dumps({
@@ -620,7 +620,7 @@
else:
raise RequestFailed
-
+
except RequestFailed:
errors = self.sanitize_error_message(res.get('message'))
self.raise_error(errors=errors)
@@ -669,7 +669,7 @@
except Exception:
self.log_error(data)
self.raise_error(True)
-
+
def cancel_eway_bill(self, eway_bill, reason, remark):
headers = self.get_headers()
data = json.dumps({
@@ -701,7 +701,7 @@
except Exception:
self.log_error(data)
self.raise_error(True)
-
+
def sanitize_error_message(self, message):
'''
On validation errors, response message looks something like this:
@@ -740,7 +740,7 @@
"Exception:", err_tb
])
frappe.log_error(title=_('E Invoice Request Failed'), message=message)
-
+
def raise_error(self, raise_exception=False, errors=[]):
title = _('E Invoice Request Failed')
if errors:
@@ -753,7 +753,7 @@
raise_exception=raise_exception,
indicator='red'
)
-
+
def set_einvoice_data(self, res):
enc_signed_invoice = res.get('SignedInvoice')
dec_signed_invoice = jwt.decode(enc_signed_invoice, verify=False)['data']
@@ -792,7 +792,7 @@
_file.save()
frappe.db.commit()
self.invoice.qrcode_image = _file.file_url
-
+
def update_invoice(self):
self.invoice.flags.ignore_validate_update_after_submit = True
self.invoice.flags.ignore_validate = True
diff --git a/erpnext/regional/india/gst_state_code_data.json b/erpnext/regional/india/gst_state_code_data.json
index ff88e0f..8481c27 100644
--- a/erpnext/regional/india/gst_state_code_data.json
+++ b/erpnext/regional/india/gst_state_code_data.json
@@ -168,5 +168,10 @@
"state_number": "37",
"state_code": "AD",
"state_name": "Andhra Pradesh (New)"
+ },
+ {
+ "state_number": "38",
+ "state_code": "LA",
+ "state_name": "Ladakh"
}
]
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index e492377..e3b41e6 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -514,7 +514,7 @@
make_delivery_note: function() {
frappe.model.open_mapped_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_delivery_note",
- frm: me.frm
+ frm: this.frm
})
},
diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py
index 3c9f849..681d161 100644
--- a/erpnext/shopping_cart/cart.py
+++ b/erpnext/shopping_cart/cart.py
@@ -462,6 +462,9 @@
return customer
def get_debtors_account(cart_settings):
+ if not cart_settings.payment_gateway_account:
+ frappe.throw(_("Payment Gateway Account not set"), _("Mandatory"))
+
payment_gateway_account_currency = \
frappe.get_doc("Payment Gateway Account", cart_settings.payment_gateway_account).currency
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json
index 702583a..3691721 100644
--- a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json
+++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json
@@ -26,10 +26,10 @@
"quotation_series",
"section_break_8",
"enable_checkout",
- "payment_success_url",
- "column_break_11",
"save_quotations_as_draft",
- "payment_gateway_account"
+ "column_break_11",
+ "payment_gateway_account",
+ "payment_success_url"
],
"fields": [
{
@@ -143,10 +143,12 @@
},
{
"default": "Orders",
+ "depends_on": "enable_checkout",
"description": "After payment completion redirect user to selected page.",
"fieldname": "payment_success_url",
"fieldtype": "Select",
"label": "Payment Success Url",
+ "mandatory_depends_on": "enable_checkout",
"options": "\nOrders\nInvoices\nMy Account"
},
{
@@ -154,9 +156,11 @@
"fieldtype": "Column Break"
},
{
+ "depends_on": "enable_checkout",
"fieldname": "payment_gateway_account",
"fieldtype": "Link",
"label": "Payment Gateway Account",
+ "mandatory_depends_on": "enable_checkout",
"options": "Payment Gateway Account"
},
{
@@ -186,7 +190,7 @@
"idx": 1,
"issingle": 1,
"links": [],
- "modified": "2021-02-01 18:18:54.606535",
+ "modified": "2021-02-11 18:48:30.433058",
"modified_by": "Administrator",
"module": "Shopping Cart",
"name": "Shopping Cart Settings",
diff --git a/erpnext/stock/__init__.py b/erpnext/stock/__init__.py
index 8d64efe..b3ae804 100644
--- a/erpnext/stock/__init__.py
+++ b/erpnext/stock/__init__.py
@@ -64,7 +64,7 @@
if not account and warehouse.company:
account = get_company_default_inventory_account(warehouse.company)
- if not account and warehouse.company:
+ if not account and warehouse.company and not warehouse.is_group:
frappe.throw(_("Please set Account in Warehouse {0} or Default Inventory Account in Company {1}")
.format(warehouse.name, warehouse.company))
return account
diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py
index 97f85ba..cbd272d 100644
--- a/erpnext/stock/doctype/batch/test_batch.py
+++ b/erpnext/stock/doctype/batch/test_batch.py
@@ -298,9 +298,9 @@
self.assertEqual(details.get('price_list_rate'), 400)
def create_batch(item_code, rate, create_item_price_for_batch):
- pi = make_purchase_invoice(company="_Test Company with perpetual inventory",
- warehouse= "Stores - TCP1", cost_center = "Main - TCP1", update_stock=1,
- expense_account ="_Test Account Cost for Goods Sold - TCP1", item_code=item_code)
+ pi = make_purchase_invoice(company="_Test Company",
+ warehouse= "Stores - _TC", cost_center = "Main - _TC", update_stock=1,
+ expense_account ="_Test Account Cost for Goods Sold - _TC", item_code=item_code)
batch = frappe.db.get_value('Batch', {'item': item_code, 'reference_name': pi.name})
diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
index 144101c..984ae46 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
@@ -148,7 +148,6 @@
def test_landed_cost_voucher_for_odd_numbers (self):
-
pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1", do_not_save=True)
pr.items[0].cost_center = "Main - TCP1"
for x in range(2):
@@ -208,6 +207,10 @@
self.assertEqual(pr.items[1].landed_cost_voucher_amount, 100)
def test_multi_currency_lcv(self):
+ from erpnext.setup.doctype.currency_exchange.test_currency_exchange import test_records, save_new_records
+
+ save_new_records(test_records)
+
## Create USD Shipping charges_account
usd_shipping = create_account(account_name="Shipping Charges USD",
parent_account="Duties and Taxes - TCP1", company="_Test Company with perpetual inventory",
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
index ba2c2c6..f22c601 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
@@ -64,7 +64,7 @@
message += "<br>" + "Traceback: <br>" + traceback
frappe.db.set_value(doc.doctype, doc.name, 'error_log', message)
- notify_error_to_stock_managers(doc)
+ notify_error_to_stock_managers(doc, message)
doc.set_status('Failed')
raise
finally:
diff --git a/erpnext/stock/doctype/shipment/test_shipment.py b/erpnext/stock/doctype/shipment/test_shipment.py
index e1fa207..9c3e22f 100644
--- a/erpnext/stock/doctype/shipment/test_shipment.py
+++ b/erpnext/stock/doctype/shipment/test_shipment.py
@@ -190,6 +190,7 @@
company.abbr = abbr
company.default_currency = 'EUR'
company.country = 'Germany'
+ company.enable_perpetual_inventory = 0
company.insert()
return company
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 95f8c43..21860b6 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -194,6 +194,8 @@
self.process_sle(sle)
def get_sle_against_current_voucher(self):
+ self.args['time_format'] = '%H:%i:%s'
+
return frappe.db.sql("""
select
*, timestamp(posting_date, posting_time) as "timestamp"
@@ -202,7 +204,8 @@
where
item_code = %(item_code)s
and warehouse = %(warehouse)s
- and timestamp(posting_date, time_format(posting_time, '%H:%i:%s')) = timestamp(%(posting_date)s, time_format(%(posting_time)s, '%H:%i:%s'))
+ and voucher_type = %(voucher_type)s
+ and voucher_no = %(voucher_no)s
order by
creation ASC
for update
diff --git a/requirements.txt b/requirements.txt
index 4511aa5..5a35236 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,7 +3,7 @@
gocardless-pro==1.11.0
googlemaps==3.1.1
pandas>=1.0.5
-plaid-python==6.0.0
+plaid-python>=7.0.0
pycountry==19.8.18
PyGithub==1.44.1
python-stdnum==1.12
@@ -12,4 +12,4 @@
tweepy==3.8.0
Unidecode==1.1.1
WooCommerce==2.1.1
-pycryptodome==3.9.8
\ No newline at end of file
+pycryptodome==3.9.8