mirror of
https://github.com/frappe/erpnext.git
synced 2026-04-13 11:55:11 +00:00
Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into pos_write_off
This commit is contained in:
@@ -399,6 +399,8 @@ def make_return_doc(doctype, source_name, target_doc=None):
|
||||
}
|
||||
}, target_doc, set_missing_values)
|
||||
|
||||
doclist.set_onload('ignore_price_list', True)
|
||||
|
||||
return doclist
|
||||
|
||||
def get_rate_for_return(voucher_type, voucher_no, item_code, return_against=None,
|
||||
|
||||
@@ -114,20 +114,16 @@ class calculate_taxes_and_totals(object):
|
||||
for item in self.doc.get("items"):
|
||||
self.doc.round_floats_in(item)
|
||||
|
||||
if not item.rate:
|
||||
item.rate = item.price_list_rate
|
||||
|
||||
if item.discount_percentage == 100:
|
||||
item.rate = 0.0
|
||||
elif item.price_list_rate:
|
||||
if item.pricing_rules or abs(item.discount_percentage) > 0:
|
||||
if not item.rate or (item.pricing_rules and item.discount_percentage > 0):
|
||||
item.rate = flt(item.price_list_rate *
|
||||
(1.0 - (item.discount_percentage / 100.0)), item.precision("rate"))
|
||||
|
||||
if abs(item.discount_percentage) > 0:
|
||||
item.discount_amount = item.price_list_rate * (item.discount_percentage / 100.0)
|
||||
item.discount_amount = item.price_list_rate * (item.discount_percentage / 100.0)
|
||||
|
||||
elif item.discount_amount or item.pricing_rules:
|
||||
elif item.discount_amount and item.pricing_rules:
|
||||
item.rate = item.price_list_rate - item.discount_amount
|
||||
|
||||
if item.doctype in ['Quotation Item', 'Sales Order Item', 'Delivery Note Item', 'Sales Invoice Item',
|
||||
|
||||
@@ -5,6 +5,12 @@ frappe.ui.form.on('Website Item', {
|
||||
onload: function(frm) {
|
||||
// should never check Private
|
||||
frm.fields_dict["website_image"].df.is_private = 0;
|
||||
|
||||
frm.set_query("website_warehouse", () => {
|
||||
return {
|
||||
filters: {"is_group": 0}
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
image: function() {
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Production Plan', {
|
||||
|
||||
before_save: function(frm) {
|
||||
// preserve temporary names on production plan item to re-link sub-assembly items
|
||||
frm.doc.po_items.forEach(item => {
|
||||
item.temporary_name = item.name;
|
||||
});
|
||||
},
|
||||
setup: function(frm) {
|
||||
frm.custom_make_buttons = {
|
||||
'Work Order': 'Work Order / Subcontract PO',
|
||||
|
||||
@@ -32,6 +32,7 @@ class ProductionPlan(Document):
|
||||
self.set_pending_qty_in_row_without_reference()
|
||||
self.calculate_total_planned_qty()
|
||||
self.set_status()
|
||||
self._rename_temporary_references()
|
||||
|
||||
def set_pending_qty_in_row_without_reference(self):
|
||||
"Set Pending Qty in independent rows (not from SO or MR)."
|
||||
@@ -57,6 +58,18 @@ class ProductionPlan(Document):
|
||||
if not flt(d.planned_qty):
|
||||
frappe.throw(_("Please enter Planned Qty for Item {0} at row {1}").format(d.item_code, d.idx))
|
||||
|
||||
def _rename_temporary_references(self):
|
||||
""" po_items and sub_assembly_items items are both constructed client side without saving.
|
||||
|
||||
Attempt to fix linkages by using temporary names to map final row names.
|
||||
"""
|
||||
new_name_map = {d.temporary_name: d.name for d in self.po_items if d.temporary_name}
|
||||
actual_names = {d.name for d in self.po_items}
|
||||
|
||||
for sub_assy in self.sub_assembly_items:
|
||||
if sub_assy.production_plan_item not in actual_names:
|
||||
sub_assy.production_plan_item = new_name_map.get(sub_assy.production_plan_item)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_open_sales_orders(self):
|
||||
""" Pull sales orders which are pending to deliver based on criteria selected"""
|
||||
|
||||
@@ -617,6 +617,39 @@ class TestProductionPlan(FrappeTestCase):
|
||||
wo_doc.submit()
|
||||
self.assertEqual(wo_doc.qty, 0.55)
|
||||
|
||||
def test_temporary_name_relinking(self):
|
||||
|
||||
pp = frappe.new_doc("Production Plan")
|
||||
|
||||
# this can not be unittested so mocking data that would be expected
|
||||
# from client side.
|
||||
for _ in range(10):
|
||||
po_item = pp.append("po_items", {
|
||||
"name": frappe.generate_hash(length=10),
|
||||
"temporary_name": frappe.generate_hash(length=10),
|
||||
})
|
||||
pp.append("sub_assembly_items", {
|
||||
"production_plan_item": po_item.temporary_name
|
||||
})
|
||||
pp._rename_temporary_references()
|
||||
|
||||
for po_item, subassy_item in zip(pp.po_items, pp.sub_assembly_items):
|
||||
self.assertEqual(po_item.name, subassy_item.production_plan_item)
|
||||
|
||||
# bad links should be erased
|
||||
pp.append("sub_assembly_items", {
|
||||
"production_plan_item": frappe.generate_hash(length=16)
|
||||
})
|
||||
pp._rename_temporary_references()
|
||||
self.assertIsNone(pp.sub_assembly_items[-1].production_plan_item)
|
||||
pp.sub_assembly_items.pop()
|
||||
|
||||
# reattempting on same doc shouldn't change anything
|
||||
pp._rename_temporary_references()
|
||||
for po_item, subassy_item in zip(pp.po_items, pp.sub_assembly_items):
|
||||
self.assertEqual(po_item.name, subassy_item.production_plan_item)
|
||||
|
||||
|
||||
def create_production_plan(**args):
|
||||
"""
|
||||
sales_order (obj): Sales Order Doc Object
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
"material_request",
|
||||
"material_request_item",
|
||||
"product_bundle_item",
|
||||
"item_reference"
|
||||
"item_reference",
|
||||
"temporary_name"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@@ -204,17 +205,25 @@
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Item Reference"
|
||||
},
|
||||
{
|
||||
"fieldname": "temporary_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "temporary name"
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-06-28 18:31:06.822168",
|
||||
"modified": "2022-03-24 04:54:09.940224",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Production Plan Item",
|
||||
"naming_rule": "Random",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "ASC"
|
||||
"sort_order": "ASC",
|
||||
"states": []
|
||||
}
|
||||
@@ -352,7 +352,6 @@ class TestWorkOrder(FrappeTestCase):
|
||||
wo_order = make_wo_order_test_record(planned_start_date=now(),
|
||||
sales_order=so.name, qty=3)
|
||||
|
||||
wo_order.submit()
|
||||
self.assertEqual(wo_order.docstatus, 1)
|
||||
|
||||
allow_overproduction("overproduction_percentage_for_sales_order", 0)
|
||||
|
||||
@@ -457,7 +457,8 @@ class WorkOrder(Document):
|
||||
mr_obj.update_requested_qty([self.material_request_item])
|
||||
|
||||
def update_ordered_qty(self):
|
||||
if self.production_plan and self.production_plan_item:
|
||||
if self.production_plan and self.production_plan_item \
|
||||
and not self.production_plan_sub_assembly_item:
|
||||
qty = frappe.get_value("Production Plan Item", self.production_plan_item, "ordered_qty") or 0.0
|
||||
|
||||
if self.docstatus == 1:
|
||||
@@ -640,9 +641,13 @@ class WorkOrder(Document):
|
||||
if not self.qty > 0:
|
||||
frappe.throw(_("Quantity to Manufacture must be greater than 0."))
|
||||
|
||||
if self.production_plan and self.production_plan_item:
|
||||
if self.production_plan and self.production_plan_item \
|
||||
and not self.production_plan_sub_assembly_item:
|
||||
qty_dict = frappe.db.get_value("Production Plan Item", self.production_plan_item, ["planned_qty", "ordered_qty"], as_dict=1)
|
||||
|
||||
if not qty_dict:
|
||||
return
|
||||
|
||||
allowance_qty = flt(frappe.db.get_single_value("Manufacturing Settings",
|
||||
"overproduction_percentage_for_work_order"))/100 * qty_dict.get("planned_qty", 0)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
erpnext.patches.v12_0.update_is_cancelled_field
|
||||
erpnext.patches.v13_0.add_bin_unique_constraint
|
||||
erpnext.patches.v11_0.rename_production_order_to_work_order
|
||||
erpnext.patches.v13_0.add_bin_unique_constraint
|
||||
erpnext.patches.v11_0.refactor_naming_series
|
||||
erpnext.patches.v11_0.refactor_autoname_naming
|
||||
execute:frappe.reload_doc("accounts", "doctype", "POS Payment Method") #2020-05-28
|
||||
@@ -352,6 +352,6 @@ erpnext.patches.v13_0.update_reserved_qty_closed_wo
|
||||
erpnext.patches.v13_0.amazon_mws_deprecation_warning
|
||||
erpnext.patches.v13_0.set_work_order_qty_in_so_from_mr
|
||||
erpnext.patches.v13_0.update_accounts_in_loan_docs
|
||||
erpnext.patches.v13_0.remove_unknown_links_to_prod_plan_items
|
||||
erpnext.patches.v13_0.remove_unknown_links_to_prod_plan_items # 24-03-2022
|
||||
erpnext.patches.v13_0.rename_non_profit_fields
|
||||
erpnext.patches.v13_0.enable_ksa_vat_docs #1
|
||||
|
||||
@@ -60,7 +60,7 @@ def execute():
|
||||
|
||||
def convert_to_seconds(value, unit):
|
||||
seconds = 0
|
||||
if value == 0:
|
||||
if not value:
|
||||
return seconds
|
||||
if unit == 'Hours':
|
||||
seconds = value * 3600
|
||||
|
||||
@@ -1041,9 +1041,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
var me = this;
|
||||
this.set_dynamic_labels();
|
||||
var company_currency = this.get_company_currency();
|
||||
// Added `ignore_pricing_rule` to determine if document is loading after mapping from another doc
|
||||
// Added `ignore_price_list` to determine if document is loading after mapping from another doc
|
||||
if(this.frm.doc.currency && this.frm.doc.currency !== company_currency
|
||||
&& !this.frm.doc.ignore_pricing_rule) {
|
||||
&& !this.frm.doc.__onload.ignore_price_list) {
|
||||
|
||||
this.get_exchange_rate(transaction_date, this.frm.doc.currency, company_currency,
|
||||
function(exchange_rate) {
|
||||
@@ -1143,8 +1143,8 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
this.set_dynamic_labels();
|
||||
|
||||
var company_currency = this.get_company_currency();
|
||||
// Added `ignore_pricing_rule` to determine if document is loading after mapping from another doc
|
||||
if(this.frm.doc.price_list_currency !== company_currency && !this.frm.doc.ignore_pricing_rule) {
|
||||
// Added `ignore_price_list` to determine if document is loading after mapping from another doc
|
||||
if(this.frm.doc.price_list_currency !== company_currency && !this.frm.doc.__onload.ignore_price_list) {
|
||||
this.get_exchange_rate(this.frm.doc.posting_date, this.frm.doc.price_list_currency, company_currency,
|
||||
function(exchange_rate) {
|
||||
me.frm.set_value("plc_conversion_rate", exchange_rate);
|
||||
|
||||
Reference in New Issue
Block a user