fix : correct logic for overlap error (#38967)
fixing overlap error logic with taking care of sequential time job cards in overlap job card list
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index d696cc4..23650b6 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -273,35 +273,39 @@
def has_overlap(self, production_capacity, time_logs):
overlap = False
- if production_capacity == 1 and len(time_logs) > 0:
+ if production_capacity == 1 and len(time_logs) >= 1:
return True
+ if not len(time_logs):
+ return False
- # Check overlap exists or not between the overlapping time logs with the current Job Card
- for row in time_logs:
- count = 1
- for next_row in time_logs:
- if row.name == next_row.name:
- continue
-
- if (
- (
- get_datetime(next_row.from_time) >= get_datetime(row.from_time)
- and get_datetime(next_row.from_time) <= get_datetime(row.to_time)
- )
- or (
- get_datetime(next_row.to_time) >= get_datetime(row.from_time)
- and get_datetime(next_row.to_time) <= get_datetime(row.to_time)
- )
- or (
- get_datetime(next_row.from_time) <= get_datetime(row.from_time)
- and get_datetime(next_row.to_time) >= get_datetime(row.to_time)
- )
- ):
- count += 1
-
- if count > production_capacity:
- return True
-
+ # sorting overlapping job cards as per from_time
+ time_logs = sorted(time_logs, key=lambda x: x.get("from_time"))
+ # alloted_capacity has key number starting from 1. Key number will increment by 1 if non sequential job card found
+ # if key number reaches/crosses to production_capacity means capacity is full and overlap error generated
+ # this will store last to_time of sequential job cards
+ alloted_capacity = {1: time_logs[0]["to_time"]}
+ # flag for sequential Job card found
+ sequential_job_card_found = False
+ for i in range(1, len(time_logs)):
+ # scanning for all Existing keys
+ for key in alloted_capacity.keys():
+ # if current Job Card from time is greater than last to_time in that key means these job card are sequential
+ if alloted_capacity[key] <= time_logs[i]["from_time"]:
+ # So update key's value with last to_time
+ alloted_capacity[key] = time_logs[i]["to_time"]
+ # flag is true as we get sequential Job Card for that key
+ sequential_job_card_found = True
+ # Immediately break so that job card to time is not added with any other key except this
+ break
+ # if sequential job card not found above means it is overlapping so increment key number to alloted_capacity
+ if not sequential_job_card_found:
+ # increment key number
+ key = key + 1
+ # for that key last to time is assigned.
+ alloted_capacity[key] = time_logs[i]["to_time"]
+ if len(alloted_capacity) >= production_capacity:
+ # if number of keys greater or equal to production caoacity means full capacity is utilized and we should throw overlap error
+ return True
return overlap
def get_time_logs(self, args, doctype, check_next_available_slot=False):