Merge remote-tracking branch 'upstream/develop' into feat/so-po-advance-payment-status

This commit is contained in:
David Arnold
2023-12-04 13:35:32 +01:00
654 changed files with 17389 additions and 2025 deletions

View File

@@ -71,6 +71,10 @@ class AccountMissingError(frappe.ValidationError):
pass
class InvalidQtyError(frappe.ValidationError):
pass
force_item_fields = (
"item_group",
"brand",
@@ -239,7 +243,7 @@ class AccountsController(TransactionBase):
references_map.setdefault(x.parent, []).append(x.name)
for doc, rows in references_map.items():
unreconcile_doc = frappe.get_doc("Unreconcile Payments", doc)
unreconcile_doc = frappe.get_doc("Unreconcile Payment", doc)
for row in rows:
unreconcile_doc.remove(unreconcile_doc.get("allocations", {"name": row})[0])
@@ -248,9 +252,9 @@ class AccountsController(TransactionBase):
unreconcile_doc.save(ignore_permissions=True)
# delete docs upon parent doc deletion
unreconcile_docs = frappe.db.get_all("Unreconcile Payments", filters={"voucher_no": self.name})
unreconcile_docs = frappe.db.get_all("Unreconcile Payment", filters={"voucher_no": self.name})
for x in unreconcile_docs:
_doc = frappe.get_doc("Unreconcile Payments", x.name)
_doc = frappe.get_doc("Unreconcile Payment", x.name)
if _doc.docstatus == 1:
_doc.cancel()
_doc.delete()
@@ -625,6 +629,7 @@ class AccountsController(TransactionBase):
args["doctype"] = self.doctype
args["name"] = self.name
args["child_doctype"] = item.doctype
args["child_docname"] = item.name
args["ignore_pricing_rule"] = (
self.ignore_pricing_rule if hasattr(self, "ignore_pricing_rule") else 0
@@ -910,10 +915,16 @@ class AccountsController(TransactionBase):
return flt(args.get(field, 0) / self.get("conversion_rate", 1))
def validate_qty_is_not_zero(self):
if self.doctype != "Purchase Receipt":
for item in self.items:
if not item.qty:
frappe.throw(_("Item quantity can not be zero"))
if self.doctype == "Purchase Receipt":
return
for item in self.items:
if not flt(item.qty):
frappe.throw(
msg=_("Row #{0}: Item quantity cannot be zero").format(item.idx),
title=_("Invalid Quantity"),
exc=InvalidQtyError,
)
def validate_account_currency(self, account, account_currency=None):
valid_currency = [self.company_currency]
@@ -2953,6 +2964,9 @@ def validate_and_delete_children(parent, data) -> bool:
d.cancel()
d.delete()
if parent.doctype == "Purchase Order":
parent.update_ordered_qty_in_so_for_removed_items(deleted_children)
# need to update ordered qty in Material Request first
# bin uses Material Request Items to recalculate & update
parent.update_prevdoc_status()
@@ -3147,16 +3161,19 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
conv_fac_precision = child_item.precision("conversion_factor") or 2
qty_precision = child_item.precision("qty") or 2
if flt(child_item.billed_amt, rate_precision) > flt(
flt(d.get("rate"), rate_precision) * flt(d.get("qty"), qty_precision), rate_precision
):
# Amount cannot be lesser than billed amount, except for negative amounts
row_rate = flt(d.get("rate"), rate_precision)
amount_below_billed_amt = flt(child_item.billed_amt, rate_precision) > flt(
row_rate * flt(d.get("qty"), qty_precision), rate_precision
)
if amount_below_billed_amt and row_rate > 0.0:
frappe.throw(
_("Row #{0}: Cannot set Rate if amount is greater than billed amount for Item {1}.").format(
child_item.idx, child_item.item_code
)
)
else:
child_item.rate = flt(d.get("rate"), rate_precision)
child_item.rate = row_rate
if d.get("conversion_factor"):
if child_item.stock_uom == child_item.uom:
@@ -3240,7 +3257,10 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
if parent_doctype == "Purchase Order":
update_last_purchase_rate(parent, is_submit=1)
parent.update_prevdoc_status()
if any_qty_changed or items_added_or_removed or any_conversion_factor_changed:
parent.update_prevdoc_status()
parent.update_requested_qty()
parent.update_ordered_qty()
parent.update_ordered_and_reserved_qty()

View File

@@ -118,6 +118,7 @@ class BuyingController(SubcontractingController):
"company": self.company,
"voucher_type": self.doctype,
"voucher_no": self.name,
"voucher_detail_no": row.name,
},
raise_error_if_no_rate=False,
)
@@ -365,7 +366,7 @@ class BuyingController(SubcontractingController):
{
"item_code": d.item_code,
"warehouse": d.get("from_warehouse"),
"posting_date": self.get("posting_date") or self.get("transation_date"),
"posting_date": self.get("posting_date") or self.get("transaction_date"),
"posting_time": posting_time,
"qty": -1 * flt(d.get("stock_qty")),
"serial_and_batch_bundle": d.get("serial_and_batch_bundle"),
@@ -373,6 +374,7 @@ class BuyingController(SubcontractingController):
"voucher_type": self.doctype,
"voucher_no": self.name,
"allow_zero_valuation": d.get("allow_zero_valuation"),
"voucher_detail_no": d.name,
},
raise_error_if_no_rate=False,
)
@@ -440,7 +442,7 @@ class BuyingController(SubcontractingController):
if allow_to_edit_stock_qty:
d.stock_qty = flt(d.stock_qty, d.precision("stock_qty"))
if d.get("received_stock_qty"):
if d.get("received_stock_qty") and d.meta.get_field("received_stock_qty"):
d.received_stock_qty = flt(d.received_stock_qty, d.precision("received_stock_qty"))
def validate_purchase_return(self):
@@ -758,7 +760,7 @@ class BuyingController(SubcontractingController):
"calculate_depreciation": 0,
"purchase_receipt_amount": purchase_amount,
"gross_purchase_amount": purchase_amount,
"asset_quantity": row.qty if is_grouped_asset else 0,
"asset_quantity": row.qty if is_grouped_asset else 1,
"purchase_receipt": self.name if self.doctype == "Purchase Receipt" else None,
"purchase_invoice": self.name if self.doctype == "Purchase Invoice" else None,
}

