Skip to content

Commit

Permalink
Merge pull request #3709 from unicef/staging
Browse files Browse the repository at this point in the history
Staging
  • Loading branch information
robertavram authored Jul 5, 2024
2 parents 80f5641 + b595d49 commit a4207ed
Show file tree
Hide file tree
Showing 12 changed files with 614 additions and 96 deletions.
4 changes: 2 additions & 2 deletions runtests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ if [[ $DJANGO_SETTINGS_MODULE = '' || $DJANGO_SETTINGS_MODULE = etools.config.se
fi

# Ensure there are no errors.
#python -W ignore manage.py check
#python -W ignore manage.py makemigrations --dry-run --check
python -W ignore manage.py check
python -W ignore manage.py makemigrations --dry-run --check

# Ensure translations are up-to-date.
cwd=$(pwd)
Expand Down
2 changes: 1 addition & 1 deletion src/etools/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
VERSION = __version__ = '11.4'
VERSION = __version__ = '11.5'
NAME = 'eTools'
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 3.2.19 on 2024-06-13 12:04

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('audit', '0031_auto_20240507_1059'),
]

operations = [
migrations.AlterField(
model_name='engagement',
name='end_date',
field=models.DateField(blank=True, null=True, verbose_name='End date of last reporting FACE'),
),
migrations.AlterField(
model_name='engagement',
name='start_date',
field=models.DateField(blank=True, null=True, verbose_name='Start date of first reporting FACE'),
),
]
89 changes: 80 additions & 9 deletions src/etools/applications/last_mile/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from django.contrib.gis import forms
from django.contrib.gis.geos import Point
from django.db import transaction
from django.urls import reverse
from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _

from unicef_attachments.admin import AttachmentSingleInline
Expand All @@ -27,8 +29,14 @@ class WaybillTransferAttachmentInline(AttachmentSingleInline):
code = 'waybill_file'


class TransferEvidenceAttachmentInline(AttachmentSingleInline):
verbose_name_plural = "Transfer Evidence File"
code = 'transfer_evidence'


@admin.register(models.PointOfInterest)
class PointOfInterestAdmin(XLSXImportMixin, admin.ModelAdmin):
readonly_fields = ('partner_names',)
list_display = ('name', 'parent', 'poi_type', 'p_code')
list_select_related = ('parent',)
list_filter = ('private', 'is_active')
Expand All @@ -48,6 +56,17 @@ class PointOfInterestAdmin(XLSXImportMixin, admin.ModelAdmin):
'P CODE': 'p_code'
}

def partner_names(self, obj):
p_names = []
for p in obj.partner_organizations.all():
print(p)
url = reverse('admin:partners_partnerorganization_change', args=[p.id])
html = format_html('<a href="{}">{}</a>', url, p.name)
p_names.append(html)
return format_html('<br>'.join(p_names))
partner_names.short_description = 'Partner Names'
partner_names.admin_order_field = 'name'

def has_import_permission(self, request):
return is_user_in_groups(request.user, ['Country Office Administrator'])

Expand Down Expand Up @@ -128,7 +147,7 @@ class TransferAdmin(AttachmentInlineAdminMixin, admin.ModelAdmin):
search_fields = ('name', 'status')
raw_id_fields = ('partner_organization', 'checked_in_by', 'checked_out_by',
'origin_point', 'destination_point', 'origin_transfer')
inlines = (ProofTransferAttachmentInline, WaybillTransferAttachmentInline, ItemInline)
inlines = (ProofTransferAttachmentInline, ItemInline)

def get_queryset(self, request):
qs = super(TransferAdmin, self).get_queryset(request)\
Expand Down Expand Up @@ -170,6 +189,16 @@ class ItemAdmin(XLSXImportMixin, admin.ModelAdmin):
list_display = ('batch_id', 'material', 'wastage_type', 'transfer')
raw_id_fields = ('transfer', 'transfers_history', 'material')
list_filter = ('wastage_type', 'hidden')
readonly_fields = ('destination_point_name',)

