Skip to content
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
e37c68a
WIP
roman-stolar Sep 17, 2025
f67877f
added unit field to Partner Field model
roman-stolar Sep 17, 2025
c5d37c5
small improve
roman-stolar Sep 17, 2025
61e4ae5
refactored
roman-stolar Sep 18, 2025
867c203
small fix
roman-stolar Sep 18, 2025
9fcaa64
Merge branch 'main' into OSDEV-2065-update-v1-production-location-emi…
roman-stolar Sep 18, 2025
4b61f24
fix migration
roman-stolar Sep 18, 2025
7fb711c
updated release notes
roman-stolar Sep 18, 2025
0c9eaad
fix linter
roman-stolar Sep 18, 2025
88e2d0e
coderabbit suggestion fix
roman-stolar Sep 18, 2025
e43ec83
adressed Vadim comments
roman-stolar Sep 18, 2025
981f1bf
addressed Vlad comments
roman-stolar Sep 19, 2025
346dfae
fix linter
roman-stolar Sep 19, 2025
baf0aef
updated release notes
roman-stolar Sep 19, 2025
7640c12
fix typo
roman-stolar Sep 19, 2025
c3ccd08
fix
roman-stolar Sep 19, 2025
5ee3e92
addressed sonarqube issue
roman-stolar Sep 19, 2025
58819f1
Merge commit 'cf9c92873826a0071d4f439e6053e8fe317b9de1' into OSDEV-20…
roman-stolar Sep 21, 2025
975d113
Bulk implementation of the extended fields creation for partner fields
roman-stolar Sep 22, 2025
974c80f
refactored
roman-stolar Sep 23, 2025
ddacda1
error detail message updated to be consistent
roman-stolar Sep 23, 2025
aded062
Updated release notes
roman-stolar Sep 23, 2025
9ed6a43
fix linter
roman-stolar Sep 23, 2025
59661d3
fix linter
roman-stolar Sep 23, 2025
ef7fc16
Added implementation to support display estimated_emissions_activity …
roman-stolar Sep 23, 2025
bba27ce
updated release notes
roman-stolar Sep 23, 2025
81b78ff
fix
roman-stolar Sep 23, 2025
d2e94ee
fix linter
roman-stolar Sep 23, 2025
fa0e783
added unit tests
roman-stolar Sep 24, 2025
c36469b
Merge branch 'main' into OSDEV-2065-update-v1-production-location-emi…
roman-stolar Sep 24, 2025
081fbe0
fix linter
roman-stolar Sep 24, 2025
1d61a6c
fix linter
roman-stolar Sep 24, 2025
3a7e475
possible tests fix
roman-stolar Sep 24, 2025
30aca95
adressed Vadim comments
roman-stolar Sep 25, 2025
309ecb5
addressed
roman-stolar Sep 25, 2025
64d2ba8
fix
roman-stolar Sep 25, 2025
8bdd8ae
fix tests
roman-stolar Sep 25, 2025
df3092d
Merge branch 'main' into OSDEV-2065-update-v1-production-location-emi…
roman-stolar Sep 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/release/RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html
* [OSDEV-2065](https://opensupplyhub.atlassian.net/browse/OSDEV-2065) - Updated v1 production locations `POST/PATCH` endpoints to include partner fields:
* Added `unit` field to `PartnerField` model
* Added type validation for submitted partner fields
* Added `create_partner_extendedfields_for_single_item()` function for bulk partner field processing
* Enhanced `all_values_empty()` function to handle dictionaries and improve list processing
* Integrated partner field creation into the moderation event approval workflow
* Added `label` field to `PartnerField` model
* Added functionality to display `estimated_emissions_activity` & `estimated_annual_energy_consumption` in Production Location Profile page

### Release instructions
* Ensure that the following commands are included in the `post_deployment` command:
Expand Down
4 changes: 2 additions & 2 deletions src/django/api/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,8 @@ def get_ordering(self, request):


class PartnerFieldAdmin(admin.ModelAdmin):
list_display = ('name', 'type', 'unit', 'created_at')
search_fields = ('name', 'type', 'unit')
list_display = ('name', 'type', 'label', 'unit', 'created_at')
search_fields = ('name', 'type', 'label', 'unit')
readonly_fields = ('uuid', 'created_at', 'updated_at')


Expand Down
74 changes: 70 additions & 4 deletions src/django/api/extended_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,20 @@ def get_product_type_extendedfield_value(field_value):


def all_values_empty(value):
if value is not None and isinstance(value, list):
values = [v for v in value if v is not None and v != ""]
return len(values) == 0
if value is not None:
if isinstance(value, list):
values = [
v for v in value
if v is not None and v != ""
]
return len(values) == 0
if isinstance(value, dict):
values = [
v for v in value.values()
if v is not None and v != ""
]
return len(values) == 0

return False


Expand Down Expand Up @@ -123,6 +134,35 @@ def create_extendedfield(field, field_value, item, contributor):
)


