diff --git a/config/common/common.views.xml b/config/common/common.views.xml
index 573e1e68532..c5e1d67c7d9 100644
--- a/config/common/common.views.xml
+++ b/config/common/common.views.xml
@@ -3514,7 +3514,8 @@
|
|
|
- -->
+
+ -->
@@ -4202,7 +4203,22 @@
|
|
|
- -->
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ |
+ |
+ |
+ |
+
+ -->
@@ -4782,7 +4798,21 @@
|
|
|
- -->
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ |
+ |
+ |
+ |
+
-->
diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/types.ts b/specifyweb/frontend/js_src/lib/components/DataModel/types.ts
index 3b38f5ce27b..ffe95745858 100644
--- a/specifyweb/frontend/js_src/lib/components/DataModel/types.ts
+++ b/specifyweb/frontend/js_src/lib/components/DataModel/types.ts
@@ -3369,6 +3369,11 @@ export type Gift = {
};
readonly toOneDependent: { readonly addressOfRecord: AddressOfRecord | null };
readonly toOneIndependent: {
+ readonly agent1: Agent | null;
+ readonly agent2: Agent | null;
+ readonly agent3: Agent | null;
+ readonly agent4: Agent | null;
+ readonly agent5: Agent | null;
readonly createdByAgent: Agent | null;
readonly deaccession: Deaccession | null;
readonly discipline: Discipline;
@@ -3762,6 +3767,11 @@ export type Loan = {
};
readonly toOneDependent: { readonly addressOfRecord: AddressOfRecord | null };
readonly toOneIndependent: {
+ readonly agent1: Agent | null;
+ readonly agent2: Agent | null;
+ readonly agent3: Agent | null;
+ readonly agent4: Agent | null;
+ readonly agent5: Agent | null;
readonly createdByAgent: Agent | null;
readonly discipline: Discipline;
readonly division: Division | null;
diff --git a/specifyweb/specify/datamodel.py b/specifyweb/specify/datamodel.py
index 10f1d2f331a..da4f561043f 100644
--- a/specifyweb/specify/datamodel.py
+++ b/specifyweb/specify/datamodel.py
@@ -4065,6 +4065,11 @@ def is_tree_table(table: Table):
],
relationships=[
Relationship(name='addressOfRecord', type='many-to-one',required=False, relatedModelName='AddressOfRecord', column='AddressOfRecordID', dependent=True),
+ Relationship(name='agent1', type='many-to-one',required=False, relatedModelName='Agent', column='Agent1ID'),
+ Relationship(name='agent2', type='many-to-one',required=False, relatedModelName='Agent', column='Agent2ID'),
+ Relationship(name='agent3', type='many-to-one',required=False, relatedModelName='Agent', column='Agent3ID'),
+ Relationship(name='agent4', type='many-to-one',required=False, relatedModelName='Agent', column='Agent4ID'),
+ Relationship(name='agent5', type='many-to-one',required=False, relatedModelName='Agent', column='Agent5ID'),
Relationship(name='createdByAgent', type='many-to-one',required=False, relatedModelName='Agent', column='CreatedByAgentID'),
Relationship(name='deaccession', type='many-to-one',required=False, relatedModelName='Deaccession', column='DeaccessionID', otherSideName='gifts'),
Relationship(name='discipline', type='many-to-one',required=True, relatedModelName='Discipline', column='DisciplineID'),
@@ -4591,6 +4596,11 @@ def is_tree_table(table: Table):
],
relationships=[
Relationship(name='addressOfRecord', type='many-to-one',required=False, relatedModelName='AddressOfRecord', column='AddressOfRecordID', otherSideName='loans', dependent=True),
+ Relationship(name='agent1', type='many-to-one',required=False, relatedModelName='Agent', column='Agent1ID'),
+ Relationship(name='agent2', type='many-to-one',required=False, relatedModelName='Agent', column='Agent2ID'),
+ Relationship(name='agent3', type='many-to-one',required=False, relatedModelName='Agent', column='Agent3ID'),
+ Relationship(name='agent4', type='many-to-one',required=False, relatedModelName='Agent', column='Agent4ID'),
+ Relationship(name='agent5', type='many-to-one',required=False, relatedModelName='Agent', column='Agent5ID'),
Relationship(name='createdByAgent', type='many-to-one',required=False, relatedModelName='Agent', column='CreatedByAgentID'),
Relationship(name='discipline', type='many-to-one',required=True, relatedModelName='Discipline', column='DisciplineID'),
Relationship(name='division', type='many-to-one',required=False, relatedModelName='Division', column='DivisionID'),
diff --git a/specifyweb/specify/migration_utils/sp7_schemaconfig.py b/specifyweb/specify/migration_utils/sp7_schemaconfig.py
index 943144b5cff..07caa8dc3cd 100644
--- a/specifyweb/specify/migration_utils/sp7_schemaconfig.py
+++ b/specifyweb/specify/migration_utils/sp7_schemaconfig.py
@@ -221,4 +221,26 @@
('date2', 'Date 2', 'Date 2'),
('date2Precision', 'Date 2 Precision', 'Date 2 Precision'),
]
+}
+
+MIGRATION_0038_FIELDS = {
+ 'Loan': ['agent1', 'agent2', 'agent3', 'agent4', 'agent5'],
+ 'Gift': ['agent1', 'agent2', 'agent3', 'agent4', 'agent5'],
+}
+
+MIGRATION_0038_UPDATE_FIELDS = {
+ 'Loan': [
+ ('agent1','Agent 1','Agent 1'),
+ ('agent2','Agent 2','Agent 2'),
+ ('agent3','Agent 3','Agent 3'),
+ ('agent4','Agent 4','Agent 4'),
+ ('agent5','Agent 5','Agent 5'),
+ ],
+ 'Gift': [
+ ('agent1','Agent 1','Agent 1'),
+ ('agent2','Agent 2','Agent 2'),
+ ('agent3','Agent 3','Agent 3'),
+ ('agent4','Agent 4','Agent 4'),
+ ('agent5','Agent 5','Agent 5'),
+ ]
}
\ No newline at end of file
diff --git a/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py b/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py
new file mode 100644
index 00000000000..fa1b172bce3
--- /dev/null
+++ b/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py
@@ -0,0 +1,153 @@
+# Generated by Django 4.2.22 on 2025-07-23 21:18
+
+from django.apps import apps as specify_apps
+from django.db import migrations, models
+from specifyweb.specify.models import protect_with_blockers
+
+from specifyweb.specify.migration_utils.update_schema_config import (
+ revert_table_field_schema_config,
+ update_table_field_schema_config_with_defaults,
+)
+from specifyweb.specify.migration_utils.sp7_schemaconfig import (
+ MIGRATION_0038_FIELDS as SCHEMA_CONFIG_RAW_FIELDS,
+ MIGRATION_0038_UPDATE_FIELDS as SCHEMA_CONFIG_FIELD_DESC,
+)
+
+def update_0038_fields(apps):
+ """
+ Update table-field schema entries for plain field names
+ (e.g., MIGRATION_0038_FIELDS).
+ """
+ Discipline = apps.get_model('specify', 'Discipline')
+ for discipline in Discipline.objects.all():
+ for table, fields in SCHEMA_CONFIG_RAW_FIELDS.items():
+ for field_name in fields:
+ update_table_field_schema_config_with_defaults(table, discipline.id, field_name, apps)
+
+def revert_0038_fields(apps):
+ """
+ Revert table-field entries for plain field names.
+ """
+ for table, fields in SCHEMA_CONFIG_RAW_FIELDS.items():
+ for field_name in fields:
+ revert_table_field_schema_config(table, field_name, apps)
+
+def update_0038_schema_config_field_desc(apps, schema_editor):
+ """
+ Update field descriptions and display names using MIGRATION_0038_UPDATE_FIELDS
+ (tuple: (fieldName, newLabel, newDesc)).
+ """
+ Splocalecontainer = apps.get_model('specify', 'Splocalecontainer')
+ Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem')
+ Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr')
+
+ for table, fields in SCHEMA_CONFIG_FIELD_DESC.items():
+ containers = Splocalecontainer.objects.filter(name=table.lower())
+ for container in containers:
+ for (field_name, new_name, new_desc) in fields:
+ items = Splocalecontaineritem.objects.filter(
+ container=container,
+ name=field_name.lower()
+ )
+ for item in items:
+ item.ishidden = True
+ item.save()
+ desc_str = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first()
+ name_str = Splocaleitemstr.objects.filter(itemname_id=item.id).first()
+ if not desc_str or not name_str:
+ continue
+ desc_str.text = new_desc
+ desc_str.save()
+ name_str.text = new_name
+ name_str.save()
+
+def revert_0038_schema_config_field_desc(apps, schema_editor):
+ """
+ Revert the field name/description updates.
+ """
+ Splocalecontainer = apps.get_model('specify', 'Splocalecontainer')
+ Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem')
+
+ for table, fields in SCHEMA_CONFIG_FIELD_DESC.items():
+ containers = Splocalecontainer.objects.filter(name=table.lower())
+ for container in containers:
+ for (field_name, _, _) in fields:
+ items = Splocalecontaineritem.objects.filter(
+ container=container,
+ name=field_name.lower()
+ )
+ for item in items:
+ # If needed, reset ishidden or revert text
+ pass
+
+def consolidated_0038_forward(apps, schema_editor):
+ update_0038_fields(apps)
+ update_0038_schema_config_field_desc(apps, schema_editor)
+
+def consolidated_0038_backward(apps, schema_editor):
+ revert_0038_schema_config_field_desc(apps, schema_editor)
+ revert_0038_fields(apps)
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('specify', '0038_make_countonly_default_false'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='gift',
+ name='agent1',
+ field=models.ForeignKey(db_column='Agent1ID', null=True, on_delete=protect_with_blockers, related_name='+', to='specify.agent'),
+ ),
+ migrations.AddField(
+ model_name='gift',
+ name='agent2',
+ field=models.ForeignKey(db_column='Agent2ID', null=True, on_delete=protect_with_blockers, related_name='+', to='specify.agent'),
+ ),
+ migrations.AddField(
+ model_name='gift',
+ name='agent3',
+ field=models.ForeignKey(db_column='Agent3ID', null=True, on_delete=protect_with_blockers, related_name='+', to='specify.agent'),
+ ),
+ migrations.AddField(
+ model_name='gift',
+ name='agent4',
+ field=models.ForeignKey(db_column='Agent4ID', null=True, on_delete=protect_with_blockers, related_name='+', to='specify.agent'),
+ ),
+ migrations.AddField(
+ model_name='gift',
+ name='agent5',
+ field=models.ForeignKey(db_column='Agent5ID', null=True, on_delete=protect_with_blockers, related_name='+', to='specify.agent'),
+ ),
+ migrations.AddField(
+ model_name='loan',
+ name='agent1',
+ field=models.ForeignKey(db_column='Agent1ID', null=True, on_delete=protect_with_blockers, related_name='+', to='specify.agent'),
+ ),
+ migrations.AddField(
+ model_name='loan',
+ name='agent2',
+ field=models.ForeignKey(db_column='Agent2ID', null=True, on_delete=protect_with_blockers, related_name='+', to='specify.agent'),
+ ),
+ migrations.AddField(
+ model_name='loan',
+ name='agent3',
+ field=models.ForeignKey(db_column='Agent3ID', null=True, on_delete=protect_with_blockers, related_name='+', to='specify.agent'),
+ ),
+ migrations.AddField(
+ model_name='loan',
+ name='agent4',
+ field=models.ForeignKey(db_column='Agent4ID', null=True, on_delete=protect_with_blockers, related_name='+', to='specify.agent'),
+ ),
+ migrations.AddField(
+ model_name='loan',
+ name='agent5',
+ field=models.ForeignKey(db_column='Agent5ID', null=True, on_delete=protect_with_blockers, related_name='+', to='specify.agent'),
+ ),
+ migrations.RunPython(
+ consolidated_0038_forward,
+ consolidated_0038_backward,
+ atomic=True,
+ ),
+ ]
\ No newline at end of file
diff --git a/specifyweb/specify/models.py b/specifyweb/specify/models.py
index f0a74a68cc2..d4e667a46a3 100644
--- a/specifyweb/specify/models.py
+++ b/specifyweb/specify/models.py
@@ -3825,6 +3825,11 @@ class Gift(models.Model):
# Relationships: Many-to-One
addressofrecord = models.ForeignKey('AddressOfRecord', db_column='AddressOfRecordID', related_name='+', null=True, on_delete=protect_with_blockers)
+ agent1 = models.ForeignKey('Agent', db_column='Agent1ID', related_name='+', null=True, on_delete=protect_with_blockers)
+ agent2 = models.ForeignKey('Agent', db_column='Agent2ID', related_name='+', null=True, on_delete=protect_with_blockers)
+ agent3 = models.ForeignKey('Agent', db_column='Agent3ID', related_name='+', null=True, on_delete=protect_with_blockers)
+ agent4 = models.ForeignKey('Agent', db_column='Agent4ID', related_name='+', null=True, on_delete=protect_with_blockers)
+ agent5 = models.ForeignKey('Agent', db_column='Agent5ID', related_name='+', null=True, on_delete=protect_with_blockers)
createdbyagent = models.ForeignKey('Agent', db_column='CreatedByAgentID', related_name='+', null=True, on_delete=protect_with_blockers)
deaccession = models.ForeignKey('Deaccession', db_column='DeaccessionID', related_name='gifts', null=True, on_delete=protect_with_blockers)
discipline = models.ForeignKey('Discipline', db_column='DisciplineID', related_name='+', null=False, on_delete=protect_with_blockers)
@@ -4322,6 +4327,11 @@ class Loan(models.Model):
# Relationships: Many-to-One
addressofrecord = models.ForeignKey('AddressOfRecord', db_column='AddressOfRecordID', related_name='loans', null=True, on_delete=protect_with_blockers)
+ agent1 = models.ForeignKey('Agent', db_column='Agent1ID', related_name='+', null=True, on_delete=protect_with_blockers)
+ agent2 = models.ForeignKey('Agent', db_column='Agent2ID', related_name='+', null=True, on_delete=protect_with_blockers)
+ agent3 = models.ForeignKey('Agent', db_column='Agent3ID', related_name='+', null=True, on_delete=protect_with_blockers)
+ agent4 = models.ForeignKey('Agent', db_column='Agent4ID', related_name='+', null=True, on_delete=protect_with_blockers)
+ agent5 = models.ForeignKey('Agent', db_column='Agent5ID', related_name='+', null=True, on_delete=protect_with_blockers)
createdbyagent = models.ForeignKey('Agent', db_column='CreatedByAgentID', related_name='+', null=True, on_delete=protect_with_blockers)
discipline = models.ForeignKey('Discipline', db_column='DisciplineID', related_name='+', null=False, on_delete=protect_with_blockers)
division = models.ForeignKey('Division', db_column='DivisionID', related_name='+', null=True, on_delete=protect_with_blockers)