def destination_point_name(self, obj):
if obj.transfer and obj.transfer.destination_point:
url = reverse('admin:last_mile_pointofinterest_change', args=[obj.transfer.destination_point.id])
return format_html('<a href="{}">{}</a>', url, obj.transfer.destination_point.name)
return '-'
destination_point_name.short_description = 'Destination Point Name'
destination_point_name.short_description = 'Destination Point Name'
destination_point_name.admin_order_field = 'transfer__destination_point__name'

def get_queryset(self, request):
qs = models.Item.all_objects\
Expand Down Expand Up @@ -203,7 +232,8 @@ def import_data(self, workbook):
# first create a list of objects in memory from the file
imported_vendor_numbers = set()
imported_material_numbers = set()
imported_destination_names = set()
# imported_destination_names = set()
imported_partner_destination_name_pair = set()
imported_records = []
for row in range(1, sheet.max_row):
import_dict = {}
Expand All @@ -217,7 +247,11 @@ def import_data(self, workbook):
for imp_record in imported_records:
imported_vendor_numbers.add(imp_record['transfer__partner_organization__vendor_number'])
imported_material_numbers.add(imp_record['material__number'])
imported_destination_names.add(imp_record['transfer__destination_point__name'])
# imported_destination_names.add(imp_record['transfer__destination_point__name'])
imported_partner_destination_name_pair.add(
(imp_record['transfer__partner_organization__vendor_number'],
imp_record['transfer__destination_point__name'])
)

def filter_records(dict_key, model, filter_name, imported_set, recs):
# print("###############", imported_set, dict_key, model.__name__, filter_name, recs)
Expand All @@ -230,6 +264,24 @@ def filter_records(dict_key, model, filter_name, imported_set, recs):

return qs, [d for d in recs if d[dict_key] in available_items]

def filter_complex_records(dict_keys, model, filter_names, imported_set, recs):
# Initialize the query set
qs = model.objects.none()
for tuple_pair in imported_set:
filter_kwargs = {filter_names[i]: tuple_pair[i] for i in range(len(tuple_pair))}
qs = qs | model.objects.filter(**filter_kwargs)

available_items = qs.values_list(*filter_names)
available_set = set(available_items)

dropped_recs = [d for d in recs if (d[dict_keys[0]], d[dict_keys[1]]) not in available_set]
if dropped_recs:
logging.error(
f"Dropping the following lines as records not available in the workspace for type {model.__name__}"
f" '{dropped_recs}' Please add the related records if needed")

return qs, [d for d in recs if (d[dict_keys[0]], d[dict_keys[1]]) in available_set]

partner_org_qs, imported_records = filter_records(
dict_key="transfer__partner_organization__vendor_number",
model=PartnerOrganization,
Expand All @@ -248,14 +300,27 @@ def filter_records(dict_key, model, filter_name, imported_set, recs):
)
material_dict = {m.number: m for m in material_qs}

poi_qs, imported_records = filter_records(
dict_key="transfer__destination_point__name",
# poi_qs, imported_records = filter_records(
# dict_key="transfer__destination_point__name",
# model=models.PointOfInterest,
# filter_name="name",
# imported_set=imported_partner_destination_name_pair,
# recs=imported_records
# )

poi_qs, imported_records = filter_complex_records(
dict_keys=["transfer__partner_organization__vendor_number", "transfer__destination_point__name"],
model=models.PointOfInterest,
filter_name="name",
imported_set=imported_destination_names,
filter_names=["partner_organizations__organization__vendor_number", "name"],
imported_set=imported_partner_destination_name_pair,
recs=imported_records
)
poi_dict = {poi.name: poi for poi in poi_qs.prefetch_related("partner_organizations")}

poi_dict = {}
for poi in poi_qs.prefetch_related("partner_organizations"):
for partner_org in poi.partner_organizations.all():
dict_key = partner_org.vendor_number + poi.name
poi_dict[dict_key] = poi

transfers = {}

Expand All @@ -271,7 +336,7 @@ def get_or_create_transfer(filter_dict):
for imp_r in imported_records:
material = material_dict[imp_r.pop("material__number")]
partner = partner_dict[imp_r.pop("transfer__partner_organization__vendor_number")]
poi = poi_dict[imp_r.pop("transfer__destination_point__name")]
poi = poi_dict[partner.vendor_number + imp_r.pop("transfer__destination_point__name")]
# ensure the POI belongs to the partner else skip:
if partner not in poi.partner_organizations.all():
logging.error(f"skipping record as POI {poi} does not belong to the Partner Org: {partner}")
Expand Down Expand Up @@ -303,4 +368,10 @@ def get_or_create_transfer(filter_dict):
)


