Skip to content

Commit

Permalink
Merge 17.0 into 18.0
Browse files Browse the repository at this point in the history
  • Loading branch information
jdetaeye committed Jan 9, 2025
2 parents 6e700bc + 40803fc commit 4b8b20a
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 36 deletions.
18 changes: 15 additions & 3 deletions frepple/controllers/inbound.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def run(self):
stck_picking_type = self.env["stock.picking.type"].with_user(
self.actual_user
)
bom_type = self.env["mrp.bom"].with_user(self.actual_user)
stck_picking = self.env["stock.picking"].with_user(self.actual_user)
stck_move = self.env["stock.move"].with_user(self.actual_user)
stck_warehouse = self.env["stock.warehouse"].with_user(self.actual_user)
Expand Down Expand Up @@ -706,6 +707,19 @@ def run(self):
remark = "frePPLe - %s" % remark
else:
remark = "frePPLe"
bom_id = int(elem.get("operation").rsplit(" ", 1)[1])
try:
bom = bom_type.search(
[
("id", "=", bom_id),
],
limit=1,
)
if not bom and bom.type == "phantom":
# Avoid creating MO on a) non-existing BOMs and b) phantom/kit BOMs
continue
except Exception:
pass
mo = mfg_order.with_context(context).create(
{
"product_qty": elem.get("quantity"),
Expand All @@ -715,9 +729,7 @@ def run(self):
"company_id": self.company.id,
"product_uom_id": int(uom_id),
"picking_type_id": picking.id,
"bom_id": int(
elem.get("operation").rsplit(" ", 1)[1]
),
"bom_id": bom_id,
"qty_producing": 0.00,
# TODO no place to store the criticality
# elem.get('criticality'),
Expand Down
92 changes: 59 additions & 33 deletions frepple/controllers/outbound.py
Original file line number Diff line number Diff line change
Expand Up @@ -1418,20 +1418,20 @@ def export_boms(self):
quoteattr(location),
)
else:
duration_per = (i["produce_delay"] or 0) + (
duration = (i["produce_delay"] or 0) + (
i["days_to_prepare_mo"] or 0
)

yield '<operation name=%s %ssize_multiple="1" duration_per="%s" posttime="P%dD" priority="%s" xsi:type="operation_time_per">\n' "<item name=%s/><location name=%s/>\n" % (
yield '<operation name=%s %ssize_multiple="1" duration="%s" posttime="P%dD" priority="%s" xsi:type="operation_fixed_time">\n' "<item name=%s/><location name=%s/>\n" % (
quoteattr(operation),
(
("description=%s " % quoteattr(i["code"]))
if i["code"]
else ""
),
(
self.convert_float_time(duration_per)
if duration_per and duration_per > 0
self.convert_float_time(duration)
if duration and duration > 0
else "P0D"
),
self.manufacturing_lead,
Expand Down Expand Up @@ -2370,6 +2370,7 @@ def export_manufacturingorders(self):
):
# Filter out irrelevant manufacturing orders
location = self.map_locations.get(i.location_dest_id.id, None)
operation = i.name
if not location and i.picking_type_id:
# For subcontracting MO we find the warehouse on the operation type
operation_type = self.operation_types.get(i.picking_type_id.id, None)
Expand All @@ -2378,7 +2379,7 @@ def export_manufacturingorders(self):
if location:
code = self.subcontracting_mo_po_mapping.get(i.id, None)
if code:
i.name = code
operation = code
item = self.product_product.get(i.product_id.id, None)
if not item or not location:
continue
Expand All @@ -2388,14 +2389,16 @@ def export_manufacturingorders(self):
# materials.
# To reflect this flexibility we need a frepple operation specific
# to each manufacturing order.
operation = i.name
try:
startdate = self.formatDateTime(
i.date_start if i.date_start else i.date_planned_start
)
# enddate = self.formatDateTime(i.date_planned_finished)
except Exception:
continue
try:
enddate = self.formatDateTime(i.date_finished)
except Exception:
enddate = None
qty = self.convert_qty_uom(
i.qty_producing if i.qty_producing else i.product_qty,
i.product_uom_id.id,
Expand All @@ -2415,40 +2418,33 @@ def export_manufacturingorders(self):
batch = mto_mo[0].display_name if mto_mo else i.name

# Create a record for the MO
# Option 1: compute MO end date based on the start date
yield '<operationplan type="MO" reference=%s batch=%s start="%s" quantity="%s" status="%s">\n' % (
yield '<operationplan type="MO" reference=%s batch=%s %s="%s" quantity="%s" status="%s">\n' % (
quoteattr(i.name),
quoteattr(batch),
startdate,
(
"start" # Option 1: compute MO end date based on the start date
if self.manage_work_orders or not enddate
else "end" # Option 2: compute MO start date based on the end date
),
(startdate if self.manage_work_orders or not enddate else enddate),
qty,
"approved", # In the "approved" status, frepple can still reschedule the MO in function of material and capacity
# "confirmed", # In the "confirmed" status, frepple sees the MO as frozen and unchangeable
# "approved" if i["status"] == "confirmed" else "confirmed", # In-progress can't be rescheduled in frepple, but confirmed MOs
# In the "approved" status, frepple can still reschedule the MO in function of material and capacity
# In the "confirmed" status, frepple sees the MO as frozen and unchangeable
(
"approved"
if self.manage_work_orders or i.state in ("confirmed", "draft")
else "confirmed"
),
)
# Option 2: compute MO start date based on the end date
# yield '<operationplan type="MO" reference=%s end="%s" quantity="%s" status="%s"><operation name=%s/><flowplans>\n' % (
# quoteattr(i["name"]),
# enddate,
# qty,
# # "approved", # In the "approved" status, frepple can still reschedule the MO in function of material and capacity
# "confirmed", # In the "confirmed" status, frepple sees the MO as frozen and unchangeable
# quoteattr(operation),
# )

# Collect work order info
if self.manage_work_orders:
wo_list = i.workorder_ids
else:
wo_list = []

# Collect move info
if i.move_raw_ids:
mv_list = i.move_raw_ids
else:
mv_list = []

if not wo_list:
# There are no workorders on the manufacturing order
if not self.manage_work_orders or not getattr(i, "workorder_ids", None):
# There are no workorders on the manufacturing order (or we don't want to see them in frepple)
yield '<operation name=%s xsi:type="operation_fixed_time" priority="0"><location name=%s/><item name=%s/><flows>' % (
quoteattr(operation),
quoteattr(location),
Expand Down Expand Up @@ -2488,7 +2484,37 @@ def export_manufacturingorders(self):
yield '<flow xsi:type="flow_end" quantity="1"><item name=%s/></flow>\n' % (
quoteattr(item["name"]),
)
yield "</flows></operation></operationplan>"
yield "</flows>"
# Pick up work center loading of all work orders
loads = {}
for wo in getattr(i, "workorder_ids", []):
# Get remaining duration of the WO
time_left = wo.duration_expected - wo.duration_unit
if wo.is_user_working and wo.time_ids:
# The WO is currently being worked on
for tm in wo.time_ids:
if tm.date_start and not tm.date_end:
time_left -= round(
(now - tm.date_start).total_seconds() / 60
)
if (
time_left > 0
and wo.workcenter_id.id in self.map_workcenters
and wo.state not in ("done", "cancel")
):
loads[self.map_workcenters[wo.workcenter_id.id]] = (
loads.get(self.map_workcenters[wo.workcenter_id.id], 0)
+ time_left
)
if loads:
yield "<loads>"
for r, q in loads.items():
yield '<load quantity_fixed="%s" quantity="0"><resource name=%s/></load>' % (
q,
quoteattr(r),
)
yield "</loads>"
yield "</operation></operationplan>"
else:
# Define an operation for the MO
yield '<operation name=%s xsi:type="operation_routing" priority="0"><item name=%s/><location name=%s/><suboperations>' % (
Expand All @@ -2499,7 +2525,7 @@ def export_manufacturingorders(self):
# Define operations for each WO
idx = 10
first_wo = True
for wo in wo_list:
for wo in i.workorder_ids:
suboperation = wo.display_name
if len(suboperation) > 300:
suboperation = suboperation[0:300]
Expand Down Expand Up @@ -2624,7 +2650,7 @@ def export_manufacturingorders(self):

# Create operationplans for each WO, starting with the last one
idx = 0
for wo in reversed(wo_list):
for wo in reversed(i.workorder_ids):
idx += 1.0
suboperation = wo.display_name
if len(suboperation) > 300:
Expand Down

0 comments on commit 4b8b20a

Please sign in to comment.