View File

@@ -356,6 +356,7 @@ def make_return_doc(
if doc.doctype == "Sales Invoice" or doc.doctype == "POS Invoice":
doc.consolidated_invoice = ""
doc.set("payments", [])
doc.update_billed_amount_in_delivery_note = True
for data in source.payments:
paid_amount = 0.00
base_paid_amount = 0.00
@@ -390,7 +391,10 @@ def make_return_doc(
if doc.get("discount_amount"):
doc.discount_amount = -1 * source.discount_amount
if doctype != "Subcontracting Receipt":
if doctype == "Subcontracting Receipt":
doc.set_warehouse = source.set_warehouse
doc.supplier_warehouse = source.supplier_warehouse
else:
doc.run_method("calculate_taxes_and_totals")
def update_item(source_doc, target_doc, source_parent):
@@ -582,8 +586,6 @@ def make_return_doc(
set_missing_values,
)
doclist.set_onload("ignore_price_list", True)
return doclist

View File

@@ -350,11 +350,12 @@ class SellingController(StockController):
return il
def has_product_bundle(self, item_code):
return frappe.db.sql(
"""select name from `tabProduct Bundle`
where new_item_code=%s and docstatus != 2""",
item_code,
)
product_bundle = frappe.qb.DocType("Product Bundle")
return (
frappe.qb.from_(product_bundle)
.select(product_bundle.name)
.where((product_bundle.new_item_code == item_code) & (product_bundle.disabled == 0))
).run()
def get_already_delivered_qty(self, current_docname, so, so_detail):
delivered_via_dn = frappe.db.sql(
@@ -443,6 +444,7 @@ class SellingController(StockController):
"company": self.company,
"voucher_type": self.doctype,
"voucher_no": self.name,
"voucher_detail_no": d.name,
"allow_zero_valuation": d.get("allow_zero_valuation"),
},
raise_error_if_no_rate=False,

View File

@@ -626,6 +626,18 @@ class SubcontractingController(StockController):
(row.item_code, row.get(self.subcontract_data.order_field))
] -= row.qty
def __set_rate_for_serial_and_batch_bundle(self):
if self.doctype != "Subcontracting Receipt":
return
for row in self.get(self.raw_material_table):
if not row.get("serial_and_batch_bundle"):
continue
row.rate = frappe.get_cached_value(
"Serial and Batch Bundle", row.serial_and_batch_bundle, "avg_rate"
)
def __modify_serial_and_batch_bundle(self):
if self.is_new():
return
@@ -681,6 +693,7 @@ class SubcontractingController(StockController):
self.__remove_changed_rows()
self.__set_supplied_items()
self.__modify_serial_and_batch_bundle()
self.__set_rate_for_serial_and_batch_bundle()
def __validate_batch_no(self, row, key):
if row.get("batch_no") and row.get("batch_no") not in self.__transferred_items.get(key).get(
@@ -867,6 +880,7 @@ class SubcontractingController(StockController):
"posting_date": self.posting_date,
"posting_time": self.posting_time,
"qty": -1 * item.consumed_qty,
"voucher_detail_no": item.name,
"serial_and_batch_bundle": item.serial_and_batch_bundle,
}
)
@@ -939,6 +953,23 @@ class SubcontractingController(StockController):
return self._sub_contracted_items
def update_requested_qty(self):
material_request_map = {}
for d in self.get("items"):
if d.material_request_item:
material_request_map.setdefault(d.material_request, []).append(d.material_request_item)
for mr, mr_item_rows in material_request_map.items():
if mr and mr_item_rows:
mr_obj = frappe.get_doc("Material Request", mr)
if mr_obj.status in ["Stopped", "Cancelled"]:
frappe.throw(
_("Material Request {0} is cancelled or stopped").format(mr), frappe.InvalidStatusError
)
mr_obj.update_requested_qty(mr_item_rows)
def get_item_details(items):
item = frappe.qb.DocType("Item")