@admin.register(models.TransferEvidence)
class TransferEvidenceAdmin(AttachmentInlineAdminMixin, admin.ModelAdmin):
raw_id_fields = ('transfer', 'user')
inlines = [TransferEvidenceAttachmentInline]


admin.site.register(models.PointOfInterestType)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 3.2.19 on 2024-06-17 09:16

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('last_mile', '0003_alter_pointofinterest_p_code'),
]

operations = [
migrations.AlterModelOptions(
name='item',
options={'base_manager_name': 'objects', 'ordering': ('expiry_date',)},
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Generated by Django 3.2.19 on 2024-06-21 10:19

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
import model_utils.fields


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('last_mile', '0004_alter_item_options'),
]

operations = [
migrations.AlterField(
model_name='transfer',
name='transfer_type',
field=models.CharField(blank=True, choices=[('DELIVERY', 'Delivery'), ('DISTRIBUTION', 'Distribution'), ('HANDOVER', 'Handover'), ('WASTAGE', 'Wastage')], max_length=30, null=True),
),
migrations.CreateModel(
name='TransferEvidence',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('comment', models.TextField(blank=True, null=True)),
('transfer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfer_evidences', to='last_mile.transfer')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfer_evidences', to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ('-created',),
},
),
]
30 changes: 29 additions & 1 deletion src/etools/applications/last_mile/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class Transfer(TimeStampedModel, models.Model):

DELIVERY = 'DELIVERY'
DISTRIBUTION = 'DISTRIBUTION'
HANDOVER = 'HANDOVER'
WASTAGE = 'WASTAGE'

SHORT = 'SHORT'
Expand All @@ -110,6 +111,7 @@ class Transfer(TimeStampedModel, models.Model):
TRANSFER_TYPE = (
(DELIVERY, _('Delivery')),
(DISTRIBUTION, _('Distribution')),
(HANDOVER, _('Handover')),
(WASTAGE, _('Wastage'))
)
TRANSFER_SUBTYPE = (
Expand Down Expand Up @@ -188,6 +190,32 @@ def __str__(self):
return f'{self.id} {self.partner_organization.name}: {self.name if self.name else self.unicef_release_order}'


class TransferEvidence(TimeStampedModel, models.Model):
comment = models.TextField(null=True, blank=True)

evidence_file = CodedGenericRelation(
Attachment,
verbose_name=_('Transfer Evidence File'),
code='transfer_evidence',
)
transfer = models.ForeignKey(
Transfer,
on_delete=models.CASCADE,
related_name='transfer_evidences'
)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='transfer_evidences'
)

class Meta:
ordering = ("-created",)

def __str__(self):
return f'{self.transfer.id} {self.transfer.transfer_type} / {self.transfer.partner_organization.name}'


class Material(TimeStampedModel, models.Model):
UOM = (
("BAG", _("BAG")),
Expand Down Expand Up @@ -333,7 +361,7 @@ class Item(TimeStampedModel, models.Model):

class Meta:
base_manager_name = 'objects'
ordering = ("-id",)
ordering = ("expiry_date",)

@cached_property
def partner_organization(self):
Expand Down
Loading

0 comments on commit a4207ed

Please sign in to comment.