Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into mergify/bp/version-13-hotfix/pr-32777

This commit is contained in:
Deepesh Garg
2022-11-08 10:40:07 +05:30
15 changed files with 180 additions and 81 deletions

View File

@@ -569,6 +569,10 @@ frappe.ui.form.on("Purchase Invoice", {
erpnext.queries.setup_queries(frm, "Warehouse", function() {
return erpnext.queries.warehouse(frm.doc);
});
if (frm.is_new()) {
frm.clear_table("tax_withheld_vouchers");
}
},
is_subcontracted: function(frm) {

View File

@@ -67,6 +67,9 @@ class PurchaseInvoice(BuyingController):
supplier_tds = frappe.db.get_value("Supplier", self.supplier, "tax_withholding_category")
self.set_onload("supplier_tds", supplier_tds)
if self.is_new():
self.set("tax_withheld_vouchers", [])
def before_save(self):
if not self.on_hold:
self.release_date = ""
@@ -1373,7 +1376,7 @@ class PurchaseInvoice(BuyingController):
"GL Entry",
"Stock Ledger Entry",
"Repost Item Valuation",
"Purchase Invoice",
"Tax Withheld Vouchers",
)
self.update_advance_tax_references(cancel=1)

View File

@@ -916,7 +916,8 @@ class TestSalesInvoice(unittest.TestCase):
pos_return.insert()
pos_return.submit()
self.assertEqual(pos_return.get("payments")[0].amount, -1000)
self.assertEqual(pos_return.get("payments")[0].amount, -500)
self.assertEqual(pos_return.get("payments")[1].amount, -500)
def test_pos_change_amount(self):
make_pos_profile(

View File

@@ -835,10 +835,7 @@ def remove_return_pos_invoices(party_type, party, invoice_list):
else:
return invoice_list
# remove pos return invoices from invoice_list
for idx, inv in enumerate(invoice_list, 0):
if inv.voucher_no in return_pos:
del invoice_list[idx]
invoice_list = [x for x in invoice_list if x.voucher_no not in return_pos]
return invoice_list

View File

@@ -384,7 +384,11 @@ frappe.ui.form.on('Asset', {
set_values_from_purchase_doc: function(frm, doctype, purchase_doc) {
frm.set_value('company', purchase_doc.company);
frm.set_value('purchase_date', purchase_doc.posting_date);
if (purchase_doc.bill_date) {
frm.set_value('purchase_date', purchase_doc.bill_date);
} else {
frm.set_value('purchase_date', purchase_doc.posting_date);
}
const item = purchase_doc.items.find(item => item.item_code === frm.doc.item_code);
if (!item) {
doctype_field = frappe.scrub(doctype)

View File

@@ -152,6 +152,7 @@ class AccountsController(TransactionBase):
self.validate_inter_company_reference()
self.disable_pricing_rule_on_internal_transfer()
self.disable_tax_included_prices_for_internal_transfer()
self.set_incoming_rate()
if self.meta.get_field("currency"):
@@ -395,6 +396,20 @@ class AccountsController(TransactionBase):
alert=1,
)
def disable_tax_included_prices_for_internal_transfer(self):
if self.is_internal_transfer():
tax_updated = False
for tax in self.get("taxes"):
if tax.get("included_in_print_rate"):
tax.included_in_print_rate = 0
tax_updated = True
if tax_updated:
frappe.msgprint(
_("Disabled tax included prices since this {} is an internal transfer").format(self.doctype),
alert=1,
)
def validate_due_date(self):
if self.get("is_pos"):
return

View File

@@ -890,24 +890,33 @@ class calculate_taxes_and_totals(object):
self.doc.other_charges_calculation = get_itemised_tax_breakup_html(self.doc)
def set_total_amount_to_default_mop(self, total_amount_to_pay):
default_mode_of_payment = frappe.db.get_value(
"POS Payment Method",
{"parent": self.doc.pos_profile, "default": 1},
["mode_of_payment"],
as_dict=1,
)
if default_mode_of_payment:
self.doc.payments = []
self.doc.append(
"payments",
{
"mode_of_payment": default_mode_of_payment.mode_of_payment,
"amount": total_amount_to_pay,
"default": 1,
},
total_paid_amount = 0
for payment in self.doc.get("payments"):
total_paid_amount += (
payment.amount if self.doc.party_account_currency == self.doc.currency else payment.base_amount
)
pending_amount = total_amount_to_pay - total_paid_amount
if pending_amount > 0:
default_mode_of_payment = frappe.db.get_value(
"POS Payment Method",
{"parent": self.doc.pos_profile, "default": 1},
["mode_of_payment"],
as_dict=1,
)
if default_mode_of_payment:
self.doc.payments = []
self.doc.append(
"payments",
{
"mode_of_payment": default_mode_of_payment.mode_of_payment,
"amount": pending_amount,
"default": 1,
},
)
def get_itemised_tax_breakup_html(doc):
if not doc.taxes:

View File

@@ -555,66 +555,69 @@ erpnext.work_order = {
}
}
if(!frm.doc.skip_transfer){
if (frm.doc.status != 'Stopped') {
// If "Material Consumption is check in Manufacturing Settings, allow Material Consumption
if (flt(doc.material_transferred_for_manufacturing) > 0 && frm.doc.status != 'Stopped') {
if ((flt(doc.produced_qty) < flt(doc.material_transferred_for_manufacturing))) {
frm.has_finish_btn = true;
if (frm.doc.__onload && frm.doc.__onload.material_consumption == 1) {
// Only show "Material Consumption" when required_qty > consumed_qty
var counter = 0;
var tbl = frm.doc.required_items || [];
var tbl_lenght = tbl.length;
for (var i = 0, len = tbl_lenght; i < len; i++) {
let wo_item_qty = frm.doc.required_items[i].transferred_qty || frm.doc.required_items[i].required_qty;
if (flt(wo_item_qty) > flt(frm.doc.required_items[i].consumed_qty)) {
counter += 1;
}
}
if (counter > 0) {
var consumption_btn = frm.add_custom_button(__('Material Consumption'), function() {
const backflush_raw_materials_based_on = frm.doc.__onload.backflush_raw_materials_based_on;
erpnext.work_order.make_consumption_se(frm, backflush_raw_materials_based_on);
});
consumption_btn.addClass('btn-primary');
if (frm.doc.__onload && frm.doc.__onload.material_consumption == 1) {
if (flt(doc.material_transferred_for_manufacturing) > 0 || frm.doc.skip_transfer) {
// Only show "Material Consumption" when required_qty > consumed_qty
var counter = 0;
var tbl = frm.doc.required_items || [];
var tbl_lenght = tbl.length;
for (var i = 0, len = tbl_lenght; i < len; i++) {
let wo_item_qty = frm.doc.required_items[i].transferred_qty || frm.doc.required_items[i].required_qty;
if (flt(wo_item_qty) > flt(frm.doc.required_items[i].consumed_qty)) {
counter += 1;
}
}
if (counter > 0) {
var consumption_btn = frm.add_custom_button(__('Material Consumption'), function() {
const backflush_raw_materials_based_on = frm.doc.__onload.backflush_raw_materials_based_on;
erpnext.work_order.make_consumption_se(frm, backflush_raw_materials_based_on);
});
consumption_btn.addClass('btn-primary');
}
}
}
if(!frm.doc.skip_transfer){
if (flt(doc.material_transferred_for_manufacturing) > 0) {
if ((flt(doc.produced_qty) < flt(doc.material_transferred_for_manufacturing))) {
frm.has_finish_btn = true;
var finish_btn = frm.add_custom_button(__('Finish'), function() {
erpnext.work_order.make_se(frm, 'Manufacture');
});
if(doc.material_transferred_for_manufacturing>=doc.qty) {
// all materials transferred for manufacturing, make this primary
finish_btn.addClass('btn-primary');
}
} else {
frappe.db.get_doc("Manufacturing Settings").then((doc) => {
let allowance_percentage = doc.overproduction_percentage_for_work_order;
if (allowance_percentage > 0) {
let allowed_qty = frm.doc.qty + ((allowance_percentage / 100) * frm.doc.qty);
if ((flt(doc.produced_qty) < allowed_qty)) {
frm.add_custom_button(__('Finish'), function() {
erpnext.work_order.make_se(frm, 'Manufacture');
});
}
}
});
}
}
} else {
if ((flt(doc.produced_qty) < flt(doc.qty))) {
var finish_btn = frm.add_custom_button(__('Finish'), function() {
erpnext.work_order.make_se(frm, 'Manufacture');
});
if(doc.material_transferred_for_manufacturing>=doc.qty) {
// all materials transferred for manufacturing, make this primary
finish_btn.addClass('btn-primary');
}
} else {
frappe.db.get_doc("Manufacturing Settings").then((doc) => {
let allowance_percentage = doc.overproduction_percentage_for_work_order;
if (allowance_percentage > 0) {
let allowed_qty = frm.doc.qty + ((allowance_percentage / 100) * frm.doc.qty);
if ((flt(doc.produced_qty) < allowed_qty)) {
frm.add_custom_button(__('Finish'), function() {
erpnext.work_order.make_se(frm, 'Manufacture');
});
}
}
});
finish_btn.addClass('btn-primary');
}
}
} else {
if ((flt(doc.produced_qty) < flt(doc.qty)) && frm.doc.status != 'Stopped') {
var finish_btn = frm.add_custom_button(__('Finish'), function() {
erpnext.work_order.make_se(frm, 'Manufacture');
});
finish_btn.addClass('btn-primary');
}
}
}
},
calculate_cost: function(doc) {
if (doc.operations){

View File

@@ -47,6 +47,12 @@ erpnext.setup_auto_gst_taxation = (doctype) => {
}
}
});
},
reverse_charge: function(frm) {
if (frm.doc.reverse_charge == "Y") {
frm.set_value('eligibility_for_itc', 'ITC on Reverse Charge');
}
}
});
}

View File

@@ -983,8 +983,6 @@ def validate_reverse_charge_transaction(doc, method):
frappe.throw(msg)
doc.eligibility_for_itc = "ITC on Reverse Charge"
def update_itc_availed_fields(doc, method):
country = frappe.get_cached_value("Company", doc.company, "country")

View File

@@ -67,7 +67,7 @@ erpnext.PointOfSale.Controller = class {
{
fieldtype: 'Link', label: __('POS Profile'),
options: 'POS Profile', fieldname: 'pos_profile', reqd: 1,
get_query: () => pos_profile_query,
get_query: () => pos_profile_query(),
onchange: () => fetch_pos_payment_methods()
},
{
@@ -101,9 +101,11 @@ erpnext.PointOfSale.Controller = class {
primary_action_label: __('Submit')
});
dialog.show();
const pos_profile_query = {
query: 'erpnext.accounts.doctype.pos_profile.pos_profile.pos_profile_query',
filters: { company: dialog.fields_dict.company.get_value() }
const pos_profile_query = () => {
return {
query: 'erpnext.accounts.doctype.pos_profile.pos_profile.pos_profile_query',
filters: { company: dialog.fields_dict.company.get_value() }
}
};
}

View File

@@ -285,7 +285,7 @@ def get_batch_no(item_code, warehouse, qty=1, throw=False, serial_no=None):
batches = get_batches(item_code, warehouse, qty, throw, serial_no)
for batch in batches:
if cint(qty) <= cint(batch.qty):
if flt(qty) <= flt(batch.qty):
batch_no = batch.batch_id
break

View File

@@ -1050,9 +1050,22 @@ class TestDeliveryNote(FrappeTestCase):
do_not_submit=True,
)
dn.append(
"taxes",
{
"charge_type": "On Net Total",
"account_head": "_Test Account Service Tax - _TC",
"description": "Tax 1",
"rate": 14,
"cost_center": "_Test Cost Center - _TC",
"included_in_print_rate": 1,
},
)
self.assertEqual(dn.items[0].rate, 500) # haven't saved yet
dn.save()
self.assertEqual(dn.ignore_pricing_rule, 1)
self.assertEqual(dn.taxes[0].included_in_print_rate, 0)
# rate should reset to incoming rate
self.assertEqual(dn.items[0].rate, rate)
@@ -1063,6 +1076,7 @@ class TestDeliveryNote(FrappeTestCase):
dn.save()
self.assertEqual(dn.items[0].rate, rate)
self.assertEqual(dn.items[0].net_rate, rate)
def test_internal_transfer_precision_gle(self):
from erpnext.selling.doctype.customer.test_customer import create_internal_customer

View File

@@ -74,10 +74,21 @@ def get_conditions(filters):
else:
frappe.throw(_("'To Date' is required"))
for field in ["item_code", "warehouse", "batch_no", "company"]:
for field in ["item_code", "batch_no", "company"]:
if filters.get(field):
conditions += " and {0} = {1}".format(field, frappe.db.escape(filters.get(field)))
if filters.get("warehouse"):
warehouse_details = frappe.db.get_value(
"Warehouse", filters.get("warehouse"), ["lft", "rgt"], as_dict=1
)
if warehouse_details:
conditions += (
" and exists (select name from `tabWarehouse` wh \
where wh.lft >= %s and wh.rgt <= %s and sle.warehouse = wh.name)"
% (warehouse_details.lft, warehouse_details.rgt)
)
return conditions
@@ -87,7 +98,7 @@ def get_stock_ledger_entries(filters):
return frappe.db.sql(
"""
select item_code, batch_no, warehouse, posting_date, sum(actual_qty) as actual_qty
from `tabStock Ledger Entry`
from `tabStock Ledger Entry` as sle
where is_cancelled = 0 and docstatus < 2 and ifnull(batch_no, '') != '' %s
group by voucher_no, batch_no, item_code, warehouse
order by item_code, warehouse"""

View File

@@ -9865,3 +9865,35 @@ Leave Type Allocation,Zuordnung Abwesenheitsarten,
From Lead,Aus Lead,
From Opportunity,Aus Chance,
Publish in Website,Auf Webseite veröffentlichen,
Total Allocated Leave(s),Gesamte zugewiesene Urlaubstage,
Expired Leave(s),Verfallene Urlaubstage,
Used Leave(s),Verbrauchte Urlaubstage,
Leave(s) Pending Approval,Urlaubstage zur Genehmigung ausstehend,
Available Leave(s),Verfügbare Urlaubstage,
Party Specific Item,Parteispezifischer Artikel,
Active Customers,Aktive Kunden,
Annual Sales,Jährlicher Umsatz,
Total Outgoing Bills,Ausgangsrechnungen insgesamt,
Total Incoming Bills,Eingangsrechnungen insgesamt,
Total Incoming Payment,Zahlungseingang insgesamt,
Total Outgoing Payment,Zahlungsausgang insgesamt,
Incoming Bills (Purchase Invoice),Eingehende Rechnungen (Eingangsrechnung),
Outgoing Bills (Sales Invoice),Ausgehende Rechnungen (Ausgangsrechnung),
Accounts Receivable Ageing,Fälligkeit Forderungen,
Accounts Payable Ageing,Fälligkeit Verbindlichkeiten,
Budget Variance,Budgetabweichung,
Based On Value,Basierend auf Wert,
Restrict Items Based On,Artikel einschränken auf Basis von,
Earnings & Deductions,Erträge & Abzüge,
Is Process Loss,Ist Prozessverlust,
Is Finished Item,Ist fertiger Artikel,
Is Scrap Item,Ist Schrott,
Issue a debit note with 0 qty against an existing Sales Invoice,Lastschrift mit Menge 0 gegen eine bestehende Ausgangsrechnung ausstellen,
Show Remarks,Bemerkungen anzeigen,
Website Item,Webseiten-Artikel,
Update Property,Eigenschaft aktualisieren,
Recurring Sales Invoice,Wiederkehrende Ausgangsrechnung,
Total Asset,Aktiva,
Total Liability,Verbindlichkeiten,
Total Equity,Eigenkapital,
Warehouse wise Stock Value,Warenwert nach Lager,
Can't render this file because it is too large.