View File

@@ -54,6 +54,7 @@ class calculate_taxes_and_totals(object):
if self.doc.apply_discount_on == "Grand Total" and self.doc.get("is_cash_or_non_trade_discount"):
self.doc.grand_total -= self.doc.discount_amount
self.doc.base_grand_total -= self.doc.base_discount_amount
self.doc.rounding_adjustment = self.doc.base_rounding_adjustment = 0.0
self.set_rounded_total()
self.calculate_shipping_charges()

View File

@@ -1001,6 +1001,7 @@ def make_subcontracted_items():
"Subcontracted Item SA5": {},
"Subcontracted Item SA6": {},
"Subcontracted Item SA7": {},
"Subcontracted Item SA8": {},
}
for item, properties in sub_contracted_items.items():
@@ -1020,6 +1021,7 @@ def make_raw_materials():
},
"Subcontracted SRM Item 4": {"has_serial_no": 1, "serial_no_series": "SRII.####"},
"Subcontracted SRM Item 5": {"has_serial_no": 1, "serial_no_series": "SRIID.####"},
"Subcontracted SRM Item 8": {},
}
for item, properties in raw_materials.items():
@@ -1043,6 +1045,7 @@ def make_service_items():
"Subcontracted Service Item 5": {},
"Subcontracted Service Item 6": {},
"Subcontracted Service Item 7": {},
"Subcontracted Service Item 8": {},
}
for item, properties in service_items.items():
@@ -1066,6 +1069,7 @@ def make_bom_for_subcontracted_items():
"Subcontracted Item SA5": ["Subcontracted SRM Item 5"],
"Subcontracted Item SA6": ["Subcontracted SRM Item 3"],
"Subcontracted Item SA7": ["Subcontracted SRM Item 1"],
"Subcontracted Item SA8": ["Subcontracted SRM Item 8"],
}
for item_code, raw_materials in boms.items():