Merge branch 'develop' into quality-inspection-parameter-group
This commit is contained in:
commit
208d1942c3
@ -82,7 +82,7 @@ def get_fiscal_years(transaction_date=None, fiscal_year=None, label="Date", verb
|
|||||||
error_msg = _("""{0} {1} is not in any active Fiscal Year""").format(label, formatdate(transaction_date))
|
error_msg = _("""{0} {1} is not in any active Fiscal Year""").format(label, formatdate(transaction_date))
|
||||||
if company:
|
if company:
|
||||||
error_msg = _("""{0} for {1}""").format(error_msg, frappe.bold(company))
|
error_msg = _("""{0} for {1}""").format(error_msg, frappe.bold(company))
|
||||||
|
|
||||||
if verbose==1: frappe.msgprint(error_msg)
|
if verbose==1: frappe.msgprint(error_msg)
|
||||||
raise FiscalYearError(error_msg)
|
raise FiscalYearError(error_msg)
|
||||||
|
|
||||||
@ -888,17 +888,22 @@ def get_coa(doctype, parent, is_root, chart=None):
|
|||||||
|
|
||||||
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
|
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
|
||||||
warehouse_account=None, company=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):
|
def _delete_gl_entries(voucher_type, voucher_no):
|
||||||
frappe.db.sql("""delete from `tabGL Entry`
|
frappe.db.sql("""delete from `tabGL Entry`
|
||||||
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
|
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
|
||||||
|
|
||||||
|
|
||||||
if not warehouse_account:
|
if not warehouse_account:
|
||||||
warehouse_account = get_warehouse_account_map(company)
|
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(stock_vouchers, posting_date)
|
||||||
gle = get_voucherwise_gl_entries(future_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), [])
|
existing_gle = gle.get((voucher_type, voucher_no), [])
|
||||||
voucher_obj = frappe.get_doc(voucher_type, voucher_no)
|
voucher_obj = frappe.get_doc(voucher_type, voucher_no)
|
||||||
expected_gle = voucher_obj.get_gl_entries(warehouse_account)
|
expected_gle = voucher_obj.get_gl_entries(warehouse_account)
|
||||||
@ -909,7 +914,7 @@ def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for
|
|||||||
else:
|
else:
|
||||||
_delete_gl_entries(voucher_type, voucher_no)
|
_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 = []
|
future_stock_vouchers = []
|
||||||
|
|
||||||
values = []
|
values = []
|
||||||
@ -922,6 +927,10 @@ def get_future_stock_vouchers(posting_date, posting_time, for_warehouses=None, f
|
|||||||
condition += " and warehouse in ({})".format(", ".join(["%s"] * len(for_warehouses)))
|
condition += " and warehouse in ({})".format(", ".join(["%s"] * len(for_warehouses)))
|
||||||
values += 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
|
for d in frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no
|
||||||
from `tabStock Ledger Entry` sle
|
from `tabStock Ledger Entry` sle
|
||||||
where
|
where
|
||||||
@ -982,7 +991,7 @@ def check_if_stock_and_account_balance_synced(posting_date, company, voucher_typ
|
|||||||
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(
|
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)
|
stock_bal, account_bal, frappe.bold(account), posting_date)
|
||||||
error_resolution = _("Please create an adjustment Journal Entry for amount {0} on {1}")\
|
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(
|
frappe.msgprint(
|
||||||
msg="""{0}<br></br>{1}<br></br>""".format(error_reason, error_resolution),
|
msg="""{0}<br></br>{1}<br></br>""".format(error_reason, error_resolution),
|
||||||
|
|||||||
@ -1309,45 +1309,28 @@ def add_taxes_from_tax_template(child_item, parent_doc):
|
|||||||
})
|
})
|
||||||
tax_row.db_insert()
|
tax_row.db_insert()
|
||||||
|
|
||||||
def set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, trans_item):
|
def set_order_defaults(parent_doctype, parent_doctype_name, child_doctype, child_docname, trans_item):
|
||||||
"""
|
"""
|
||||||
Returns a Sales Order Item child item containing the default values
|
Returns a Sales/Purchase Order Item child item containing the default values
|
||||||
"""
|
"""
|
||||||
p_doc = frappe.get_doc(parent_doctype, parent_doctype_name)
|
p_doc = frappe.get_doc(parent_doctype, parent_doctype_name)
|
||||||
child_item = frappe.new_doc('Sales Order Item', p_doc, child_docname)
|
child_item = frappe.new_doc(child_doctype, p_doc, child_docname)
|
||||||
item = frappe.get_doc("Item", trans_item.get('item_code'))
|
item = frappe.get_doc("Item", trans_item.get('item_code'))
|
||||||
child_item.item_code = item.item_code
|
for field in ("item_code", "item_name", "description", "item_group"):
|
||||||
child_item.item_name = item.item_name
|
child_item.update({field: item.get(field)})
|
||||||
child_item.description = item.description
|
date_fieldname = "delivery_date" if child_doctype == "Sales Order Item" else "schedule_date"
|
||||||
child_item.delivery_date = trans_item.get('delivery_date') or p_doc.delivery_date
|
child_item.update({date_fieldname: trans_item.get(date_fieldname) or p_doc.get(date_fieldname)})
|
||||||
child_item.uom = trans_item.get("uom") or item.stock_uom
|
child_item.uom = trans_item.get("uom") or item.stock_uom
|
||||||
conversion_factor = flt(get_conversion_factor(item.item_code, child_item.uom).get("conversion_factor"))
|
conversion_factor = flt(get_conversion_factor(item.item_code, child_item.uom).get("conversion_factor"))
|
||||||
child_item.conversion_factor = flt(trans_item.get('conversion_factor')) or conversion_factor
|
child_item.conversion_factor = flt(trans_item.get('conversion_factor')) or conversion_factor
|
||||||
set_child_tax_template_and_map(item, child_item, p_doc)
|
if child_doctype == "Purchase Order Item":
|
||||||
add_taxes_from_tax_template(child_item, p_doc)
|
child_item.base_rate = 1 # Initiallize value will update in parent validation
|
||||||
child_item.warehouse = get_item_warehouse(item, p_doc, overwrite_warehouse=True)
|
child_item.base_amount = 1 # Initiallize value will update in parent validation
|
||||||
if not child_item.warehouse:
|
if child_doctype == "Sales Order Item":
|
||||||
frappe.throw(_("Cannot find {} for item {}. Please set the same in Item Master or Stock Settings.")
|
child_item.warehouse = get_item_warehouse(item, p_doc, overwrite_warehouse=True)
|
||||||
.format(frappe.bold("default warehouse"), frappe.bold(item.item_code)))
|
if not child_item.warehouse:
|
||||||
return child_item
|
frappe.throw(_("Cannot find {} for item {}. Please set the same in Item Master or Stock Settings.")
|
||||||
|
.format(frappe.bold("default warehouse"), frappe.bold(item.item_code)))
|
||||||
|
|
||||||
def set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, trans_item):
|
|
||||||
"""
|
|
||||||
Returns a Purchase Order Item child item containing the default values
|
|
||||||
"""
|
|
||||||
p_doc = frappe.get_doc(parent_doctype, parent_doctype_name)
|
|
||||||
child_item = frappe.new_doc('Purchase Order Item', p_doc, child_docname)
|
|
||||||
item = frappe.get_doc("Item", trans_item.get('item_code'))
|
|
||||||
child_item.item_code = item.item_code
|
|
||||||
child_item.item_name = item.item_name
|
|
||||||
child_item.description = item.description
|
|
||||||
child_item.schedule_date = trans_item.get('schedule_date') or p_doc.schedule_date
|
|
||||||
child_item.uom = trans_item.get("uom") or item.stock_uom
|
|
||||||
conversion_factor = flt(get_conversion_factor(item.item_code, child_item.uom).get("conversion_factor"))
|
|
||||||
child_item.conversion_factor = flt(trans_item.get('conversion_factor')) or conversion_factor
|
|
||||||
child_item.base_rate = 1 # Initiallize value will update in parent validation
|
|
||||||
child_item.base_amount = 1 # Initiallize value will update in parent validation
|
|
||||||
set_child_tax_template_and_map(item, child_item, p_doc)
|
set_child_tax_template_and_map(item, child_item, p_doc)
|
||||||
add_taxes_from_tax_template(child_item, p_doc)
|
add_taxes_from_tax_template(child_item, p_doc)
|
||||||
return child_item
|
return child_item
|
||||||
@ -1411,8 +1394,8 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
|
|||||||
)
|
)
|
||||||
|
|
||||||
def get_new_child_item(item_row):
|
def get_new_child_item(item_row):
|
||||||
new_child_function = set_sales_order_defaults if parent_doctype == "Sales Order" else set_purchase_order_defaults
|
child_doctype = "Sales Order Item" if parent_doctype == "Sales Order" else "Purchase Order Item"
|
||||||
return new_child_function(parent_doctype, parent_doctype_name, child_docname, item_row)
|
return set_order_defaults(parent_doctype, parent_doctype_name, child_doctype, child_docname, item_row)
|
||||||
|
|
||||||
def validate_quantity(child_item, d):
|
def validate_quantity(child_item, d):
|
||||||
if parent_doctype == "Sales Order" and flt(d.get("qty")) < flt(child_item.delivered_qty):
|
if parent_doctype == "Sales Order" and flt(d.get("qty")) < flt(child_item.delivered_qty):
|
||||||
|
|||||||
@ -488,13 +488,12 @@ class StockController(AccountsController):
|
|||||||
"voucher_no": self.name,
|
"voucher_no": self.name,
|
||||||
"company": self.company
|
"company": self.company
|
||||||
})
|
})
|
||||||
|
|
||||||
if check_if_future_sle_exists(args):
|
if check_if_future_sle_exists(args):
|
||||||
create_repost_item_valuation_entry(args)
|
create_repost_item_valuation_entry(args)
|
||||||
elif not is_reposting_pending():
|
elif not is_reposting_pending():
|
||||||
check_if_stock_and_account_balance_synced(self.posting_date,
|
check_if_stock_and_account_balance_synced(self.posting_date,
|
||||||
self.company, self.doctype, self.name)
|
self.company, self.doctype, self.name)
|
||||||
|
|
||||||
def is_reposting_pending():
|
def is_reposting_pending():
|
||||||
return frappe.db.exists("Repost Item Valuation",
|
return frappe.db.exists("Repost Item Valuation",
|
||||||
{'docstatus': 1, 'status': ['in', ['Queued','In Progress']]})
|
{'docstatus': 1, 'status': ['in', ['Queued','In Progress']]})
|
||||||
|
|||||||
@ -20,7 +20,7 @@ class PlaidConnector():
|
|||||||
client_id=self.settings.plaid_client_id,
|
client_id=self.settings.plaid_client_id,
|
||||||
secret=self.settings.get_password("plaid_secret"),
|
secret=self.settings.get_password("plaid_secret"),
|
||||||
environment=self.settings.plaid_env,
|
environment=self.settings.plaid_env,
|
||||||
api_version="2019-05-29"
|
api_version="2020-09-14"
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_access_token(self, public_token):
|
def get_access_token(self, public_token):
|
||||||
@ -29,7 +29,7 @@ class PlaidConnector():
|
|||||||
response = self.client.Item.public_token.exchange(public_token)
|
response = self.client.Item.public_token.exchange(public_token)
|
||||||
access_token = response["access_token"]
|
access_token = response["access_token"]
|
||||||
return access_token
|
return access_token
|
||||||
|
|
||||||
def get_token_request(self, update_mode=False):
|
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"]
|
country_codes = ["US", "CA", "FR", "IE", "NL", "ES", "GB"] if self.settings.enable_european_access else ["US", "CA"]
|
||||||
args = {
|
args = {
|
||||||
|
|||||||
@ -121,6 +121,7 @@ class ClinicalProcedure(Document):
|
|||||||
|
|
||||||
stock_entry.stock_entry_type = 'Material Receipt'
|
stock_entry.stock_entry_type = 'Material Receipt'
|
||||||
stock_entry.to_warehouse = self.warehouse
|
stock_entry.to_warehouse = self.warehouse
|
||||||
|
stock_entry.company = self.company
|
||||||
expense_account = get_account(None, 'expense_account', 'Healthcare Settings', self.company)
|
expense_account = get_account(None, 'expense_account', 'Healthcare Settings', self.company)
|
||||||
for item in self.items:
|
for item in self.items:
|
||||||
if item.qty > item.actual_qty:
|
if item.qty > item.actual_qty:
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (c) 2017, ESS LLP and Contributors
|
# Copyright (c) 2017, ESS LLP and Contributors
|
||||||
# See license.txt
|
# See license.txt
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
@ -60,6 +60,7 @@ def create_procedure(procedure_template, patient, practitioner):
|
|||||||
procedure.practitioner = practitioner
|
procedure.practitioner = practitioner
|
||||||
procedure.consume_stock = procedure_template.allow_stock_consumption
|
procedure.consume_stock = procedure_template.allow_stock_consumption
|
||||||
procedure.items = procedure_template.items
|
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()
|
procedure.submit()
|
||||||
return procedure
|
return procedure
|
||||||
@ -752,3 +752,5 @@ erpnext.patches.v13_0.set_company_in_leave_ledger_entry
|
|||||||
erpnext.patches.v13_0.convert_qi_parameter_to_link_field
|
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.setup_patient_history_settings_for_standard_doctypes
|
||||||
erpnext.patches.v13_0.add_naming_series_to_old_projects # 1-02-2021
|
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
|
||||||
|
|||||||
16
erpnext/patches/v12_0/add_state_code_for_ladakh.py
Normal file
16
erpnext/patches/v12_0/add_state_code_for_ladakh.py
Normal file
@ -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()
|
||||||
@ -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
|
||||||
BIN
erpnext/public/images/erpnext-logo.png
Normal file
BIN
erpnext/public/images/erpnext-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
@ -140,6 +140,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
|||||||
() => me.update_batch_serial_no_items(),
|
() => me.update_batch_serial_no_items(),
|
||||||
() => {
|
() => {
|
||||||
refresh_field("items");
|
refresh_field("items");
|
||||||
|
refresh_field("packed_items");
|
||||||
if (me.callback) {
|
if (me.callback) {
|
||||||
return me.callback(me.item);
|
return me.callback(me.item);
|
||||||
}
|
}
|
||||||
@ -154,7 +155,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
|||||||
if (this.item.serial_no) {
|
if (this.item.serial_no) {
|
||||||
this.dialog.fields_dict.serial_no.set_value(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) {
|
if (this.has_batch && !this.has_serial_no && d.batch_no) {
|
||||||
this.frm.doc.items.forEach(data => {
|
this.frm.doc.items.forEach(data => {
|
||||||
if(data.item_code == d.item_code) {
|
if(data.item_code == d.item_code) {
|
||||||
@ -231,7 +232,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
|||||||
this.map_row_values(row, batch, 'batch_no',
|
this.map_row_values(row, batch, 'batch_no',
|
||||||
'selected_qty', this.values.warehouse);
|
'selected_qty', this.values.warehouse);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
update_serial_no_item() {
|
update_serial_no_item() {
|
||||||
@ -250,7 +251,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
|||||||
filters: { 'name': ["in", selected_serial_nos]},
|
filters: { 'name': ["in", selected_serial_nos]},
|
||||||
fields: ["batch_no", "name"]
|
fields: ["batch_no", "name"]
|
||||||
}).then((data) => {
|
}).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"}]
|
// {batch_no: 'batch-2', name: "SR-003"}, {batch_no: 'batch-2', name: "SR-004"}]
|
||||||
const batch_serial_map = data.reduce((acc, d) => {
|
const batch_serial_map = data.reduce((acc, d) => {
|
||||||
if (!acc[d['batch_no']]) acc[d['batch_no']] = [];
|
if (!acc[d['batch_no']]) acc[d['batch_no']] = [];
|
||||||
@ -298,6 +299,8 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
|||||||
} else {
|
} else {
|
||||||
row.warehouse = values.warehouse || warehouse;
|
row.warehouse = values.warehouse || warehouse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.frm.dirty();
|
||||||
},
|
},
|
||||||
|
|
||||||
update_total_qty: function() {
|
update_total_qty: function() {
|
||||||
|
|||||||
@ -32,7 +32,12 @@ body[data-route*="marketplace"] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.hub-image-loading, .hub-image-broken {
|
.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;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|||||||
@ -5,12 +5,16 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import getdate
|
from frappe.utils import getdate, get_link_to_form
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
|
|
||||||
class LowerDeductionCertificate(Document):
|
class LowerDeductionCertificate(Document):
|
||||||
def validate(self):
|
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):
|
if getdate(self.valid_upto) < getdate(self.valid_from):
|
||||||
frappe.throw(_("Valid Upto date cannot be before Valid From date"))
|
frappe.throw(_("Valid Upto date cannot be before Valid From date"))
|
||||||
|
|
||||||
@ -24,3 +28,20 @@ class LowerDeductionCertificate(Document):
|
|||||||
<= fiscal_year.year_end_date):
|
<= fiscal_year.year_end_date):
|
||||||
frappe.throw(_("Valid Upto date not in Fiscal Year {0}").format(frappe.bold(self.fiscal_year)))
|
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
|
||||||
@ -20,6 +20,7 @@ states = [
|
|||||||
'Jharkhand',
|
'Jharkhand',
|
||||||
'Karnataka',
|
'Karnataka',
|
||||||
'Kerala',
|
'Kerala',
|
||||||
|
'Ladakh',
|
||||||
'Lakshadweep Islands',
|
'Lakshadweep Islands',
|
||||||
'Madhya Pradesh',
|
'Madhya Pradesh',
|
||||||
'Maharashtra',
|
'Maharashtra',
|
||||||
@ -59,6 +60,7 @@ state_numbers = {
|
|||||||
"Jharkhand": "20",
|
"Jharkhand": "20",
|
||||||
"Karnataka": "29",
|
"Karnataka": "29",
|
||||||
"Kerala": "32",
|
"Kerala": "32",
|
||||||
|
"Ladakh": "38",
|
||||||
"Lakshadweep Islands": "31",
|
"Lakshadweep Islands": "31",
|
||||||
"Madhya Pradesh": "23",
|
"Madhya Pradesh": "23",
|
||||||
"Maharashtra": "27",
|
"Maharashtra": "27",
|
||||||
@ -80,4 +82,4 @@ state_numbers = {
|
|||||||
"West Bengal": "19",
|
"West Bengal": "19",
|
||||||
}
|
}
|
||||||
|
|
||||||
number_state_mapping = {v: k for k, v in iteritems(state_numbers)}
|
number_state_mapping = {v: k for k, v in iteritems(state_numbers)}
|
||||||
|
|||||||
@ -23,7 +23,7 @@ def validate_einvoice_fields(doc):
|
|||||||
invalid_doctype = doc.doctype != 'Sales Invoice'
|
invalid_doctype = doc.doctype != 'Sales Invoice'
|
||||||
invalid_supply_type = doc.get('gst_category') not in ['Registered Regular', 'SEZ', 'Overseas', 'Deemed Export']
|
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')
|
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:
|
if not einvoicing_enabled or invalid_doctype or invalid_supply_type or company_transaction or no_taxes_applied:
|
||||||
return
|
return
|
||||||
@ -63,7 +63,7 @@ def get_transaction_details(invoice):
|
|||||||
elif invoice.gst_category == 'Overseas': supply_type = 'EXPWOP'
|
elif invoice.gst_category == 'Overseas': supply_type = 'EXPWOP'
|
||||||
elif invoice.gst_category == 'Deemed Export': supply_type = 'DEXP'
|
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')
|
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),
|
frappe.throw(_('GST category should be one of {}, {}, {}, {}').format(rr, sez, overseas, export),
|
||||||
title=_('Invalid Supply Type'))
|
title=_('Invalid Supply Type'))
|
||||||
@ -128,7 +128,7 @@ def get_gstin_details(gstin):
|
|||||||
if details:
|
if details:
|
||||||
frappe.local.gstin_cache[key] = details
|
frappe.local.gstin_cache[key] = details
|
||||||
return details
|
return details
|
||||||
|
|
||||||
if not details:
|
if not details:
|
||||||
return GSPConnector.get_gstin_details(gstin)
|
return GSPConnector.get_gstin_details(gstin)
|
||||||
|
|
||||||
@ -174,7 +174,7 @@ def get_item_list(invoice):
|
|||||||
item.serial_no = ""
|
item.serial_no = ""
|
||||||
|
|
||||||
item = update_item_taxes(invoice, item)
|
item = update_item_taxes(invoice, item)
|
||||||
|
|
||||||
item.total_value = abs(
|
item.total_value = abs(
|
||||||
item.taxable_value + item.igst_amount + item.sgst_amount +
|
item.taxable_value + item.igst_amount + item.sgst_amount +
|
||||||
item.cgst_amount + item.cess_amount + item.cess_nadv_amount + item.other_charges
|
item.cgst_amount + item.cess_amount + item.cess_nadv_amount + item.other_charges
|
||||||
@ -232,9 +232,9 @@ def get_invoice_value_details(invoice):
|
|||||||
invoice_value_details.round_off = invoice.base_rounding_adjustment
|
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.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.grand_total = abs(invoice.rounded_total) or abs(invoice.grand_total)
|
||||||
|
|
||||||
invoice_value_details = update_invoice_taxes(invoice, invoice_value_details)
|
invoice_value_details = update_invoice_taxes(invoice, invoice_value_details)
|
||||||
|
|
||||||
return invoice_value_details
|
return invoice_value_details
|
||||||
|
|
||||||
def update_invoice_taxes(invoice, invoice_value_details):
|
def update_invoice_taxes(invoice, invoice_value_details):
|
||||||
@ -251,13 +251,13 @@ def update_invoice_taxes(invoice, invoice_value_details):
|
|||||||
if t.account_head in gst_accounts.cess_account:
|
if t.account_head in gst_accounts.cess_account:
|
||||||
# using after discount amt since item also uses after discount amt for cess calc
|
# 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)
|
invoice_value_details.total_cess_amt += abs(t.base_tax_amount_after_discount_amount)
|
||||||
|
|
||||||
for tax_type in ['igst', 'cgst', 'sgst']:
|
for tax_type in ['igst', 'cgst', 'sgst']:
|
||||||
if t.account_head in gst_accounts[f'{tax_type}_account']:
|
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)
|
invoice_value_details[f'total_{tax_type}_amt'] += abs(t.base_tax_amount_after_discount_amount)
|
||||||
else:
|
else:
|
||||||
invoice_value_details.total_other_charges += abs(t.base_tax_amount_after_discount_amount)
|
invoice_value_details.total_other_charges += abs(t.base_tax_amount_after_discount_amount)
|
||||||
|
|
||||||
return invoice_value_details
|
return invoice_value_details
|
||||||
|
|
||||||
def get_payment_details(invoice):
|
def get_payment_details(invoice):
|
||||||
@ -329,23 +329,23 @@ def make_einvoice(invoice):
|
|||||||
place_of_supply = get_place_of_supply(invoice, invoice.doctype) or invoice.billing_address_gstin
|
place_of_supply = get_place_of_supply(invoice, invoice.doctype) or invoice.billing_address_gstin
|
||||||
place_of_supply = place_of_supply[:2]
|
place_of_supply = place_of_supply[:2]
|
||||||
buyer_details.update(dict(place_of_supply=place_of_supply))
|
buyer_details.update(dict(place_of_supply=place_of_supply))
|
||||||
|
|
||||||
shipping_details = payment_details = prev_doc_details = eway_bill_details = frappe._dict({})
|
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.shipping_address_name and invoice.customer_address != invoice.shipping_address_name:
|
||||||
if invoice.gst_category == 'Overseas':
|
if invoice.gst_category == 'Overseas':
|
||||||
shipping_details = get_overseas_address_details(invoice.shipping_address_name)
|
shipping_details = get_overseas_address_details(invoice.shipping_address_name)
|
||||||
else:
|
else:
|
||||||
shipping_details = get_party_details(invoice.shipping_address_name)
|
shipping_details = get_party_details(invoice.shipping_address_name)
|
||||||
|
|
||||||
if invoice.is_pos and invoice.base_paid_amount:
|
if invoice.is_pos and invoice.base_paid_amount:
|
||||||
payment_details = get_payment_details(invoice)
|
payment_details = get_payment_details(invoice)
|
||||||
|
|
||||||
if invoice.is_return and invoice.return_against:
|
if invoice.is_return and invoice.return_against:
|
||||||
prev_doc_details = get_return_doc_reference(invoice)
|
prev_doc_details = get_return_doc_reference(invoice)
|
||||||
|
|
||||||
if invoice.transporter:
|
if invoice.transporter:
|
||||||
eway_bill_details = get_eway_bill_details(invoice)
|
eway_bill_details = get_eway_bill_details(invoice)
|
||||||
|
|
||||||
# not yet implemented
|
# not yet implemented
|
||||||
dispatch_details = period_details = export_details = frappe._dict({})
|
dispatch_details = period_details = export_details = frappe._dict({})
|
||||||
|
|
||||||
@ -357,7 +357,7 @@ def make_einvoice(invoice):
|
|||||||
export_details=export_details, eway_bill_details=eway_bill_details
|
export_details=export_details, eway_bill_details=eway_bill_details
|
||||||
)
|
)
|
||||||
einvoice = json.loads(einvoice)
|
einvoice = json.loads(einvoice)
|
||||||
|
|
||||||
validations = json.loads(read_json('einv_validation'))
|
validations = json.loads(read_json('einv_validation'))
|
||||||
errors = validate_einvoice(validations, einvoice)
|
errors = validate_einvoice(validations, einvoice)
|
||||||
if errors:
|
if errors:
|
||||||
@ -419,7 +419,7 @@ def validate_einvoice(validations, einvoice, errors=[]):
|
|||||||
errors.append(_('{} {} should be between {} and {}').format(label, value, minimum, maximum))
|
errors.append(_('{} {} should be between {} and {}').format(label, value, minimum, maximum))
|
||||||
if pattern_str and not pattern.match(value):
|
if pattern_str and not pattern.match(value):
|
||||||
errors.append(field_validation.get('validationMsg'))
|
errors.append(field_validation.get('validationMsg'))
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
class RequestFailed(Exception): pass
|
class RequestFailed(Exception): pass
|
||||||
@ -452,19 +452,19 @@ class GSPConnector():
|
|||||||
else:
|
else:
|
||||||
credentials = self.e_invoice_settings.credentials[0] if self.e_invoice_settings.credentials else None
|
credentials = self.e_invoice_settings.credentials[0] if self.e_invoice_settings.credentials else None
|
||||||
return credentials
|
return credentials
|
||||||
|
|
||||||
def get_seller_gstin(self):
|
def get_seller_gstin(self):
|
||||||
gstin = self.invoice.company_gstin or frappe.db.get_value('Address', self.invoice.company_address, 'gstin')
|
gstin = self.invoice.company_gstin or frappe.db.get_value('Address', self.invoice.company_address, 'gstin')
|
||||||
if not gstin:
|
if not gstin:
|
||||||
frappe.throw(_('Cannot retrieve Company GSTIN. Please select company address with valid GSTIN.'))
|
frappe.throw(_('Cannot retrieve Company GSTIN. Please select company address with valid GSTIN.'))
|
||||||
return gstin
|
return gstin
|
||||||
|
|
||||||
def get_auth_token(self):
|
def get_auth_token(self):
|
||||||
if time_diff_in_seconds(self.e_invoice_settings.token_expiry, now_datetime()) < 150.0:
|
if time_diff_in_seconds(self.e_invoice_settings.token_expiry, now_datetime()) < 150.0:
|
||||||
self.fetch_auth_token()
|
self.fetch_auth_token()
|
||||||
|
|
||||||
return self.e_invoice_settings.auth_token
|
return self.e_invoice_settings.auth_token
|
||||||
|
|
||||||
def make_request(self, request_type, url, headers=None, data=None):
|
def make_request(self, request_type, url, headers=None, data=None):
|
||||||
if request_type == 'post':
|
if request_type == 'post':
|
||||||
res = make_post_request(url, headers=headers, data=data)
|
res = make_post_request(url, headers=headers, data=data)
|
||||||
@ -473,7 +473,7 @@ class GSPConnector():
|
|||||||
|
|
||||||
self.log_request(url, headers, data, res)
|
self.log_request(url, headers, data, res)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def log_request(self, url, headers, data, res):
|
def log_request(self, url, headers, data, res):
|
||||||
headers.update({ 'password': self.credentials.password })
|
headers.update({ 'password': self.credentials.password })
|
||||||
request_log = frappe.get_doc({
|
request_log = frappe.get_doc({
|
||||||
@ -504,7 +504,7 @@ class GSPConnector():
|
|||||||
except Exception:
|
except Exception:
|
||||||
self.log_error(res)
|
self.log_error(res)
|
||||||
self.raise_error(True)
|
self.raise_error(True)
|
||||||
|
|
||||||
def get_headers(self):
|
def get_headers(self):
|
||||||
return {
|
return {
|
||||||
'content-type': 'application/json',
|
'content-type': 'application/json',
|
||||||
@ -526,7 +526,7 @@ class GSPConnector():
|
|||||||
else:
|
else:
|
||||||
self.log_error(res)
|
self.log_error(res)
|
||||||
raise RequestFailed
|
raise RequestFailed
|
||||||
|
|
||||||
except RequestFailed:
|
except RequestFailed:
|
||||||
self.raise_error()
|
self.raise_error()
|
||||||
|
|
||||||
@ -571,7 +571,7 @@ class GSPConnector():
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
raise RequestFailed
|
raise RequestFailed
|
||||||
|
|
||||||
except RequestFailed:
|
except RequestFailed:
|
||||||
errors = self.sanitize_error_message(res.get('message'))
|
errors = self.sanitize_error_message(res.get('message'))
|
||||||
self.raise_error(errors=errors)
|
self.raise_error(errors=errors)
|
||||||
@ -579,7 +579,7 @@ class GSPConnector():
|
|||||||
except Exception:
|
except Exception:
|
||||||
self.log_error(data)
|
self.log_error(data)
|
||||||
self.raise_error(True)
|
self.raise_error(True)
|
||||||
|
|
||||||
def get_irn_details(self, irn):
|
def get_irn_details(self, irn):
|
||||||
headers = self.get_headers()
|
headers = self.get_headers()
|
||||||
|
|
||||||
@ -590,7 +590,7 @@ class GSPConnector():
|
|||||||
return res.get('result')
|
return res.get('result')
|
||||||
else:
|
else:
|
||||||
raise RequestFailed
|
raise RequestFailed
|
||||||
|
|
||||||
except RequestFailed:
|
except RequestFailed:
|
||||||
errors = self.sanitize_error_message(res.get('message'))
|
errors = self.sanitize_error_message(res.get('message'))
|
||||||
self.raise_error(errors=errors)
|
self.raise_error(errors=errors)
|
||||||
@ -598,7 +598,7 @@ class GSPConnector():
|
|||||||
except Exception:
|
except Exception:
|
||||||
self.log_error()
|
self.log_error()
|
||||||
self.raise_error(True)
|
self.raise_error(True)
|
||||||
|
|
||||||
def cancel_irn(self, irn, reason, remark):
|
def cancel_irn(self, irn, reason, remark):
|
||||||
headers = self.get_headers()
|
headers = self.get_headers()
|
||||||
data = json.dumps({
|
data = json.dumps({
|
||||||
@ -620,7 +620,7 @@ class GSPConnector():
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
raise RequestFailed
|
raise RequestFailed
|
||||||
|
|
||||||
except RequestFailed:
|
except RequestFailed:
|
||||||
errors = self.sanitize_error_message(res.get('message'))
|
errors = self.sanitize_error_message(res.get('message'))
|
||||||
self.raise_error(errors=errors)
|
self.raise_error(errors=errors)
|
||||||
@ -669,7 +669,7 @@ class GSPConnector():
|
|||||||
except Exception:
|
except Exception:
|
||||||
self.log_error(data)
|
self.log_error(data)
|
||||||
self.raise_error(True)
|
self.raise_error(True)
|
||||||
|
|
||||||
def cancel_eway_bill(self, eway_bill, reason, remark):
|
def cancel_eway_bill(self, eway_bill, reason, remark):
|
||||||
headers = self.get_headers()
|
headers = self.get_headers()
|
||||||
data = json.dumps({
|
data = json.dumps({
|
||||||
@ -701,7 +701,7 @@ class GSPConnector():
|
|||||||
except Exception:
|
except Exception:
|
||||||
self.log_error(data)
|
self.log_error(data)
|
||||||
self.raise_error(True)
|
self.raise_error(True)
|
||||||
|
|
||||||
def sanitize_error_message(self, message):
|
def sanitize_error_message(self, message):
|
||||||
'''
|
'''
|
||||||
On validation errors, response message looks something like this:
|
On validation errors, response message looks something like this:
|
||||||
@ -740,7 +740,7 @@ class GSPConnector():
|
|||||||
"Exception:", err_tb
|
"Exception:", err_tb
|
||||||
])
|
])
|
||||||
frappe.log_error(title=_('E Invoice Request Failed'), message=message)
|
frappe.log_error(title=_('E Invoice Request Failed'), message=message)
|
||||||
|
|
||||||
def raise_error(self, raise_exception=False, errors=[]):
|
def raise_error(self, raise_exception=False, errors=[]):
|
||||||
title = _('E Invoice Request Failed')
|
title = _('E Invoice Request Failed')
|
||||||
if errors:
|
if errors:
|
||||||
@ -753,7 +753,7 @@ class GSPConnector():
|
|||||||
raise_exception=raise_exception,
|
raise_exception=raise_exception,
|
||||||
indicator='red'
|
indicator='red'
|
||||||
)
|
)
|
||||||
|
|
||||||
def set_einvoice_data(self, res):
|
def set_einvoice_data(self, res):
|
||||||
enc_signed_invoice = res.get('SignedInvoice')
|
enc_signed_invoice = res.get('SignedInvoice')
|
||||||
dec_signed_invoice = jwt.decode(enc_signed_invoice, verify=False)['data']
|
dec_signed_invoice = jwt.decode(enc_signed_invoice, verify=False)['data']
|
||||||
@ -792,7 +792,7 @@ class GSPConnector():
|
|||||||
_file.save()
|
_file.save()
|
||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
self.invoice.qrcode_image = _file.file_url
|
self.invoice.qrcode_image = _file.file_url
|
||||||
|
|
||||||
def update_invoice(self):
|
def update_invoice(self):
|
||||||
self.invoice.flags.ignore_validate_update_after_submit = True
|
self.invoice.flags.ignore_validate_update_after_submit = True
|
||||||
self.invoice.flags.ignore_validate = True
|
self.invoice.flags.ignore_validate = True
|
||||||
|
|||||||
@ -168,5 +168,10 @@
|
|||||||
"state_number": "37",
|
"state_number": "37",
|
||||||
"state_code": "AD",
|
"state_code": "AD",
|
||||||
"state_name": "Andhra Pradesh (New)"
|
"state_name": "Andhra Pradesh (New)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"state_number": "38",
|
||||||
|
"state_code": "LA",
|
||||||
|
"state_name": "Ladakh"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -514,7 +514,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
|||||||
make_delivery_note: function() {
|
make_delivery_note: function() {
|
||||||
frappe.model.open_mapped_doc({
|
frappe.model.open_mapped_doc({
|
||||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_delivery_note",
|
method: "erpnext.selling.doctype.sales_order.sales_order.make_delivery_note",
|
||||||
frm: me.frm
|
frm: this.frm
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -462,6 +462,9 @@ def get_party(user=None):
|
|||||||
return customer
|
return customer
|
||||||
|
|
||||||
def get_debtors_account(cart_settings):
|
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 = \
|
payment_gateway_account_currency = \
|
||||||
frappe.get_doc("Payment Gateway Account", cart_settings.payment_gateway_account).currency
|
frappe.get_doc("Payment Gateway Account", cart_settings.payment_gateway_account).currency
|
||||||
|
|
||||||
|
|||||||
@ -26,10 +26,10 @@
|
|||||||
"quotation_series",
|
"quotation_series",
|
||||||
"section_break_8",
|
"section_break_8",
|
||||||
"enable_checkout",
|
"enable_checkout",
|
||||||
"payment_success_url",
|
|
||||||
"column_break_11",
|
|
||||||
"save_quotations_as_draft",
|
"save_quotations_as_draft",
|
||||||
"payment_gateway_account"
|
"column_break_11",
|
||||||
|
"payment_gateway_account",
|
||||||
|
"payment_success_url"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -143,10 +143,12 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "Orders",
|
"default": "Orders",
|
||||||
|
"depends_on": "enable_checkout",
|
||||||
"description": "After payment completion redirect user to selected page.",
|
"description": "After payment completion redirect user to selected page.",
|
||||||
"fieldname": "payment_success_url",
|
"fieldname": "payment_success_url",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"label": "Payment Success Url",
|
"label": "Payment Success Url",
|
||||||
|
"mandatory_depends_on": "enable_checkout",
|
||||||
"options": "\nOrders\nInvoices\nMy Account"
|
"options": "\nOrders\nInvoices\nMy Account"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -154,9 +156,11 @@
|
|||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"depends_on": "enable_checkout",
|
||||||
"fieldname": "payment_gateway_account",
|
"fieldname": "payment_gateway_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Payment Gateway Account",
|
"label": "Payment Gateway Account",
|
||||||
|
"mandatory_depends_on": "enable_checkout",
|
||||||
"options": "Payment Gateway Account"
|
"options": "Payment Gateway Account"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -186,7 +190,7 @@
|
|||||||
"idx": 1,
|
"idx": 1,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-02-01 18:18:54.606535",
|
"modified": "2021-02-11 18:48:30.433058",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Shopping Cart",
|
"module": "Shopping Cart",
|
||||||
"name": "Shopping Cart Settings",
|
"name": "Shopping Cart Settings",
|
||||||
|
|||||||
@ -64,7 +64,7 @@ def get_warehouse_account(warehouse, warehouse_account=None):
|
|||||||
if not account and warehouse.company:
|
if not account and warehouse.company:
|
||||||
account = get_company_default_inventory_account(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}")
|
frappe.throw(_("Please set Account in Warehouse {0} or Default Inventory Account in Company {1}")
|
||||||
.format(warehouse.name, warehouse.company))
|
.format(warehouse.name, warehouse.company))
|
||||||
return account
|
return account
|
||||||
|
|||||||
@ -298,9 +298,9 @@ class TestBatch(unittest.TestCase):
|
|||||||
self.assertEqual(details.get('price_list_rate'), 400)
|
self.assertEqual(details.get('price_list_rate'), 400)
|
||||||
|
|
||||||
def create_batch(item_code, rate, create_item_price_for_batch):
|
def create_batch(item_code, rate, create_item_price_for_batch):
|
||||||
pi = make_purchase_invoice(company="_Test Company with perpetual inventory",
|
pi = make_purchase_invoice(company="_Test Company",
|
||||||
warehouse= "Stores - TCP1", cost_center = "Main - TCP1", update_stock=1,
|
warehouse= "Stores - _TC", cost_center = "Main - _TC", update_stock=1,
|
||||||
expense_account ="_Test Account Cost for Goods Sold - TCP1", item_code=item_code)
|
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})
|
batch = frappe.db.get_value('Batch', {'item': item_code, 'reference_name': pi.name})
|
||||||
|
|
||||||
|
|||||||
@ -148,7 +148,6 @@ class TestLandedCostVoucher(unittest.TestCase):
|
|||||||
|
|
||||||
|
|
||||||
def test_landed_cost_voucher_for_odd_numbers (self):
|
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 = 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"
|
pr.items[0].cost_center = "Main - TCP1"
|
||||||
for x in range(2):
|
for x in range(2):
|
||||||
@ -208,6 +207,10 @@ class TestLandedCostVoucher(unittest.TestCase):
|
|||||||
self.assertEqual(pr.items[1].landed_cost_voucher_amount, 100)
|
self.assertEqual(pr.items[1].landed_cost_voucher_amount, 100)
|
||||||
|
|
||||||
def test_multi_currency_lcv(self):
|
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
|
## Create USD Shipping charges_account
|
||||||
usd_shipping = create_account(account_name="Shipping Charges USD",
|
usd_shipping = create_account(account_name="Shipping Charges USD",
|
||||||
parent_account="Duties and Taxes - TCP1", company="_Test Company with perpetual inventory",
|
parent_account="Duties and Taxes - TCP1", company="_Test Company with perpetual inventory",
|
||||||
|
|||||||
@ -64,7 +64,7 @@ def repost(doc):
|
|||||||
message += "<br>" + "Traceback: <br>" + traceback
|
message += "<br>" + "Traceback: <br>" + traceback
|
||||||
frappe.db.set_value(doc.doctype, doc.name, 'error_log', message)
|
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')
|
doc.set_status('Failed')
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
@ -190,6 +190,7 @@ def create_shipment_company(company_name, abbr):
|
|||||||
company.abbr = abbr
|
company.abbr = abbr
|
||||||
company.default_currency = 'EUR'
|
company.default_currency = 'EUR'
|
||||||
company.country = 'Germany'
|
company.country = 'Germany'
|
||||||
|
company.enable_perpetual_inventory = 0
|
||||||
company.insert()
|
company.insert()
|
||||||
return company
|
return company
|
||||||
|
|
||||||
|
|||||||
@ -194,6 +194,8 @@ class update_entries_after(object):
|
|||||||
self.process_sle(sle)
|
self.process_sle(sle)
|
||||||
|
|
||||||
def get_sle_against_current_voucher(self):
|
def get_sle_against_current_voucher(self):
|
||||||
|
self.args['time_format'] = '%H:%i:%s'
|
||||||
|
|
||||||
return frappe.db.sql("""
|
return frappe.db.sql("""
|
||||||
select
|
select
|
||||||
*, timestamp(posting_date, posting_time) as "timestamp"
|
*, timestamp(posting_date, posting_time) as "timestamp"
|
||||||
@ -202,7 +204,8 @@ class update_entries_after(object):
|
|||||||
where
|
where
|
||||||
item_code = %(item_code)s
|
item_code = %(item_code)s
|
||||||
and warehouse = %(warehouse)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
|
order by
|
||||||
creation ASC
|
creation ASC
|
||||||
for update
|
for update
|
||||||
|
|||||||
@ -3,7 +3,7 @@ frappe
|
|||||||
gocardless-pro==1.11.0
|
gocardless-pro==1.11.0
|
||||||
googlemaps==3.1.1
|
googlemaps==3.1.1
|
||||||
pandas>=1.0.5
|
pandas>=1.0.5
|
||||||
plaid-python==6.0.0
|
plaid-python>=7.0.0
|
||||||
pycountry==19.8.18
|
pycountry==19.8.18
|
||||||
PyGithub==1.44.1
|
PyGithub==1.44.1
|
||||||
python-stdnum==1.12
|
python-stdnum==1.12
|
||||||
@ -12,4 +12,4 @@ taxjar==1.9.0
|
|||||||
tweepy==3.8.0
|
tweepy==3.8.0
|
||||||
Unidecode==1.1.1
|
Unidecode==1.1.1
|
||||||
WooCommerce==2.1.1
|
WooCommerce==2.1.1
|
||||||
pycryptodome==3.9.8
|
pycryptodome==3.9.8
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user