def handle(self, *args, **options): try: logger.info('Running command {}'.format(__name__)) today = timezone.localtime(timezone.now()).date() # today = today + relativedelta(days=70) # Pick up all the remediation actions which are close to due and no notifications sent yet ras = RemediationAction.objects.filter(Q(due_date__lt=today) & Q(status=RemediationAction.STATUS_OPEN)). \ exclude(notifications__in=RemediationActionNotification.objects.filter(type=RemediationActionNotification.TYPE_OVERDUE)) for ra in ras: print(ra) # Send email (to: offender, bcc: officers) for ra in ras: try: with transaction.atomic(): # Create new comms log entry data = {'sanction_outcome': ra.sanction_outcome.id} serializer = SanctionOutcomeCommsLogEntrySerializer( data=data) serializer.is_valid(raise_exception=True) workflow_entry = serializer.save() to_address = [ ra.sanction_outcome.get_offender()[0].email, ] cc = None bcc = [ ra.sanction_outcome.responsible_officer.email ] if ra.sanction_outcome.responsible_officer else [ member.email for member in ra.sanction_outcome.allocated_group.members ] attachments = [] email_data = send_notification_overdue_remediation_action( to_address, ra.sanction_outcome, cc, bcc, attachments) # Record in the RemediationActionNotification data = { 'remediation_action_id': ra.id, 'sanction_outcome_comms_log_entry_id': workflow_entry.id, 'type': RemediationActionNotification.TYPE_OVERDUE, } serializer = RemediationActionNotificationCreateSerializer( data=data) serializer.is_valid(raise_exception=True) ran = serializer.save() # Set remediation action status to the 'overdue' serializer = RemediationActionUpdateStatusSerializer( ra, data={'status': RemediationAction.STATUS_OVERDUE}, ) serializer.is_valid(raise_exception=True) serializer.save() # Comms log if email_data: serializer = SanctionOutcomeCommsLogEntrySerializer( workflow_entry, data=email_data, partial=True) serializer.is_valid(raise_exception=True) serializer.save() # Action log, status has been changed to the 'overdue', record it as an action ra.sanction_outcome.log_user_action( SanctionOutcomeUserAction. ACTION_REMEDIATION_ACTION_OVERDUE.format( ra.remediation_action_id)) except Exception as e: logger.error('Error command {}'.format(__name__)) logger.info('Command {} completed'.format(__name__)) except Exception as e: logger.error('Error command {}'.format(__name__))
def handle(self, *args, **options): try: with transaction.atomic(): logger.info('Running command {}'.format(__name__)) today = timezone.localtime(timezone.now()).date() # Retrieve quersyset of SanctionOutcomes # type == 'infringement_notice' # is_parking_offence == True # status == 'with_dot' # details not sent to the DoT yet acos = AllegedCommittedOffence.objects.filter(Q(sanction_outcome__type=SO_TYPE_INFRINGEMENT_NOTICE) & Q(sanction_outcome__status=SanctionOutcome.STATUS_WITH_DOT) & Q(sanction_outcome__offender=None) & Q(sanction_outcome__dot_request_files=None) & Q(included=True) & Q(alleged_offence__removed=False) & Q(alleged_offence__section_regulation__is_parking_offence=True)).\ exclude(sanction_outcome__payment_status=SanctionOutcome.PAYMENT_STATUS_PAID) count = acos.count() logger.info( '{} parking infringement notice(s) found to process.'. format(str(count))) for aco in acos: print(aco.sanction_outcome.id) if count: file_for_dot = DotRequestFile() file_for_dot.save( ) # Create the object to save manytomany fields index = 1 for aco in acos: try: file_for_dot.contents += aco.sanction_outcome.registration_number + ',' + str( index ).zfill( 2 ) + ',' + aco.sanction_outcome.offence_occurrence_date.strftime( "%d%m%Y") + '\r\n' file_for_dot.sanction_outcomes.add( aco.sanction_outcome) except Exception as e: logger.error('Error command {}'.format(__name__)) if not file_for_dot.sanction_outcomes.count(): return file_for_dot.filename = 'DPaw-' + datetime.date.today( ).strftime("%d%b%Y") + '-Request.txt' file_for_dot.save() # Determine the bcc members = get_infringement_notice_coordinators() recipients = [ member.email for member in members ] if members else [settings.NOTIFICATION_EMAIL] # Email to_address = recipients cc = None bcc = None attachments = [ (file_for_dot.filename, file_for_dot.contents, 'text/plain'), ] email_data = email_detais_to_department_of_transport( to_address, attachments, cc, bcc) # # Add communication log if email_data: for so in file_for_dot.sanction_outcomes.all(): email_data['sanction_outcome'] = so.id serializer = SanctionOutcomeCommsLogEntrySerializer( data=email_data, partial=True) serializer.is_valid(raise_exception=True) serializer.save() # Record action log per infringement notice for so in file_for_dot.sanction_outcomes.all(): so.log_user_action( SanctionOutcomeUserAction.ACTION_SEND_TO_DOT. format(so.lodgement_number)) so.status = SanctionOutcome.STATUS_WITH_DOT # probably already WITH_DOT so.save() logger.info('Command {} completed'.format(__name__)) except Exception as e: logger.error('Error command {}'.format(__name__))
def handle(self, *args, **options): try: with transaction.atomic(): logger.info('Running command {}'.format(__name__)) today = timezone.localtime(timezone.now()).date() # Retrieve sanction outcomes whose type is Infringement Notice and which is unpaid sanction_outcomes_base = SanctionOutcome.objects.filter( Q(type=SanctionOutcome.TYPE_INFRINGEMENT_NOTICE) & Q(status=SanctionOutcome.STATUS_AWAITING_PAYMENT) & Q(payment_status=SanctionOutcome.PAYMENT_STATUS_UNPAID))\ .filter(due_dates__in=SanctionOutcomeDueDate.objects.filter(Q(due_date_2nd__lt=today) & Q(due_date_term_currently_applied='2nd'))) if DEBUG: # For debugging purpose, infringement notice which has the string '__overdue2nd__' in the description field is also selected. logger.info('DEBUG = True') sanction_outcomes_debug = SanctionOutcome.objects.filter( Q(type=SanctionOutcome.TYPE_INFRINGEMENT_NOTICE) & # Q(status=SanctionOutcome.STATUS_AWAITING_PAYMENT) & # Q(payment_status=SanctionOutcome.PAYMENT_STATUS_UNPAID) & Q(description__icontains='__overdue2nd__')) # .filter(due_dates__in=SanctionOutcomeDueDate.objects.filter(Q(due_date_term_currently_applied='2nd'))) # Merge querysets sanction_outcomes = (sanction_outcomes_base | sanction_outcomes_debug).distinct() count = sanction_outcomes.count() logger.info( '{} overdue (1st) infringement notice(s) found.'.format( str(count))) if count: # Create record first to generate filename based on the ID uin_file = UnpaidInfringementFile() uin_file.save() # Construct header uin_header = UnpaidInfringementFileHeader() uin_header.agency_code.set('DPW') uin_header.uin_file_reference.set(uin_file.filename) uin_header.date_created.set(datetime.date.today()) uin_header.responsible_officer.set('') content_header = uin_header.get_content() # Construct body content_body = '' penalty_amount_total = 0 for so in sanction_outcomes: try: content_body += so.get_content_for_uin() penalty_amount_total += so.penalty_amount_2nd except Exception as e: logger.error( 'Error command {} for the sanction outcome: {}' .format(__name__, str(so.id))) # Construct trailer uin_trailer = UnpaidInfringementFileTrailer() uin_trailer.number_of_records.set( sanction_outcomes.count()) uin_trailer.total_penalty_amount.set(penalty_amount_total) uin_trailer.first_additional_cost_code.set('') uin_trailer.first_additional_cost_total.set('') uin_trailer.second_additional_cost_code.set('') uin_trailer.second_additional_cost_total.set('') content_trailer = uin_trailer.get_content() # Construct file contents contents_to_attach = content_header + content_body + content_trailer # Save contents in the DB, too uin_file.contents = contents_to_attach uin_file.save() # Determine the recipients members = get_infringement_notice_coordinators() # Emailing to_address = [ member.email for member in members ] if members else [settings.NOTIFICATION_EMAIL] cc = None bcc = None attachments = [ (uin_file.filename, contents_to_attach, 'text/plain'), ] email_data = send_unpaid_infringements_file( to_address, cc, bcc, attachments) # # Add communication log if email_data: for so in sanction_outcomes: email_data['sanction_outcome'] = so.id serializer = SanctionOutcomeCommsLogEntrySerializer( data=email_data, partial=True) serializer.is_valid(raise_exception=True) serializer.save() # Record action log per infringement notice # for dict_item in due_dates: for so in sanction_outcomes: so.log_user_action( SanctionOutcomeUserAction. ACTION_SEND_DETAILS_TO_INFRINGEMENT_NOTICE_COORDINATOR .format(so.lodgement_number)) so.status = SanctionOutcome.STATUS_OVERDUE so.save() # Create new due_date record data = {} data['due_date_1st'] = None data['due_date_2nd'] = None data['reason_for_extension'] = 'Overdue 2nd due date' data['extended_by_id'] = None data['sanction_outcome_id'] = so.id data['due_date_term_currently_applied'] = 'overdue' serializer = SaveSanctionOutcomeDueDateSerializer( data=data) serializer.is_valid(raise_exception=True) serializer.save() logger.info('Command {} completed'.format(__name__)) except Exception as e: logger.error('Error command {}'.format(__name__))
def handle(self, *args, **options): try: logger.info('Running command {}'.format(__name__)) today = timezone.localtime(timezone.now()).date() one_week_before = today + relativedelta(days=7) # Pick up all the remediation actions which are close to due and no notifications sent yet ras = RemediationAction.objects\ .filter( Q(due_date__lt=one_week_before) & Q(status=RemediationAction.STATUS_OPEN))\ .exclude(notifications__in=RemediationActionNotification.objects.filter(type=RemediationActionNotification.TYPE_CLOSE_TO_DUE)) for ra in ras: print(ra) # Send email (to: offender, bcc: officers) for ra in ras: try: with transaction.atomic(): data = {'sanction_outcome': ra.sanction_outcome.id} serializer = SanctionOutcomeCommsLogEntrySerializer( data=data) serializer.is_valid(raise_exception=True) workflow_entry = serializer.save() to_address = [ ra.sanction_outcome.get_offender()[0].email, ] cc = None bcc = [ member.email for member in ra.sanction_outcome.allocated_group.members ] attachments = [] email_data = send_notification_close_to_due_remediation_action( to_address, ra.sanction_outcome, workflow_entry, cc, bcc, attachments) # Record in the RemediationActionNotification data = { 'remediation_action_id': ra.id, 'sanction_outcome_comms_log_entry_id': workflow_entry.id, 'type': RemediationActionNotification.TYPE_CLOSE_TO_DUE, } serializer = RemediationActionNotificationCreateSerializer( data=data) serializer.is_valid(raise_exception=True) ran = serializer.save() # Comms log if email_data: serializer = SanctionOutcomeCommsLogEntrySerializer( workflow_entry, data=email_data, partial=True) serializer.is_valid(raise_exception=True) serializer.save() # Action log: sending reminder mail doesn't require an action log entry except Exception as e: logger.error('Error command {}'.format(__name__)) logger.info('Command {} completed'.format(__name__)) except Exception as e: logger.error('Error command {}'.format(__name__))