mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-07 07:02:54 +00:00
chore: resolve conflicts
This commit is contained in:
@@ -3,13 +3,8 @@
|
|||||||
|
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
<<<<<<< HEAD
|
|
||||||
from frappe.tests.utils import FrappeTestCase, change_settings, timeout
|
from frappe.tests.utils import FrappeTestCase, change_settings, timeout
|
||||||
from frappe.utils import add_days, add_months, add_to_date, cint, flt, now, today
|
|
||||||
=======
|
|
||||||
from frappe.tests import timeout
|
|
||||||
from frappe.utils import add_days, add_months, add_to_date, cint, flt, now, nowdate, nowtime, today
|
from frappe.utils import add_days, add_months, add_to_date, cint, flt, now, nowdate, nowtime, today
|
||||||
>>>>>>> 93ad48bc1b (fix: process loss with bom path disassembly)
|
|
||||||
|
|
||||||
from erpnext.manufacturing.doctype.job_card.job_card import JobCardCancelError
|
from erpnext.manufacturing.doctype.job_card.job_card import JobCardCancelError
|
||||||
from erpnext.manufacturing.doctype.job_card.job_card import make_stock_entry as make_stock_entry_from_jc
|
from erpnext.manufacturing.doctype.job_card.job_card import make_stock_entry as make_stock_entry_from_jc
|
||||||
|
|||||||
@@ -868,10 +868,6 @@ erpnext.work_order = {
|
|||||||
return flt(max, precision("qty"));
|
return flt(max, precision("qty"));
|
||||||
},
|
},
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
show_prompt_for_qty_input: function (frm, purpose) {
|
|
||||||
let max = this.get_max_transferable_qty(frm, purpose);
|
|
||||||
=======
|
|
||||||
show_disassembly_prompt: function (frm) {
|
show_disassembly_prompt: function (frm) {
|
||||||
let max_qty = flt(frm.doc.produced_qty - frm.doc.disassembled_qty);
|
let max_qty = flt(frm.doc.produced_qty - frm.doc.disassembled_qty);
|
||||||
|
|
||||||
@@ -926,9 +922,8 @@ erpnext.work_order = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
show_prompt_for_qty_input: function (frm, purpose, qty, additional_transfer_entry) {
|
show_prompt_for_qty_input: function (frm, purpose) {
|
||||||
let max = !additional_transfer_entry ? this.get_max_transferable_qty(frm, purpose) : qty;
|
let max = this.get_max_transferable_qty(frm, purpose);
|
||||||
>>>>>>> 68e97808c5 (fix: disassembly prompt with source stock entry field)
|
|
||||||
|
|
||||||
let fields = [
|
let fields = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1480,18 +1480,13 @@ def set_work_order_ops(name):
|
|||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
<<<<<<< HEAD
|
|
||||||
def make_stock_entry(work_order_id, purpose, qty=None, target_warehouse=None):
|
|
||||||
=======
|
|
||||||
def make_stock_entry(
|
def make_stock_entry(
|
||||||
work_order_id: str,
|
work_order_id: str,
|
||||||
purpose: str,
|
purpose: str,
|
||||||
qty: float | None = None,
|
qty: float | None = None,
|
||||||
target_warehouse: str | None = None,
|
target_warehouse: str | None = None,
|
||||||
is_additional_transfer_entry: bool = False,
|
|
||||||
source_stock_entry: str | None = None,
|
source_stock_entry: str | None = None,
|
||||||
):
|
):
|
||||||
>>>>>>> 68e97808c5 (fix: disassembly prompt with source stock entry field)
|
|
||||||
work_order = frappe.get_doc("Work Order", work_order_id)
|
work_order = frappe.get_doc("Work Order", work_order_id)
|
||||||
if not frappe.db.get_value("Warehouse", work_order.wip_warehouse, "is_group"):
|
if not frappe.db.get_value("Warehouse", work_order.wip_warehouse, "is_group"):
|
||||||
wip_warehouse = work_order.wip_warehouse
|
wip_warehouse = work_order.wip_warehouse
|
||||||
@@ -1541,16 +1536,7 @@ def make_stock_entry(
|
|||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
def get_default_warehouse():
|
|
||||||
doc = frappe.get_cached_doc("Manufacturing Settings")
|
|
||||||
|
|
||||||
=======
|
|
||||||
def get_disassembly_available_qty(stock_entry_name: str) -> float:
|
|
||||||
=======
|
|
||||||
def get_disassembly_available_qty(stock_entry_name: str, current_se_name: str | None = None) -> float:
|
def get_disassembly_available_qty(stock_entry_name: str, current_se_name: str | None = None) -> float:
|
||||||
>>>>>>> 6394dead72 (fix: validate qty that can be disassembled from source stock entry.)
|
|
||||||
se = frappe.db.get_value("Stock Entry", stock_entry_name, ["fg_completed_qty"], as_dict=True)
|
se = frappe.db.get_value("Stock Entry", stock_entry_name, ["fg_completed_qty"], as_dict=True)
|
||||||
if not se:
|
if not se:
|
||||||
return 0.0
|
return 0.0
|
||||||
@@ -1570,11 +1556,9 @@ def get_disassembly_available_qty(stock_entry_name: str, current_se_name: str |
|
|||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_default_warehouse(company: str):
|
def get_default_warehouse():
|
||||||
wip, fg, scrap = frappe.get_cached_value(
|
doc = frappe.get_cached_doc("Manufacturing Settings")
|
||||||
"Company", company, ["default_wip_warehouse", "default_fg_warehouse", "default_scrap_warehouse"]
|
|
||||||
)
|
|
||||||
>>>>>>> 68e97808c5 (fix: disassembly prompt with source stock entry field)
|
|
||||||
return {
|
return {
|
||||||
"wip_warehouse": doc.default_wip_warehouse,
|
"wip_warehouse": doc.default_wip_warehouse,
|
||||||
"fg_warehouse": doc.default_fg_warehouse,
|
"fg_warehouse": doc.default_fg_warehouse,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"naming_series",
|
"naming_series",
|
||||||
"stock_entry_type",
|
"stock_entry_type",
|
||||||
"outgoing_stock_entry",
|
"outgoing_stock_entry",
|
||||||
|
"source_stock_entry",
|
||||||
"purpose",
|
"purpose",
|
||||||
"add_to_transit",
|
"add_to_transit",
|
||||||
"work_order",
|
"work_order",
|
||||||
@@ -28,15 +29,7 @@
|
|||||||
"column_break_eaoa",
|
"column_break_eaoa",
|
||||||
"set_posting_time",
|
"set_posting_time",
|
||||||
"inspection_required",
|
"inspection_required",
|
||||||
<<<<<<< HEAD
|
|
||||||
"apply_putaway_rule",
|
"apply_putaway_rule",
|
||||||
=======
|
|
||||||
"column_break_jabv",
|
|
||||||
"work_order",
|
|
||||||
"subcontracting_order",
|
|
||||||
"outgoing_stock_entry",
|
|
||||||
"source_stock_entry",
|
|
||||||
>>>>>>> d4baa9a74a (fix: create source_stock_entry to refer to original manufacturing entry)
|
|
||||||
"bom_info_section",
|
"bom_info_section",
|
||||||
"from_bom",
|
"from_bom",
|
||||||
"use_multi_level_bom",
|
"use_multi_level_bom",
|
||||||
|
|||||||
@@ -141,12 +141,8 @@ class StockEntry(StockController):
|
|||||||
scan_barcode: DF.Data | None
|
scan_barcode: DF.Data | None
|
||||||
select_print_heading: DF.Link | None
|
select_print_heading: DF.Link | None
|
||||||
set_posting_time: DF.Check
|
set_posting_time: DF.Check
|
||||||
<<<<<<< HEAD
|
|
||||||
source_address_display: DF.SmallText | None
|
source_address_display: DF.SmallText | None
|
||||||
=======
|
|
||||||
source_address_display: DF.TextEditor | None
|
|
||||||
source_stock_entry: DF.Link | None
|
source_stock_entry: DF.Link | None
|
||||||
>>>>>>> d4baa9a74a (fix: create source_stock_entry to refer to original manufacturing entry)
|
|
||||||
source_warehouse_address: DF.Link | None
|
source_warehouse_address: DF.Link | None
|
||||||
stock_entry_type: DF.Link
|
stock_entry_type: DF.Link
|
||||||
subcontracting_order: DF.Link | None
|
subcontracting_order: DF.Link | None
|
||||||
@@ -375,34 +371,17 @@ class StockEntry(StockController):
|
|||||||
|
|
||||||
self._set_serial_batch_bundle_for_disassembly_row(row, serial_nos, batches)
|
self._set_serial_batch_bundle_for_disassembly_row(row, serial_nos, batches)
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
bundle_doc = SerialBatchCreation(
|
|
||||||
{
|
|
||||||
"item_code": row.item_code,
|
|
||||||
"warehouse": warehouse,
|
|
||||||
"posting_date": self.posting_date,
|
|
||||||
"posting_time": self.posting_time,
|
|
||||||
"voucher_type": self.doctype,
|
|
||||||
"voucher_no": self.name,
|
|
||||||
"voucher_detail_no": row.name,
|
|
||||||
"qty": row.transfer_qty,
|
|
||||||
"type_of_transaction": "Inward" if row.t_warehouse else "Outward",
|
|
||||||
"company": self.company,
|
|
||||||
"do_not_submit": True,
|
|
||||||
}
|
|
||||||
).make_serial_and_batch_bundle(serial_nos=serial_nos, batch_nos=batches)
|
|
||||||
=======
|
|
||||||
def _set_serial_batch_bundle_for_disassembly_row(self, row, serial_nos, batches):
|
def _set_serial_batch_bundle_for_disassembly_row(self, row, serial_nos, batches):
|
||||||
if not serial_nos and not batches:
|
if not serial_nos and not batches:
|
||||||
return
|
return
|
||||||
>>>>>>> 13b019ab8e (fix: set serial and batch from source stock entry - on disassemble)
|
|
||||||
|
|
||||||
warehouse = row.s_warehouse or row.t_warehouse
|
warehouse = row.s_warehouse or row.t_warehouse
|
||||||
bundle_doc = SerialBatchCreation(
|
bundle_doc = SerialBatchCreation(
|
||||||
{
|
{
|
||||||
"item_code": row.item_code,
|
"item_code": row.item_code,
|
||||||
"warehouse": warehouse,
|
"warehouse": warehouse,
|
||||||
"posting_datetime": get_combine_datetime(self.posting_date, self.posting_time),
|
"posting_date": self.posting_date,
|
||||||
|
"posting_time": self.posting_time,
|
||||||
"voucher_type": self.doctype,
|
"voucher_type": self.doctype,
|
||||||
"voucher_no": self.name,
|
"voucher_no": self.name,
|
||||||
"voucher_detail_no": row.name,
|
"voucher_detail_no": row.name,
|
||||||
@@ -2215,45 +2194,7 @@ class StockEntry(StockController):
|
|||||||
# Finished goods
|
# Finished goods
|
||||||
self.load_items_from_bom()
|
self.load_items_from_bom()
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
def get_items_from_manufacture_entry(self):
|
|
||||||
return frappe.get_all(
|
|
||||||
"Stock Entry",
|
|
||||||
fields=[
|
|
||||||
"`tabStock Entry Detail`.`item_code`",
|
|
||||||
"`tabStock Entry Detail`.`item_name`",
|
|
||||||
"`tabStock Entry Detail`.`description`",
|
|
||||||
"sum(`tabStock Entry Detail`.qty) as qty",
|
|
||||||
"sum(`tabStock Entry Detail`.transfer_qty) as transfer_qty",
|
|
||||||
"`tabStock Entry Detail`.`stock_uom`",
|
|
||||||
"`tabStock Entry Detail`.`uom`",
|
|
||||||
"`tabStock Entry Detail`.`basic_rate`",
|
|
||||||
"`tabStock Entry Detail`.`conversion_factor`",
|
|
||||||
"`tabStock Entry Detail`.`is_finished_item`",
|
|
||||||
"`tabStock Entry Detail`.`batch_no`",
|
|
||||||
"`tabStock Entry Detail`.`serial_no`",
|
|
||||||
"`tabStock Entry Detail`.`s_warehouse`",
|
|
||||||
"`tabStock Entry Detail`.`t_warehouse`",
|
|
||||||
"`tabStock Entry Detail`.`use_serial_batch_fields`",
|
|
||||||
],
|
|
||||||
filters=[
|
|
||||||
["Stock Entry", "purpose", "=", "Manufacture"],
|
|
||||||
["Stock Entry", "work_order", "=", self.work_order],
|
|
||||||
["Stock Entry", "docstatus", "=", 1],
|
|
||||||
["Stock Entry Detail", "docstatus", "=", 1],
|
|
||||||
],
|
|
||||||
order_by="`tabStock Entry Detail`.`idx` desc, `tabStock Entry Detail`.`is_finished_item` desc",
|
|
||||||
group_by="`tabStock Entry Detail`.`item_code`",
|
|
||||||
=======
|
|
||||||
def get_items_from_manufacture_stock_entry(self, stock_entry):
|
|
||||||
=======
|
|
||||||
def get_items_from_manufacture_stock_entry(self, stock_entry=None):
|
|
||||||
>>>>>>> 3cf1ce8360 (fix: manufacture entry with group_by support)
|
|
||||||
=======
|
|
||||||
def get_items_from_manufacture_stock_entry(self):
|
def get_items_from_manufacture_stock_entry(self):
|
||||||
>>>>>>> 98dfd64f63 (fix: remove unnecessary param, and use value from self)
|
|
||||||
SE = frappe.qb.DocType("Stock Entry")
|
SE = frappe.qb.DocType("Stock Entry")
|
||||||
SED = frappe.qb.DocType("Stock Entry Detail")
|
SED = frappe.qb.DocType("Stock Entry Detail")
|
||||||
query = frappe.qb.from_(SED).join(SE).on(SED.parent == SE.name).where(SE.docstatus == 1)
|
query = frappe.qb.from_(SED).join(SE).on(SED.parent == SE.name).where(SE.docstatus == 1)
|
||||||
@@ -2293,7 +2234,6 @@ class StockEntry(StockController):
|
|||||||
.groupby(SED.item_code)
|
.groupby(SED.item_code)
|
||||||
.orderby(SED.idx)
|
.orderby(SED.idx)
|
||||||
.run(as_dict=True)
|
.run(as_dict=True)
|
||||||
>>>>>>> 1ed0124ad7 (fix: add support to fetch items based on manufacture stock entry; fix how it's done from work order)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
@@ -2420,161 +2360,7 @@ class StockEntry(StockController):
|
|||||||
if self.pro_doc and self.pro_doc.scrap_warehouse:
|
if self.pro_doc and self.pro_doc.scrap_warehouse:
|
||||||
item["to_warehouse"] = self.pro_doc.scrap_warehouse
|
item["to_warehouse"] = self.pro_doc.scrap_warehouse
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
self.add_to_stock_entry_detail(scrap_item_dict, bom_no=self.bom_no)
|
self.add_to_stock_entry_detail(scrap_item_dict, bom_no=self.bom_no)
|
||||||
=======
|
|
||||||
if (
|
|
||||||
self.purpose not in ["Material Transfer for Manufacture"]
|
|
||||||
and frappe.db.get_single_value("Manufacturing Settings", "backflush_raw_materials_based_on")
|
|
||||||
!= "BOM"
|
|
||||||
and not skip_transfer
|
|
||||||
):
|
|
||||||
return
|
|
||||||
|
|
||||||
reservation_entries = self.get_available_reserved_materials()
|
|
||||||
if not reservation_entries:
|
|
||||||
return
|
|
||||||
|
|
||||||
new_items_to_add = []
|
|
||||||
for d in self.items:
|
|
||||||
if d.serial_and_batch_bundle or d.serial_no or d.batch_no:
|
|
||||||
continue
|
|
||||||
|
|
||||||
key = (d.item_code, d.s_warehouse)
|
|
||||||
if details := reservation_entries.get(key):
|
|
||||||
original_qty = d.qty
|
|
||||||
if batches := details.get("batch_no"):
|
|
||||||
for batch_no, qty in batches.items():
|
|
||||||
if original_qty <= 0:
|
|
||||||
break
|
|
||||||
|
|
||||||
if qty <= 0:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if d.batch_no and original_qty > 0:
|
|
||||||
new_row = frappe.copy_doc(d)
|
|
||||||
new_row.name = None
|
|
||||||
new_row.batch_no = batch_no
|
|
||||||
new_row.qty = qty
|
|
||||||
new_row.idx = d.idx + 1
|
|
||||||
if new_row.batch_no and details.get("batchwise_sn"):
|
|
||||||
new_row.serial_no = "\n".join(
|
|
||||||
details.get("batchwise_sn")[new_row.batch_no][: cint(new_row.qty)]
|
|
||||||
)
|
|
||||||
|
|
||||||
new_items_to_add.append(new_row)
|
|
||||||
original_qty -= qty
|
|
||||||
batches[batch_no] -= qty
|
|
||||||
|
|
||||||
if qty >= d.qty and not d.batch_no:
|
|
||||||
d.batch_no = batch_no
|
|
||||||
batches[batch_no] -= d.qty
|
|
||||||
if d.batch_no and details.get("batchwise_sn"):
|
|
||||||
d.serial_no = "\n".join(
|
|
||||||
details.get("batchwise_sn")[d.batch_no][: cint(d.qty)]
|
|
||||||
)
|
|
||||||
elif not d.batch_no:
|
|
||||||
d.batch_no = batch_no
|
|
||||||
d.qty = qty
|
|
||||||
original_qty -= qty
|
|
||||||
batches[batch_no] = 0
|
|
||||||
|
|
||||||
if d.batch_no and details.get("batchwise_sn"):
|
|
||||||
d.serial_no = "\n".join(
|
|
||||||
details.get("batchwise_sn")[d.batch_no][: cint(d.qty)]
|
|
||||||
)
|
|
||||||
|
|
||||||
if details.get("serial_no"):
|
|
||||||
d.serial_no = "\n".join(details.get("serial_no")[: cint(d.qty)])
|
|
||||||
|
|
||||||
d.use_serial_batch_fields = 1
|
|
||||||
|
|
||||||
for new_row in new_items_to_add:
|
|
||||||
self.append("items", new_row)
|
|
||||||
|
|
||||||
sorted_items = sorted(self.items, key=lambda x: x.item_code)
|
|
||||||
if self.purpose == "Manufacture":
|
|
||||||
# ensure finished item at last
|
|
||||||
sorted_items = sorted(sorted_items, key=lambda x: x.t_warehouse)
|
|
||||||
|
|
||||||
idx = 0
|
|
||||||
for row in sorted_items:
|
|
||||||
idx += 1
|
|
||||||
row.idx = idx
|
|
||||||
self.set("items", sorted_items)
|
|
||||||
|
|
||||||
def get_available_reserved_materials(self):
|
|
||||||
reserved_entries = self.get_reserved_materials()
|
|
||||||
if not reserved_entries:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
itemwise_serial_batch_qty = frappe._dict()
|
|
||||||
|
|
||||||
for d in reserved_entries:
|
|
||||||
key = (d.item_code, d.warehouse)
|
|
||||||
if key not in itemwise_serial_batch_qty:
|
|
||||||
itemwise_serial_batch_qty[key] = frappe._dict(
|
|
||||||
{
|
|
||||||
"serial_no": [],
|
|
||||||
"batch_no": defaultdict(float),
|
|
||||||
"batchwise_sn": defaultdict(list),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
details = itemwise_serial_batch_qty[key]
|
|
||||||
if d.batch_no:
|
|
||||||
details.batch_no[d.batch_no] += d.qty
|
|
||||||
if d.serial_no:
|
|
||||||
details.batchwise_sn[d.batch_no].extend(d.serial_no.split("\n"))
|
|
||||||
elif d.serial_no:
|
|
||||||
details.serial_no.append(d.serial_no)
|
|
||||||
|
|
||||||
return itemwise_serial_batch_qty
|
|
||||||
|
|
||||||
def get_reserved_materials(self):
|
|
||||||
doctype = frappe.qb.DocType("Stock Reservation Entry")
|
|
||||||
serial_batch_doc = frappe.qb.DocType("Serial and Batch Entry")
|
|
||||||
|
|
||||||
query = (
|
|
||||||
frappe.qb.from_(doctype)
|
|
||||||
.inner_join(serial_batch_doc)
|
|
||||||
.on(doctype.name == serial_batch_doc.parent)
|
|
||||||
.select(
|
|
||||||
serial_batch_doc.serial_no,
|
|
||||||
serial_batch_doc.batch_no,
|
|
||||||
serial_batch_doc.qty,
|
|
||||||
doctype.item_code,
|
|
||||||
doctype.warehouse,
|
|
||||||
doctype.name,
|
|
||||||
doctype.transferred_qty,
|
|
||||||
doctype.consumed_qty,
|
|
||||||
)
|
|
||||||
.where(
|
|
||||||
(doctype.docstatus == 1)
|
|
||||||
& (doctype.voucher_no == (self.work_order or self.subcontracting_order))
|
|
||||||
& (serial_batch_doc.delivered_qty < serial_batch_doc.qty)
|
|
||||||
)
|
|
||||||
.orderby(serial_batch_doc.idx)
|
|
||||||
)
|
|
||||||
|
|
||||||
return query.run(as_dict=True)
|
|
||||||
|
|
||||||
def set_secondary_items(self):
|
|
||||||
if self.purpose in ["Manufacture", "Repack"]:
|
|
||||||
secondary_items_dict = self.get_secondary_items(self.fg_completed_qty)
|
|
||||||
for item in secondary_items_dict.values():
|
|
||||||
if self.pro_doc and item.type:
|
|
||||||
if self.pro_doc.scrap_warehouse and item.type == "Scrap":
|
|
||||||
item["to_warehouse"] = self.pro_doc.scrap_warehouse
|
|
||||||
|
|
||||||
if item.process_loss_per:
|
|
||||||
item["qty"] -= flt(
|
|
||||||
item["qty"] * (item.process_loss_per / 100),
|
|
||||||
self.precision("fg_completed_qty"),
|
|
||||||
)
|
|
||||||
|
|
||||||
self.add_to_stock_entry_detail(secondary_items_dict, bom_no=self.bom_no)
|
|
||||||
>>>>>>> ea392b2009 (fix: validate work order consistency in stock entry)
|
|
||||||
|
|
||||||
def set_process_loss_qty(self):
|
def set_process_loss_qty(self):
|
||||||
if self.purpose not in ("Manufacture", "Repack"):
|
if self.purpose not in ("Manufacture", "Repack"):
|
||||||
|
|||||||
Reference in New Issue
Block a user