diff --git a/specifyweb/backend/stored_queries/batch_edit.py b/specifyweb/backend/stored_queries/batch_edit.py index 56f3fedfaed..f124c3364cf 100644 --- a/specifyweb/backend/stored_queries/batch_edit.py +++ b/specifyweb/backend/stored_queries/batch_edit.py @@ -1095,7 +1095,31 @@ def _get_orig_column(string_id: str): # We would have arbitarily sorted the columns, so our columns will not be correct. # Rather than sifting the data, we just add a default visual order. - visual_order = Func.first(headers_enumerated) + visual_order_groups: list[list[int]] = [[] for _ in visible_fields] + prev_group: int | None = None + prev_duplicate_index: int | None = None + for index, (key, _header) in headers_enumerated: + # Find the column's original position if it existed in the origin query + original_place = key[0] + duplicate_index = key[1] + if original_place < len(visible_fields): + if prev_duplicate_index is not None and duplicate_index > 1 and (duplicate_index == prev_duplicate_index+1 or duplicate_index == prev_duplicate_index): + # There are duplicate columns, group them by record instead of original query order + # Columns are already grouped by record, just preserve the order if the dupe index is greater than the previous. + visual_order_groups[prev_group].append(index) + else: + visual_order_groups[original_place].append(index) + prev_group = original_place + else: + # New field/column. Add it to the end of the dataset. + visual_order_groups.append([index]) + # prev_group = len(visual_order_groups)-1 + + prev_duplicate_index = duplicate_index + + visual_order: list[int] = [] + for bucket in visual_order_groups: + visual_order.extend(bucket) headers = Func.second(key_and_headers) diff --git a/specifyweb/backend/stored_queries/tests/test_batch_edit.py b/specifyweb/backend/stored_queries/tests/test_batch_edit.py index 6372521c6f3..477af0f5970 100644 --- a/specifyweb/backend/stored_queries/tests/test_batch_edit.py +++ b/specifyweb/backend/stored_queries/tests/test_batch_edit.py @@ -155,9 +155,9 @@ def test_basic_run(self): "CollectionObject catalogNumber", "CollectionObject integer1", "Agent (formatted)", - "CollectingEvent (formatted)", "Agent firstName", "Agent lastName", + "CollectingEvent (formatted)", "Locality localityName", ], ) @@ -554,6 +554,14 @@ def test_duplicates_flattened(self): "CollectionObject catalogNumber", "CollectionObject integer1", "Agent (formatted)", + "Determination integer1", + "Determination remarks", + "Determination integer1 #2", + "Determination remarks #2", + "Determination integer1 #3", + "Determination remarks #3", + "Preparation countAmt", + "Preparation text1", "Agent firstName", "Agent lastName", "AgentSpecialty specialtyName", @@ -576,14 +584,6 @@ def test_duplicates_flattened(self): "CollectingEvent stationFieldNumber #7", "Collector remarks #8", "CollectingEvent stationFieldNumber #8", - "Determination integer1", - "Determination remarks", - "Determination integer1 #2", - "Determination remarks #2", - "Determination integer1 #3", - "Determination remarks #3", - "Preparation countAmt", - "Preparation text1" ], )