mirror of
https://github.com/frappe/erpnext.git
synced 2026-03-17 17:26:43 +00:00
Merge branch 'version-13-hotfix' into mergify/bp/version-13-hotfix/pr-29740
This commit is contained in:
@@ -418,11 +418,12 @@ class Asset(AccountsController):
|
||||
def validate_asset_finance_books(self, row):
|
||||
if flt(row.expected_value_after_useful_life) >= flt(self.gross_purchase_amount):
|
||||
frappe.throw(_("Row {0}: Expected Value After Useful Life must be less than Gross Purchase Amount")
|
||||
.format(row.idx))
|
||||
.format(row.idx), title=_("Invalid Schedule"))
|
||||
|
||||
if not row.depreciation_start_date:
|
||||
if not self.available_for_use_date:
|
||||
frappe.throw(_("Row {0}: Depreciation Start Date is required").format(row.idx))
|
||||
frappe.throw(_("Row {0}: Depreciation Start Date is required")
|
||||
.format(row.idx), title=_("Invalid Schedule"))
|
||||
row.depreciation_start_date = get_last_day(self.available_for_use_date)
|
||||
|
||||
if not self.is_existing_asset:
|
||||
@@ -440,8 +441,9 @@ class Asset(AccountsController):
|
||||
else:
|
||||
self.number_of_depreciations_booked = 0
|
||||
|
||||
if cint(self.number_of_depreciations_booked) > cint(row.total_number_of_depreciations):
|
||||
frappe.throw(_("Number of Depreciations Booked cannot be greater than Total Number of Depreciations"))
|
||||
if flt(row.total_number_of_depreciations) <= cint(self.number_of_depreciations_booked):
|
||||
frappe.throw(_("Row {0}: Total Number of Depreciations cannot be less than or equal to Number of Depreciations Booked")
|
||||
.format(row.idx), title=_("Invalid Schedule"))
|
||||
|
||||
if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(self.purchase_date):
|
||||
frappe.throw(_("Depreciation Row {0}: Next Depreciation Date cannot be before Purchase Date")
|
||||
|
||||
@@ -820,8 +820,9 @@ class TestDepreciationBasics(AssetSetup):
|
||||
self.assertRaises(frappe.ValidationError, asset.save)
|
||||
|
||||
def test_number_of_depreciations(self):
|
||||
"""Tests if an error is raised when number_of_depreciations_booked > total_number_of_depreciations."""
|
||||
"""Tests if an error is raised when number_of_depreciations_booked >= total_number_of_depreciations."""
|
||||
|
||||
# number_of_depreciations_booked > total_number_of_depreciations
|
||||
asset = create_asset(
|
||||
item_code = "Macbook Pro",
|
||||
calculate_depreciation = 1,
|
||||
@@ -836,6 +837,21 @@ class TestDepreciationBasics(AssetSetup):
|
||||
|
||||
self.assertRaises(frappe.ValidationError, asset.save)
|
||||
|
||||
# number_of_depreciations_booked = total_number_of_depreciations
|
||||
asset_2 = create_asset(
|
||||
item_code = "Macbook Pro",
|
||||
calculate_depreciation = 1,
|
||||
available_for_use_date = "2019-12-31",
|
||||
total_number_of_depreciations = 5,
|
||||
expected_value_after_useful_life = 10000,
|
||||
depreciation_start_date = "2020-07-01",
|
||||
opening_accumulated_depreciation = 10000,
|
||||
number_of_depreciations_booked = 5,
|
||||
do_not_save = 1
|
||||
)
|
||||
|
||||
self.assertRaises(frappe.ValidationError, asset_2.save)
|
||||
|
||||
def test_depreciation_start_date_is_before_purchase_date(self):
|
||||
asset = create_asset(
|
||||
item_code = "Macbook Pro",
|
||||
|
||||
@@ -68,6 +68,28 @@ frappe.ui.form.on('Asset Repair', {
|
||||
});
|
||||
|
||||
frappe.ui.form.on('Asset Repair Consumed Item', {
|
||||
item_code: function(frm, cdt, cdn) {
|
||||
var item = locals[cdt][cdn];
|
||||
|
||||
let item_args = {
|
||||
'item_code': item.item_code,
|
||||
'warehouse': frm.doc.warehouse,
|
||||
'qty': item.consumed_quantity,
|
||||
'serial_no': item.serial_no,
|
||||
'company': frm.doc.company
|
||||
};
|
||||
|
||||
frappe.call({
|
||||
method: 'erpnext.stock.utils.get_incoming_rate',
|
||||
args: {
|
||||
args: item_args
|
||||
},
|
||||
callback: function(r) {
|
||||
frappe.model.set_value(cdt, cdn, 'valuation_rate', r.message);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
consumed_quantity: function(frm, cdt, cdn) {
|
||||
var row = locals[cdt][cdn];
|
||||
frappe.model.set_value(cdt, cdn, 'total_value', row.consumed_quantity * row.valuation_rate);
|
||||
|
||||
@@ -13,12 +13,10 @@
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fetch_from": "item.valuation_rate",
|
||||
"fieldname": "valuation_rate",
|
||||
"fieldtype": "Currency",
|
||||
"in_list_view": 1,
|
||||
"label": "Valuation Rate",
|
||||
"read_only": 1
|
||||
"label": "Valuation Rate"
|
||||
},
|
||||
{
|
||||
"fieldname": "consumed_quantity",
|
||||
@@ -49,7 +47,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-11-11 18:23:00.492483",
|
||||
"modified": "2022-02-08 17:37:20.028290",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Asset Repair Consumed Item",
|
||||
|
||||
@@ -8,10 +8,6 @@ from frappe.utils import cint, flt
|
||||
|
||||
from erpnext import get_default_company, get_region
|
||||
|
||||
TAX_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "tax_account_head")
|
||||
SHIP_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "shipping_account_head")
|
||||
TAXJAR_CREATE_TRANSACTIONS = frappe.db.get_single_value("TaxJar Settings", "taxjar_create_transactions")
|
||||
TAXJAR_CALCULATE_TAX = frappe.db.get_single_value("TaxJar Settings", "taxjar_calculate_tax")
|
||||
SUPPORTED_COUNTRY_CODES = ["AT", "AU", "BE", "BG", "CA", "CY", "CZ", "DE", "DK", "EE", "ES", "FI",
|
||||
"FR", "GB", "GR", "HR", "HU", "IE", "IT", "LT", "LU", "LV", "MT", "NL", "PL", "PT", "RO",
|
||||
"SE", "SI", "SK", "US"]
|
||||
@@ -35,12 +31,14 @@ def get_client():
|
||||
if api_key and api_url:
|
||||
client = taxjar.Client(api_key=api_key, api_url=api_url)
|
||||
client.set_api_config('headers', {
|
||||
'x-api-version': '2020-08-07'
|
||||
'x-api-version': '2022-01-24'
|
||||
})
|
||||
return client
|
||||
|
||||
|
||||
def create_transaction(doc, method):
|
||||
TAXJAR_CREATE_TRANSACTIONS = frappe.db.get_single_value("TaxJar Settings", "taxjar_create_transactions")
|
||||
|
||||
"""Create an order transaction in TaxJar"""
|
||||
|
||||
if not TAXJAR_CREATE_TRANSACTIONS:
|
||||
@@ -51,6 +49,7 @@ def create_transaction(doc, method):
|
||||
if not client:
|
||||
return
|
||||
|
||||
TAX_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "tax_account_head")
|
||||
sales_tax = sum([tax.tax_amount for tax in doc.taxes if tax.account_head == TAX_ACCOUNT_HEAD])
|
||||
|
||||
if not sales_tax:
|
||||
@@ -79,6 +78,7 @@ def create_transaction(doc, method):
|
||||
|
||||
def delete_transaction(doc, method):
|
||||
"""Delete an existing TaxJar order transaction"""
|
||||
TAXJAR_CREATE_TRANSACTIONS = frappe.db.get_single_value("TaxJar Settings", "taxjar_create_transactions")
|
||||
|
||||
if not TAXJAR_CREATE_TRANSACTIONS:
|
||||
return
|
||||
@@ -92,6 +92,8 @@ def delete_transaction(doc, method):
|
||||
|
||||
|
||||
def get_tax_data(doc):
|
||||
SHIP_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "shipping_account_head")
|
||||
|
||||
from_address = get_company_address_details(doc)
|
||||
from_shipping_state = from_address.get("state")
|
||||
from_country_code = frappe.db.get_value("Country", from_address.country, "code")
|
||||
@@ -113,20 +115,20 @@ def get_tax_data(doc):
|
||||
to_shipping_state = get_state_code(to_address, 'Shipping')
|
||||
|
||||
tax_dict = {
|
||||
'from_country': from_country_code,
|
||||
'from_zip': from_address.pincode,
|
||||
'from_state': from_shipping_state,
|
||||
'from_city': from_address.city,
|
||||
'from_street': from_address.address_line1,
|
||||
'to_country': to_country_code,
|
||||
'to_zip': to_address.pincode,
|
||||
'to_city': to_address.city,
|
||||
'to_street': to_address.address_line1,
|
||||
'to_state': to_shipping_state,
|
||||
'shipping': shipping,
|
||||
'amount': doc.net_total,
|
||||
'plugin': 'erpnext',
|
||||
'line_items': line_items
|
||||
"from_country": from_country_code,
|
||||
"from_zip": from_address.pincode,
|
||||
"from_state": from_shipping_state,
|
||||
"from_city": from_address.city,
|
||||
"from_street": from_address.address_line1,
|
||||
"to_country": to_country_code,
|
||||
"to_zip": to_address.pincode,
|
||||
"to_city": to_address.city,
|
||||
"to_street": to_address.address_line1,
|
||||
"to_state": to_shipping_state,
|
||||
"shipping": shipping,
|
||||
"amount": doc.net_total,
|
||||
"plugin": "erpnext",
|
||||
"line_items": line_items
|
||||
}
|
||||
return tax_dict
|
||||
|
||||
@@ -156,6 +158,9 @@ def get_line_item_dict(item, docstatus):
|
||||
return tax_dict
|
||||
|
||||
def set_sales_tax(doc, method):
|
||||
TAX_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "tax_account_head")
|
||||
TAXJAR_CALCULATE_TAX = frappe.db.get_single_value("TaxJar Settings", "taxjar_calculate_tax")
|
||||
|
||||
if not TAXJAR_CALCULATE_TAX:
|
||||
return
|
||||
|
||||
@@ -206,6 +211,7 @@ def set_sales_tax(doc, method):
|
||||
doc.run_method("calculate_taxes_and_totals")
|
||||
|
||||
def check_for_nexus(doc, tax_dict):
|
||||
TAX_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "tax_account_head")
|
||||
if not frappe.db.get_value('TaxJar Nexus', {'region_code': tax_dict["to_state"]}):
|
||||
for item in doc.get("items"):
|
||||
item.tax_collectable = flt(0)
|
||||
@@ -218,6 +224,8 @@ def check_for_nexus(doc, tax_dict):
|
||||
|
||||
def check_sales_tax_exemption(doc):
|
||||
# if the party is exempt from sales tax, then set all tax account heads to zero
|
||||
TAX_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "tax_account_head")
|
||||
|
||||
sales_tax_exempted = hasattr(doc, "exempt_from_sales_tax") and doc.exempt_from_sales_tax \
|
||||
or frappe.db.has_column("Customer", "exempt_from_sales_tax") \
|
||||
and frappe.db.get_value("Customer", doc.customer, "exempt_from_sales_tax")
|
||||
|
||||
@@ -62,7 +62,7 @@ class JobCard(Document):
|
||||
|
||||
if self.get('time_logs'):
|
||||
for d in self.get('time_logs'):
|
||||
if get_datetime(d.from_time) > get_datetime(d.to_time):
|
||||
if d.to_time and get_datetime(d.from_time) > get_datetime(d.to_time):
|
||||
frappe.throw(_("Row {0}: From time must be less than to time").format(d.idx))
|
||||
|
||||
data = self.get_overlap_for(d)
|
||||
|
||||
@@ -1265,7 +1265,7 @@ class SalarySlip(TransactionBase):
|
||||
for i, earning in enumerate(self.earnings):
|
||||
if earning.salary_component == salary_component:
|
||||
self.earnings[i].amount = wages_amount
|
||||
self.gross_pay += self.earnings[i].amount
|
||||
self.gross_pay += flt(self.earnings[i].amount, earning.precision("amount"))
|
||||
self.net_pay = flt(self.gross_pay) - flt(self.total_deduction)
|
||||
|
||||
def compute_year_to_date(self):
|
||||
|
||||
@@ -525,6 +525,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
|
||||
item.weight_per_unit = 0;
|
||||
item.weight_uom = '';
|
||||
item.conversion_factor = 0;
|
||||
|
||||
if(['Sales Invoice'].includes(this.frm.doc.doctype)) {
|
||||
update_stock = cint(me.frm.doc.update_stock);
|
||||
|
||||
@@ -57,14 +57,13 @@ class MaterialRequest(BuyingController):
|
||||
if actual_so_qty and (flt(so_items[so_no][item]) + already_indented > actual_so_qty):
|
||||
frappe.throw(_("Material Request of maximum {0} can be made for Item {1} against Sales Order {2}").format(actual_so_qty - already_indented, item, so_no))
|
||||
|
||||
# Validate
|
||||
# ---------------------
|
||||
def validate(self):
|
||||
super(MaterialRequest, self).validate()
|
||||
|
||||
self.validate_schedule_date()
|
||||
self.check_for_on_hold_or_closed_status('Sales Order', 'sales_order')
|
||||
self.validate_uom_is_integer("uom", "qty")
|
||||
self.validate_material_request_type()
|
||||
|
||||
if not self.status:
|
||||
self.status = "Draft"
|
||||
@@ -84,6 +83,12 @@ class MaterialRequest(BuyingController):
|
||||
self.reset_default_field_value("set_warehouse", "items", "warehouse")
|
||||
self.reset_default_field_value("set_from_warehouse", "items", "from_warehouse")
|
||||
|
||||
def validate_material_request_type(self):
|
||||
""" Validate fields in accordance with selected type """
|
||||
|
||||
if self.material_request_type != "Customer Provided":
|
||||
self.customer = None
|
||||
|
||||
def set_title(self):
|
||||
'''Set title as comma separated list of items'''
|
||||
if not self.title:
|
||||
|
||||
@@ -3726,7 +3726,7 @@ Earliest Age,Frühestes Alter,
|
||||
Edit Details,Details bearbeiten,
|
||||
Edit Profile,Profil bearbeiten,
|
||||
Either GST Transporter ID or Vehicle No is required if Mode of Transport is Road,Bei Straßentransport ist entweder die GST-Transporter-ID oder die Fahrzeug-Nr. Erforderlich,
|
||||
Email,Email,
|
||||
Email,E-Mail,
|
||||
Email Campaigns,E-Mail-Kampagnen,
|
||||
Employee ID is linked with another instructor,Die Mitarbeiter-ID ist mit einem anderen Ausbilder verknüpft,
|
||||
Employee Tax and Benefits,Mitarbeitersteuern und -leistungen,
|
||||
@@ -6481,7 +6481,7 @@ Select Users,Wählen Sie Benutzer aus,
|
||||
Send Emails At,Die E-Mails senden um,
|
||||
Reminder,Erinnerung,
|
||||
Daily Work Summary Group User,Tägliche Arbeit Zusammenfassung Gruppenbenutzer,
|
||||
email,Email,
|
||||
email,E-Mail,
|
||||
Parent Department,Elternabteilung,
|
||||
Leave Block List,Urlaubssperrenliste,
|
||||
Days for which Holidays are blocked for this department.,"Tage, an denen eine Urlaubssperre für diese Abteilung gilt.",
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -11,7 +11,7 @@
|
||||
{% if frappe.session.user == 'Guest' %}
|
||||
<a id="signup" class="btn btn-primary btn-lg" href="/login#signup">{{_('Sign Up')}}</a>
|
||||
{% elif not has_access %}
|
||||
<button id="enroll" class="btn btn-primary btn-lg" onclick="enroll()" disabled>{{_('Enroll')}}</button>
|
||||
<button id="enroll" class="btn btn-primary btn-lg" onclick="enroll()">{{_('Enroll')}}</button>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
@@ -20,34 +20,35 @@
|
||||
<script type="text/javascript">
|
||||
frappe.ready(() => {
|
||||
btn = document.getElementById('enroll');
|
||||
if (btn) btn.disabled = false;
|
||||
})
|
||||
|
||||
function enroll() {
|
||||
let params = frappe.utils.get_query_params()
|
||||
|
||||
let btn = document.getElementById('enroll');
|
||||
btn.disbaled = true;
|
||||
btn.innerText = __('Enrolling...')
|
||||
|
||||
let opts = {
|
||||
method: 'erpnext.education.utils.enroll_in_program',
|
||||
args: {
|
||||
program_name: params.program
|
||||
}
|
||||
},
|
||||
freeze: true,
|
||||
freeze_message: __('Enrolling...')
|
||||
}
|
||||
|
||||
frappe.call(opts).then(res => {
|
||||
let success_dialog = new frappe.ui.Dialog({
|
||||
title: __('Success'),
|
||||
primary_action_label: __('View Program Content'),
|
||||
primary_action: function() {
|
||||
window.location.reload();
|
||||
},
|
||||
secondary_action: function() {
|
||||
window.location.reload()
|
||||
window.location.reload();
|
||||
}
|
||||
})
|
||||
success_dialog.set_message(__('You have successfully enrolled for the program '));
|
||||
success_dialog.$message.show()
|
||||
success_dialog.show();
|
||||
btn.disbaled = false;
|
||||
success_dialog.set_message(__('You have successfully enrolled for the program '));
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user