diff --git a/.vscode/settings.json b/.vscode/settings.json index 923b8bb5..c5984d3b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,7 @@ { "settings": { "python.terminal.activateEnvInCurrentTerminal": true, - "python.defaultInterpreterPath": "${workspaceFolder}/venv/bin/python" + "python.defaultInterpreterPath": "${workspaceFolder}/venv/bin/python", + "editor.renderWhitespace": "all", } } diff --git a/mooringlicensing/components/approvals/api.py b/mooringlicensing/components/approvals/api.py index 2c99f4f3..d61facc3 100755 --- a/mooringlicensing/components/approvals/api.py +++ b/mooringlicensing/components/approvals/api.py @@ -354,7 +354,7 @@ def get_queryset(self): if is_internal(self.request): if target_email_user_id: target_user = EmailUser.objects.get(id=target_email_user_id) - all = all.filter(Q(submitter=target_user)) + all = all.filter(Q(submitter=target_user.id)) return all elif is_customer(self.request): qs = all.filter(Q(submitter=request_user.id)) diff --git a/mooringlicensing/components/approvals/models.py b/mooringlicensing/components/approvals/models.py index 83b6c348..0424845f 100755 --- a/mooringlicensing/components/approvals/models.py +++ b/mooringlicensing/components/approvals/models.py @@ -1236,8 +1236,13 @@ def manage_stickers(self, proposal): existing_sticker = existing_stickers.order_by('number').last() # There should be just one existing sticker if proposal.proposal_type.code == PROPOSAL_TYPE_AMENDMENT: # There is an existing sticker to be replaced - existing_sticker_to_be_returned = existing_sticker - new_sticker_status = Sticker.STICKER_STATUS_NOT_READY_YET + if proposal.vessel_ownership == proposal.previous_application.vessel_ownership: + # Same vessel_ownership means the same vessel. In the case no other vessel related, existing sticker does not need to be returned. + existing_sticker_to_be_expired = existing_sticker + else: + # Different vessel related. In this case, existing sticker needs to be returned. + existing_sticker_to_be_returned = existing_sticker + new_sticker_status = Sticker.STICKER_STATUS_NOT_READY_YET elif proposal.proposal_type.code == PROPOSAL_TYPE_RENEWAL: # There is an existing sticker to be replaced existing_sticker_to_be_expired = existing_sticker diff --git a/mooringlicensing/components/approvals/serializers.py b/mooringlicensing/components/approvals/serializers.py index f2caaf37..115931cd 100755 --- a/mooringlicensing/components/approvals/serializers.py +++ b/mooringlicensing/components/approvals/serializers.py @@ -861,7 +861,7 @@ def get_stickers_historical(self, obj): return list_return def get_stickers(self, obj): - stickers = obj.stickers.filter(status__in=[ + stickers = obj.stickers.order_by('id').filter(status__in=[ Sticker.STICKER_STATUS_CURRENT, Sticker.STICKER_STATUS_AWAITING_PRINTING] ) diff --git a/mooringlicensing/components/compliances/api.py b/mooringlicensing/components/compliances/api.py index d936a182..8d8ef02c 100755 --- a/mooringlicensing/components/compliances/api.py +++ b/mooringlicensing/components/compliances/api.py @@ -414,7 +414,7 @@ def get_queryset(self): if is_internal(self.request): if target_email_user_id: target_user = EmailUser.objects.get(id=target_email_user_id) - qs = Compliance.objects.filter(Q(approval__submitter=target_user)) + qs = Compliance.objects.filter(Q(approval__submitter=target_user.id)) else: qs = Compliance.objects.all() elif is_customer(self.request): diff --git a/mooringlicensing/components/proposals/api.py b/mooringlicensing/components/proposals/api.py index a0b6ed5b..da8c0698 100755 --- a/mooringlicensing/components/proposals/api.py +++ b/mooringlicensing/components/proposals/api.py @@ -1355,7 +1355,7 @@ def fetch_vessel(self, request, *args, **kwargs): if instance.vessel_ownership: vessel_ownership_serializer = VesselOwnershipSerializer(instance.vessel_ownership) vessel_ownership_data = deepcopy(vessel_ownership_serializer.data) - vessel_ownership_data["individual_owner"] = False if instance.vessel_ownership.company_ownerships else True + vessel_ownership_data["individual_owner"] = False if instance.vessel_ownership.individual_owner else True else: vessel_ownership_data["percentage"] = instance.percentage vessel_ownership_data["individual_owner"] = instance.individual_owner @@ -1739,7 +1739,7 @@ def lookup_vessel_ownership(self, request, *args, **kwargs): vessel_ownership_data = {} vessel_ownership_serializer = VesselOwnershipSerializer(vo) vessel_ownership_data = deepcopy(vessel_ownership_serializer.data) - vessel_ownership_data["individual_owner"] = False if vo.company_ownership else True + vessel_ownership_data["individual_owner"] = True if vo.individual_owner else False vessel_data["vessel_ownership"] = vessel_ownership_data return Response(vessel_data) @@ -2038,7 +2038,7 @@ def lookup_vessel(self, request, *args, **kwargs): vessel_ownership = vo_qs[0] vessel_ownership_serializer = VesselOwnershipSerializer(vessel_ownership) vessel_ownership_data = deepcopy(vessel_ownership_serializer.data) - vessel_ownership_data["individual_owner"] = False if vessel_ownership.company_ownerships else True + vessel_ownership_data["individual_owner"] = True if vessel_ownership.individual_owner else False vessel_data["vessel_ownership"] = vessel_ownership_data return Response(vessel_data) @@ -2050,7 +2050,7 @@ def list_internal(self, request, *args, **kwargs): target_email_user_id = int(self.request.GET.get('target_email_user_id', 0)) if target_email_user_id: target_user = EmailUser.objects.get(id=target_email_user_id) - owner_qs = Owner.objects.filter(emailuser=target_user) + owner_qs = Owner.objects.filter(emailuser=target_user.id) if owner_qs: owner = owner_qs[0] diff --git a/mooringlicensing/components/proposals/models.py b/mooringlicensing/components/proposals/models.py index 382f1d4d..e7d26ce9 100644 --- a/mooringlicensing/components/proposals/models.py +++ b/mooringlicensing/components/proposals/models.py @@ -4104,7 +4104,6 @@ def get_queryset(self): class VesselOwnership(RevisionedMixin): owner = models.ForeignKey('Owner', on_delete=models.CASCADE) vessel = models.ForeignKey(Vessel, on_delete=models.CASCADE) - # company_ownership = models.ForeignKey(CompanyOwnership, null=True, blank=True, on_delete=models.CASCADE) percentage = models.IntegerField(null=True, blank=True) start_date = models.DateTimeField(default=timezone.now) # date of sale @@ -4127,6 +4126,10 @@ def get_latest_company_ownership(self, status_list=[VesselOwnershipCompanyOwners if self.company_ownerships.count(): company_ownership = self.company_ownerships.filter(vesselownershipcompanyownership__status__in=status_list).order_by('created').last() return company_ownership + # company_ownership = self.company_ownerships.all().order_by('updated').last() + # for voco in VesselOwnershipCompanyOwnership.objects.filter(vessel_ownership=self, company_ownership=company_ownership): + # if voco.status in status_list: + # return company_ownership return CompanyOwnership.objects.none() @property diff --git a/mooringlicensing/components/proposals/signals.py b/mooringlicensing/components/proposals/signals.py index da9fa967..33078786 100644 --- a/mooringlicensing/components/proposals/signals.py +++ b/mooringlicensing/components/proposals/signals.py @@ -2,14 +2,23 @@ from django.db.models.signals import post_save from django.dispatch import receiver -from mooringlicensing.components.proposals.models import Proposal, CompanyOwnership, VesselOwnershipCompanyOwnership +from mooringlicensing.components.proposals.models import AuthorisedUserApplication, MooringLicenceApplication, Proposal, CompanyOwnership, VesselOwnershipCompanyOwnership logger = logging.getLogger(__name__) -class ProposalListener(object): +# class TestListener(object): +# @staticmethod +# @receiver(post_save, sender=MooringLicenceApplication) +# def _post_save(sender, instance, **kwargs): +# logger.info(f'sender: [{sender}]') +# logger.info(f'instance: [{instance}]') + +class ProposalListener(object): @staticmethod @receiver(post_save, sender=Proposal) + @receiver(post_save, sender=MooringLicenceApplication) # To make sure this signal is called, register 'MooringLicenceApplication' too as well as 'Proposal'. + # Without this line, in some case this _post_save() signal is not called even after saving the MLApplication. def _post_save(sender, instance, **kwargs): if instance.processing_status in [ Proposal.PROCESSING_STATUS_APPROVED, @@ -25,36 +34,15 @@ def _post_save(sender, instance, **kwargs): # Update the status of the vessel_ownersip_company_ownership if instance.vessel_ownership: - # company_ownerships = instance.vessel_ownership.company_ownerships.filter( - # vessel=instance.vessel_ownership.vessel, - # vesselownershipcompanyownership__status__in=[VesselOwnershipCompanyOwnership.COMPANY_OWNERSHIP_STATUS_DRAFT,] - # ) - # for company_ownership in company_ownerships: - # # For each company_ownership with the 'draft' status - # vessel_ownership_company_ownerships = VesselOwnershipCompanyOwnership.objects.filter( - # company_ownership=company_ownership, - # vessel_ownership=instance.vessel_ownership, - # status=VesselOwnershipCompanyOwnership.COMPANY_OWNERSHIP_STATUS_DRAFT - # ) - # for vessel_ownership_company_ownership in vessel_ownership_company_ownerships: - # if instance.processing_status in [Proposal.PROCESSING_STATUS_APPROVED, Proposal.PROCESSING_STATUS_PRINTING_STICKER,]: - # new_status = VesselOwnershipCompanyOwnership.COMPANY_OWNERSHIP_STATUS_APPROVED - # elif instance.processing_status in [Proposal.PROCESSING_STATUS_DECLINED,]: - # new_status = VesselOwnershipCompanyOwnership.COMPANY_OWNERSHIP_STATUS_DECLINED - # vessel_ownership_company_ownership.status = new_status - # vessel_ownership_company_ownership.save() - # logger.info(f'Status: [{new_status}] has been set to the VesselOwnershipCompanyOwnership: [{vessel_ownership_company_ownership}].') - vocos_draft = VesselOwnershipCompanyOwnership.objects.filter( vessel_ownership=instance.vessel_ownership, status=VesselOwnershipCompanyOwnership.COMPANY_OWNERSHIP_STATUS_DRAFT ) for voco_draft in vocos_draft: - new_status = '' if instance.processing_status in [Proposal.PROCESSING_STATUS_APPROVED, Proposal.PROCESSING_STATUS_PRINTING_STICKER,]: voco_draft.status = VesselOwnershipCompanyOwnership.COMPANY_OWNERSHIP_STATUS_APPROVED voco_draft.save() - logger.info(f'Status: [{new_status}] has been set to the VesselOwnershipCompanyOwnership: [{voco_draft}].') + logger.info(f'Status: [{VesselOwnershipCompanyOwnership.COMPANY_OWNERSHIP_STATUS_APPROVED}] has been set to the VesselOwnershipCompanyOwnership: [{voco_draft}].') # Set status 'old' to the previous 'approved' voco vocos_approved = VesselOwnershipCompanyOwnership.objects.filter( @@ -68,14 +56,19 @@ def _post_save(sender, instance, **kwargs): elif instance.processing_status in [Proposal.PROCESSING_STATUS_DECLINED,]: voco_draft.status = VesselOwnershipCompanyOwnership.COMPANY_OWNERSHIP_STATUS_DECLINED voco_draft.save() - logger.info(f'Status: [{new_status}] has been set to the VesselOwnershipCompanyOwnership: [{voco_draft}].') - - # for voco_approved in vocos_approved: - # if voco_approved.id not in vocos_approved_ids: # Avoid the vocos approved just now - # voco_approved.status = VesselOwnershipCompanyOwnership.COMPANY_OWNERSHIP_STATUS_OLD - # voco_approved.save() - # logger.info(f'Status: [{VesselOwnershipCompanyOwnership.COMPANY_OWNERSHIP_STATUS_OLD}] has been set to the VesselOwnershipCompanyOwnership: [{voco_approved}].') - - + logger.info(f'Status: [{VesselOwnershipCompanyOwnership.COMPANY_OWNERSHIP_STATUS_DECLINED}] has been set to the VesselOwnershipCompanyOwnership: [{voco_draft}].') + if instance.processing_status in [Proposal.PROCESSING_STATUS_APPROVED, Proposal.PROCESSING_STATUS_PRINTING_STICKER,]: + # if instance.vessel_ownership.individual_owner: + if instance.individual_owner: + # Proposal.status is 'approved'/'printing_sticker' and the vessel is individually owned. + # Change company_ownership with the 'approved' status to 'old' status + vocos_approved = VesselOwnershipCompanyOwnership.objects.filter( + vessel_ownership=instance.vessel_ownership, + status=VesselOwnershipCompanyOwnership.COMPANY_OWNERSHIP_STATUS_APPROVED + ) + for voco_approved in vocos_approved: + voco_approved.status = VesselOwnershipCompanyOwnership.COMPANY_OWNERSHIP_STATUS_OLD + voco_approved.save() + logger.info(f'Status: [{VesselOwnershipCompanyOwnership.COMPANY_OWNERSHIP_STATUS_OLD}] has been set to the VesselOwnershipCompanyOwnership: [{voco_approved}].') diff --git a/mooringlicensing/components/proposals/utils.py b/mooringlicensing/components/proposals/utils.py index 1ba23af1..aaf94665 100644 --- a/mooringlicensing/components/proposals/utils.py +++ b/mooringlicensing/components/proposals/utils.py @@ -899,6 +899,7 @@ def store_vessel_ownership(request, vessel, instance=None): ) if company_ownership: vessel_ownership.company_ownerships.add(company_ownership) + logger.info(f'CompanyOwnership: [{company_ownership}] has been added to the company_ownerships field of the VesselOwnership: [{vessel_ownership}].') vo_created = True elif instance.proposal_type.code in [PROPOSAL_TYPE_AMENDMENT, PROPOSAL_TYPE_RENEWAL,]: # Retrieve a vessel_ownership from the previous proposal @@ -922,8 +923,11 @@ def store_vessel_ownership(request, vessel, instance=None): vessel_ownership = VesselOwnership.objects.create( owner=owner, # Owner is actually the accessing user (request.user) as above. vessel=vessel, - company_ownership=company_ownership + # company_ownership=company_ownership ) + if company_ownership: + vessel_ownership.company_ownerships.add(company_ownership) + logger.info(f'CompanyOwnership: [{company_ownership}] has been added to the company_ownerships field of the VesselOwnership: [{vessel_ownership}].') vo_created = True q_for_approvals_check &= ~Q(id=instance.approval.id) # We want to exclude the approval we are currently processing for @@ -959,6 +963,7 @@ def store_vessel_ownership(request, vessel, instance=None): ##### if company_ownership: vessel_ownership.company_ownerships.add(company_ownership) + logger.info(f'CompanyOwnership: [{company_ownership}] has been added to the company_ownerships field of the VesselOwnership: [{vessel_ownership}].') ##### # check and set blocking_owner