mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-23 23:19:20 +00:00
Merge branch 'version-13-hotfix' into mergify/bp/version-13-hotfix/pr-27916
This commit is contained in:
@@ -590,5 +590,11 @@ frappe.ui.form.on("Purchase Invoice", {
|
|||||||
|
|
||||||
company: function(frm) {
|
company: function(frm) {
|
||||||
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
|
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
|
||||||
|
|
||||||
|
if (frm.doc.company) {
|
||||||
|
frappe.db.get_value('Company', frm.doc.company, 'default_payable_account', (r) => {
|
||||||
|
frm.set_value('credit_to', r.default_payable_account);
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -10,9 +10,17 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
|||||||
this.setup_posting_date_time_check();
|
this.setup_posting_date_time_check();
|
||||||
this._super(doc);
|
this._super(doc);
|
||||||
},
|
},
|
||||||
|
|
||||||
company: function() {
|
company: function() {
|
||||||
erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
|
erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
|
||||||
|
let me = this;
|
||||||
|
if (this.frm.doc.company) {
|
||||||
|
frappe.db.get_value('Company', this.frm.doc.company, 'default_receivable_account', (r) => {
|
||||||
|
me.frm.set_value('debit_to', r.default_receivable_account);
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onload: function() {
|
onload: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
this._super();
|
this._super();
|
||||||
|
|||||||
@@ -1359,8 +1359,8 @@ class AccountsController(TransactionBase):
|
|||||||
total = 0
|
total = 0
|
||||||
base_total = 0
|
base_total = 0
|
||||||
for d in self.get("payment_schedule"):
|
for d in self.get("payment_schedule"):
|
||||||
total += flt(d.payment_amount)
|
total += flt(d.payment_amount, d.precision("payment_amount"))
|
||||||
base_total += flt(d.base_payment_amount)
|
base_total += flt(d.base_payment_amount, d.precision("base_payment_amount"))
|
||||||
|
|
||||||
base_grand_total = self.get("base_rounded_total") or self.base_grand_total
|
base_grand_total = self.get("base_rounded_total") or self.base_grand_total
|
||||||
grand_total = self.get("rounded_total") or self.grand_total
|
grand_total = self.get("rounded_total") or self.grand_total
|
||||||
@@ -1376,8 +1376,9 @@ class AccountsController(TransactionBase):
|
|||||||
else:
|
else:
|
||||||
grand_total -= self.get("total_advance")
|
grand_total -= self.get("total_advance")
|
||||||
base_grand_total = flt(grand_total * self.get("conversion_rate"), self.precision("base_grand_total"))
|
base_grand_total = flt(grand_total * self.get("conversion_rate"), self.precision("base_grand_total"))
|
||||||
if total != flt(grand_total, self.precision("grand_total")) or \
|
|
||||||
base_total != flt(base_grand_total, self.precision("base_grand_total")):
|
if flt(total, self.precision("grand_total")) != flt(grand_total, self.precision("grand_total")) or \
|
||||||
|
flt(base_total, self.precision("base_grand_total")) != flt(base_grand_total, self.precision("base_grand_total")):
|
||||||
frappe.throw(_("Total Payment Amount in Payment Schedule must be equal to Grand / Rounded Total"))
|
frappe.throw(_("Total Payment Amount in Payment Schedule must be equal to Grand / Rounded Total"))
|
||||||
|
|
||||||
def is_rounded_total_disabled(self):
|
def is_rounded_total_disabled(self):
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
|
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _dict
|
|
||||||
from frappe.utils import floor
|
from frappe.utils import floor
|
||||||
|
|
||||||
|
|
||||||
@@ -96,38 +95,32 @@ class ProductFiltersBuilder:
|
|||||||
return
|
return
|
||||||
|
|
||||||
attributes = [row.attribute for row in self.doc.filter_attributes]
|
attributes = [row.attribute for row in self.doc.filter_attributes]
|
||||||
attribute_docs = [
|
|
||||||
frappe.get_doc('Item Attribute', attribute) for attribute in attributes
|
|
||||||
]
|
|
||||||
|
|
||||||
valid_attributes = []
|
if not attributes:
|
||||||
|
return []
|
||||||
|
|
||||||
for attr_doc in attribute_docs:
|
result = frappe.db.sql(
|
||||||
selected_attributes = []
|
"""
|
||||||
for attr in attr_doc.item_attribute_values:
|
select
|
||||||
or_filters = []
|
distinct attribute, attribute_value
|
||||||
filters= [
|
from
|
||||||
["Item Variant Attribute", "attribute", "=", attr.parent],
|
`tabItem Variant Attribute`
|
||||||
["Item Variant Attribute", "attribute_value", "=", attr.attribute_value]
|
where
|
||||||
]
|
attribute in %(attributes)s
|
||||||
if self.item_group:
|
and attribute_value is not null
|
||||||
or_filters.extend([
|
""",
|
||||||
["item_group", "=", self.item_group],
|
{"attributes": attributes},
|
||||||
["Website Item Group", "item_group", "=", self.item_group]
|
as_dict=1,
|
||||||
])
|
)
|
||||||
|
|
||||||
if frappe.db.get_all("Item", filters, or_filters=or_filters, limit=1):
|
attribute_value_map = {}
|
||||||
selected_attributes.append(attr)
|
for d in result:
|
||||||
|
attribute_value_map.setdefault(d.attribute, []).append(d.attribute_value)
|
||||||
|
|
||||||
if selected_attributes:
|
out = []
|
||||||
valid_attributes.append(
|
for name, values in attribute_value_map.items():
|
||||||
_dict(
|
out.append(frappe._dict(name=name, item_attribute_values=values))
|
||||||
item_attribute_values=selected_attributes,
|
return out
|
||||||
name=attr_doc.name
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return valid_attributes
|
|
||||||
|
|
||||||
def get_discount_filters(self, discounts):
|
def get_discount_filters(self, discounts):
|
||||||
discount_filters = []
|
discount_filters = []
|
||||||
@@ -147,4 +140,4 @@ class ProductFiltersBuilder:
|
|||||||
label = f"{discount}% and below"
|
label = f"{discount}% and below"
|
||||||
discount_filters.append([discount, label])
|
discount_filters.append([discount, label])
|
||||||
|
|
||||||
return discount_filters
|
return discount_filters
|
||||||
|
|||||||
@@ -175,9 +175,7 @@ class TestProductDataEngine(unittest.TestCase):
|
|||||||
|
|
||||||
filter_engine = ProductFiltersBuilder()
|
filter_engine = ProductFiltersBuilder()
|
||||||
attribute_filter = filter_engine.get_attribute_filters()[0]
|
attribute_filter = filter_engine.get_attribute_filters()[0]
|
||||||
attributes = attribute_filter.item_attribute_values
|
attribute_values = attribute_filter.item_attribute_values
|
||||||
|
|
||||||
attribute_values = [d.attribute_value for d in attributes]
|
|
||||||
|
|
||||||
self.assertEqual(attribute_filter.name, "Test Size")
|
self.assertEqual(attribute_filter.name, "Test Size")
|
||||||
self.assertGreater(len(attribute_values), 0)
|
self.assertGreater(len(attribute_values), 0)
|
||||||
@@ -349,4 +347,4 @@ def create_variant_web_item():
|
|||||||
variant.save()
|
variant.save()
|
||||||
|
|
||||||
if not frappe.db.exists("Website Item", {"variant_of": "Test Web Item"}):
|
if not frappe.db.exists("Website Item", {"variant_of": "Test Web Item"}):
|
||||||
make_website_item(variant, save=True)
|
make_website_item(variant, save=True)
|
||||||
|
|||||||
@@ -311,7 +311,7 @@ class ProductionPlan(Document):
|
|||||||
|
|
||||||
if self.total_produced_qty > 0:
|
if self.total_produced_qty > 0:
|
||||||
self.status = "In Process"
|
self.status = "In Process"
|
||||||
if self.total_produced_qty >= self.total_planned_qty:
|
if self.check_have_work_orders_completed():
|
||||||
self.status = "Completed"
|
self.status = "Completed"
|
||||||
|
|
||||||
if self.status != 'Completed':
|
if self.status != 'Completed':
|
||||||
@@ -575,6 +575,15 @@ class ProductionPlan(Document):
|
|||||||
|
|
||||||
self.append("sub_assembly_items", data)
|
self.append("sub_assembly_items", data)
|
||||||
|
|
||||||
|
def check_have_work_orders_completed(self):
|
||||||
|
wo_status = frappe.db.get_list(
|
||||||
|
"Work Order",
|
||||||
|
filters={"production_plan": self.name},
|
||||||
|
fields="status",
|
||||||
|
pluck="status"
|
||||||
|
)
|
||||||
|
return all(s == "Completed" for s in wo_status)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def download_raw_materials(doc, warehouses=None):
|
def download_raw_materials(doc, warehouses=None):
|
||||||
if isinstance(doc, str):
|
if isinstance(doc, str):
|
||||||
|
|||||||
@@ -329,3 +329,4 @@ erpnext.patches.v13_0.trim_sales_invoice_custom_field_length
|
|||||||
erpnext.patches.v13_0.enable_scheduler_job_for_item_reposting
|
erpnext.patches.v13_0.enable_scheduler_job_for_item_reposting
|
||||||
erpnext.patches.v13_0.requeue_failed_reposts
|
erpnext.patches.v13_0.requeue_failed_reposts
|
||||||
erpnext.patches.v13_0.fetch_thumbnail_in_website_items
|
erpnext.patches.v13_0.fetch_thumbnail_in_website_items
|
||||||
|
erpnext.patches.v12_0.update_production_plan_status
|
||||||
|
|||||||
31
erpnext/patches/v12_0/update_production_plan_status.py
Normal file
31
erpnext/patches/v12_0/update_production_plan_status.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# Copyright (c) 2021, Frappe and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
frappe.reload_doc("manufacturing", "doctype", "production_plan")
|
||||||
|
frappe.db.sql("""
|
||||||
|
UPDATE `tabProduction Plan` ppl
|
||||||
|
SET status = "Completed"
|
||||||
|
WHERE ppl.name IN (
|
||||||
|
SELECT ss.name FROM (
|
||||||
|
SELECT
|
||||||
|
(
|
||||||
|
count(wo.status = "Completed") =
|
||||||
|
count(pp.name)
|
||||||
|
) =
|
||||||
|
(
|
||||||
|
pp.status != "Completed"
|
||||||
|
AND pp.total_produced_qty >= pp.total_planned_qty
|
||||||
|
) AS should_set,
|
||||||
|
pp.name AS name
|
||||||
|
FROM
|
||||||
|
`tabWork Order` wo INNER JOIN`tabProduction Plan` pp
|
||||||
|
ON wo.production_plan = pp.name
|
||||||
|
GROUP BY pp.name
|
||||||
|
HAVING should_set = 1
|
||||||
|
) ss
|
||||||
|
)
|
||||||
|
""")
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"category": "Modules",
|
"category": "Modules",
|
||||||
"charts": [],
|
"charts": [],
|
||||||
|
"content": "[{\"type\":\"header\",\"data\":{\"text\":\"Your Shortcuts\\n\\t\\t\\t\\n\\t\\t\\n\\t\\t\\t\\n\\t\\t\\n\\t\\t\\t\\n\\t\\t\",\"level\":4,\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Projects Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Stock Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"HR Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Selling Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Buying Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Support Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Shopping Cart Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Portal Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Domain Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Products Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Naming Series\",\"col\":4}}]",
|
||||||
"creation": "2020-03-12 14:47:51.166455",
|
"creation": "2020-03-12 14:47:51.166455",
|
||||||
"developer_mode_only": 0,
|
"developer_mode_only": 0,
|
||||||
"disable_user_customization": 0,
|
"disable_user_customization": 0,
|
||||||
@@ -15,7 +16,7 @@
|
|||||||
"is_standard": 1,
|
"is_standard": 1,
|
||||||
"label": "ERPNext Settings",
|
"label": "ERPNext Settings",
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-06-12 01:58:11.399566",
|
"modified": "2021-10-26 21:32:55.323591",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Setup",
|
"module": "Setup",
|
||||||
"name": "ERPNext Settings",
|
"name": "ERPNext Settings",
|
||||||
@@ -29,6 +30,14 @@
|
|||||||
"link_to": "Projects Settings",
|
"link_to": "Projects Settings",
|
||||||
"type": "DocType"
|
"type": "DocType"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"color": "Grey",
|
||||||
|
"doc_view": "",
|
||||||
|
"icon": "dot-horizontal",
|
||||||
|
"label": "Naming Series",
|
||||||
|
"link_to": "Naming Series",
|
||||||
|
"type": "DocType"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"icon": "accounting",
|
"icon": "accounting",
|
||||||
"label": "Accounts Settings",
|
"label": "Accounts Settings",
|
||||||
|
|||||||
@@ -339,15 +339,15 @@
|
|||||||
<div class="filter-options">
|
<div class="filter-options">
|
||||||
{% for attr_value in attribute.item_attribute_values %}
|
{% for attr_value in attribute.item_attribute_values %}
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label data-value="{{ attr_value }}">
|
<label>
|
||||||
<input type="checkbox"
|
<input type="checkbox"
|
||||||
class="product-filter attribute-filter"
|
class="product-filter attribute-filter"
|
||||||
id="{{attr_value.name}}"
|
id="{{ attr_value }}"
|
||||||
data-attribute-name="{{ attribute.name }}"
|
data-attribute-name="{{ attribute.name }}"
|
||||||
data-attribute-value="{{ attr_value.attribute_value }}"
|
data-attribute-value="{{ attr_value }}"
|
||||||
style="width: 14px !important"
|
style="width: 14px !important"
|
||||||
{% if attr_value.checked %} checked {% endif %}>
|
{% if attr_value.checked %} checked {% endif %}>
|
||||||
<span class="label-area">{{ attr_value.attribute_value }}</span>
|
<span class="label-area">{{ attr_value }}</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
Reference in New Issue
Block a user