OBJECT_FIELD_TYPE = "object"


def create_partner_extendedfield(
field,
field_value,
field_type,
item,
contributor
):
if field_value is not None and field_value != "" \
and not all_values_empty(field_value):
if field_type == OBJECT_FIELD_TYPE:
field_value = {
'raw_values': field_value,
}
else:
field_value = {
'raw_value': field_value,
}

ExtendedField.objects.create(
contributor=contributor,
facility_list_item=item,
field_name=field,
value=field_value
)


RAW_DATA_FIELDS = (
ExtendedField.NUMBER_OF_WORKERS,
ExtendedField.NATIVE_LANGUAGE_NAME,
Expand All @@ -137,7 +177,10 @@ def create_extendedfield(field, field_value, item, contributor):
)


def create_extendedfields_for_single_item(item, raw_data):
def create_extendedfields_for_single_item(
item,
raw_data
):
if item.id is None:
return False
contributor = item.source.contributor
Expand All @@ -147,6 +190,29 @@ def create_extendedfields_for_single_item(item, raw_data):
create_extendedfield(field, field_value, item, contributor)


def create_partner_extendedfields_for_single_item(
item,
raw_data
):
if item.id is None:
return False
contributor = item.source.contributor

for partner_field in item.source.contributor \
.partner_fields.all():
field = partner_field.name
field_type = partner_field.type
field_value = raw_data.get(field)

create_partner_extendedfield(
field,
field_value,
field_type,
item,
contributor
)


def update_extendedfields_for_list_item(list_item):
for extended_field in ExtendedField.objects.filter(
facility_list_item=list_item):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from django.db import migrations, models
import uuid

class Migration(migrations.Migration):
"""
Expand Down
22 changes: 22 additions & 0 deletions src/django/api/migrations/0181_add_label_to_partner_field.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from django.db import migrations, models

class Migration(migrations.Migration):
"""
Migration add unit field to PartnerField model.
"""

dependencies = [
('api', '0180_add_unit_to_partner_field'),
]

operations = [
migrations.AddField(
model_name='partnerfield',
name='label',
field=models.CharField(
max_length=200,
blank=True,
help_text=('The partner field label.')
),
),
]
10 changes: 10 additions & 0 deletions src/django/api/models/extended_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class ExtendedField(models.Model):
DUNS_ID = 'duns_id'
LEI_ID = 'lei_id'
RBA_ID = 'rba_id'
ESTIMATED_EMISSIONS_ACTIVITY = 'estimated_emissions_activity'
ESTIMATED_ANNUAL_ENERGY_CONSUMPTION = 'estimated_annual_energy_consumption'

FIELD_CHOICES = (
(NAME, NAME),
Expand All @@ -36,6 +38,14 @@ class ExtendedField(models.Model):
(DUNS_ID, DUNS_ID),
(LEI_ID, LEI_ID),
(RBA_ID, RBA_ID),
(
ESTIMATED_EMISSIONS_ACTIVITY,
ESTIMATED_EMISSIONS_ACTIVITY
),
(
ESTIMATED_ANNUAL_ENERGY_CONSUMPTION,
ESTIMATED_ANNUAL_ENERGY_CONSUMPTION
)
)

uuid = models.UUIDField(
Expand Down
4 changes: 4 additions & 0 deletions src/django/api/models/partner_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ class Meta:
max_length=200,
blank=True,
help_text=('The partner field unit.'))
label = models.CharField(
max_length=200,
blank=True,
help_text=('The partner field label.'))

created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
)
from api.extended_fields import (
create_extendedfields_for_single_item,
create_partner_extendedfields_for_single_item,
update_extendedfields_for_list_item,
)
from api.models.contributor.contributor import Contributor
Expand Down Expand Up @@ -83,12 +84,24 @@ def process_moderation_event(self) -> FacilityListItem:
f'created. Id: {item.id}'
)

create_extendedfields_for_single_item(item, data["fields"])
create_extendedfields_for_single_item(
item,
data["fields"]
)
log.info(
f'{LOCATION_CONTRIBUTION_APPROVAL_LOG_PREFIX} Extended fields '
'created.'
)

create_partner_extendedfields_for_single_item(
item,
data["fields"]
)
log.info(
f'{LOCATION_CONTRIBUTION_APPROVAL_LOG_PREFIX} Partner extended '
'fields created.'
)

self.__set_geocoded_location(item, data, self.__event)
log.info(
f'{LOCATION_CONTRIBUTION_APPROVAL_LOG_PREFIX} Geocoded '
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ def __transform_type_errors(
'errors': [
{
'field': name,
'detail': f'Field {name} must be of type {expected}, '
f'but received {type(value).__name__}',
'detail': f'Field {name} must be a {expected}, '
f'not a {type(value).__name__}.',
}
for name, expected, value in invalid_type_fields
],
Expand Down
Loading
Loading