def clean(self): cleaned_data = super(Categorized, self).clean() branch = self.wizard.values[u'branch'] delivered_date = self.wizard.values[u'delivered_date'] legal_date = cleaned_data.get(u'legal_date', None) last_action_dd = cleaned_data.get(u'last_action_dd', None) if legal_date is not None: try: if legal_date > delivered_date: msg = _( u'inforequests:obligee_action:Categorized:legal_date:error:newer_than_delivered_date' ) raise ValidationError(msg) if legal_date < branch.last_action.legal_date: msg = _( u'inforequests:obligee_action:Categorized:legal_date:error:older_than_previous' ) raise ValidationError(msg) if legal_date > local_today(): msg = _( u'inforequests:obligee_action:Categorized:legal_date:error:from_future' ) raise ValidationError(msg) except ValidationError as e: if u'legal_date' in cleaned_data: self.add_error(u'legal_date', e) if last_action_dd is not None: try: if legal_date and last_action_dd > legal_date: msg = _( u'inforequests:obligee_action:Categorized:last_action_dd:error:newer_than_legal_date' ) raise ValidationError(msg) if last_action_dd < branch.last_action.legal_date: msg = _( u'inforequests:obligee_action:Categorized:last_action_dd:error:older_than_last_action_legal_date' ) raise ValidationError(msg) if last_action_dd > local_today(): msg = _( u'inforequests:obligee_action:Categorized:last_action_dd:error:from_future' ) raise ValidationError(msg) pass except ValidationError as e: if u'last_action_dd' in cleaned_data: self.add_error(u'last_action_dd', e) return cleaned_data
def add_expirations(): inforequests = (Inforequest.objects.not_closed().without_undecided_email( ).prefetch_related(Inforequest.prefetch_branches()).prefetch_related( Branch.prefetch_last_action(u'branches'))) filtered = [] for inforequest in inforequests: for branch in inforequest.branches: try: if not branch.last_action.has_obligee_deadline: continue if not branch.last_action.deadline_missed: continue if workdays.between(branch.last_action.deadline_date, local_today()) < 30: continue # Last action obligee deadline was missed at least 30 workdays ago. 30 workdays is # half of EXPIRATION deadline. filtered.append(branch) except Exception: cron_logger.error( u'Checking if expiration action should be added failed: %s\n%s' % (repr(branch), traceback.format_exc())) for branch in filtered: try: with transaction.atomic(): branch.add_expiration_if_expired() cron_logger.info(u'Added expiration action: %s' % repr(branch)) except Exception: cron_logger.error(u'Adding expiration action failed: %s\n%s' % (repr(branch), traceback.format_exc()))
def can_add_appeal(self): if self.last_action.type in [ Action.TYPES.REQUEST, Action.TYPES.CLARIFICATION_RESPONSE, Action.TYPES.CONFIRMATION, Action.TYPES.EXTENSION, Action.TYPES.REMANDMENT, Action.TYPES.ADVANCED_REQUEST, ]: # All these actions have deadlines return self.last_action.deadline.is_deadline_missed if self.last_action.type == Action.TYPES.ADVANCEMENT: # Advancement has no deadline defined return (local_today() - self.last_action.delivered_date).days <= 7 if self.last_action.type == Action.TYPES.REFUSAL: return self.last_action.deadline.calendar_days_behind <= 7 if self.last_action.type == Action.TYPES.DISCLOSURE: return (self.last_action.disclosure_level != Action.DISCLOSURE_LEVELS.FULL and self.last_action.deadline.calendar_days_behind <= 47) if self.last_action.type == Action.TYPES.EXPIRATION: return self.last_action.deadline.calendar_days_behind <= 47 return False
def test_deadline_missed_property_and_deadline_missed_at_method_without_deadline( self): with self._test_deadline_missed_aux( type=Action.TYPES.REVERSION) as action: self.assertIsNone(action.deadline) self.assertFalse(action.deadline_missed) self.assertFalse(action.deadline_missed_at(local_today()))
def _create_action(self, **kwargs): return self._call_with_defaults(Action.objects.create, kwargs, { u'type': Action.TYPES.REQUEST, u'subject': u'Default Testing Subject', u'content': u'Default Testing Content', u'effective_date': local_today(), })
def __init__(self, type, base_date, value, unit, snooze): self.type = type self.base_date = base_date self.value = value self.unit = unit self._snooze = snooze self._today = local_today()
def deadline_details_live_aux(cls, effective_date, deadline, extension): try: deadline = int(deadline) extension = int(extension or '0') except (ValueError, TypeError): return u'--' for format in get_format(u'DATE_INPUT_FORMATS'): try: effective_date = datetime.datetime.strptime( effective_date, format).date() break except (ValueError, TypeError): continue else: return u'--' days_passed = workdays.between(effective_date, local_today()) deadline_remaining = deadline + extension - days_passed deadline_missed = (deadline_remaining < 0) if deadline_missed: return u'Deadline was missed {days} working days ago.'.format( days=-deadline_remaining) else: return u'Deadline will be missed in {days} working days.'.format( days=deadline_remaining)
def _create_action(self, **kwargs): return self._call_with_defaults( Action.objects.create, kwargs, { u'type': Action.TYPES.REQUEST, u'subject': u'Default Testing Subject', u'content': u'Default Testing Content', u'effective_date': local_today(), })
def clean(self): cleaned_data = super(AppealPaperStep, self).clean() branch = self.wizard.branch effective_date = cleaned_data.get(u'effective_date', None) if effective_date: try: if effective_date < branch.last_action.effective_date: raise ValidationError(_(u'inforequests:AppealPaperStep:effective_date:older_than_last_action_error')) if effective_date < local_today(): raise ValidationError(_(u'inforequests:AppealPaperStep:effective_date:from_past_error')) if effective_date > local_today() + relativedelta(days=5): raise ValidationError(_(u'inforequests:AppealPaperStep:effective_date:too_far_from_future_error')) except ValidationError as e: self.add_error(u'effective_date', e) return cleaned_data
def add_expiration_if_expired(self): if self.last_action.has_obligee_deadline and self.last_action.deadline_missed: expiration = Action( branch=self, type=(Action.TYPES.APPEAL_EXPIRATION if self.last_action.type == Action.TYPES.APPEAL else Action.TYPES.EXPIRATION), effective_date=local_today(), ) expiration.save()
def save(self, action): action.branch = self.branch action.subject = self.values[u'subject'] action.content = self.values[u'content'] action.effective_date = local_today() @after_saved(action) def deferred(action): action.attachment_set = self.values[u'attachments']
def clean(self): cleaned_data = super(EffectiveDateMixin, self).clean() if not self.draft: branch = cleaned_data.get(u'branch', None) effective_date = cleaned_data.get(u'effective_date', None) if effective_date: try: if branch and effective_date < branch.last_action.effective_date: raise ValidationError(_(u'inforequests:EffectiveDateMixin:older_than_previous_error')) if effective_date > local_today(): raise ValidationError(_(u'inforequests:EffectiveDateMixin:from_future_error')) if effective_date < local_today() - relativedelta(months=1): raise ValidationError(_(u'inforequests:EffectiveDateMixin:older_than_month_error')) except ValidationError as e: self.add_error(u'effective_date', e) return cleaned_data
def clean(self): cleaned_data = super(InputBasics, self).clean() branch = self.wizard.values[u'branch'] delivered_date = cleaned_data.get(u'delivered_date', None) if delivered_date is not None: try: if delivered_date < branch.last_action.legal_date: msg = _(u'inforequests:obligee_action:InputBasics:delivered_date:error:older_than_previous') raise ValidationError(msg.format(date=branch.last_action.legal_date)) if delivered_date > local_today(): msg = _(u'inforequests:obligee_action:InputBasics:delivered_date:error:from_future') raise ValidationError(msg) if delivered_date < local_today() - relativedelta(months=1): msg = _(u'inforequests:obligee_action:InputBasics:delivered_date:error:older_than_month') raise ValidationError(msg) except ValidationError as e: self.add_error(u'delivered_date', e) return cleaned_data
def clean(self): cleaned_data = super(AppealLegalDateStep, self).clean() branch = self.wizard.branch legal_date = cleaned_data.get(u'legal_date', None) if legal_date is not None: try: if legal_date < branch.last_action.legal_date: msg = _(u'inforequests:appeal:AppealLegalDateStep:legal_date:error:older_than_last_action') raise ValidationError(msg) if legal_date < local_today(): msg = _(u'inforequests:appeal:AppealLegalDateStep:legal_date:error:from_past') raise ValidationError(msg) if legal_date > local_today() + relativedelta(days=5): msg = _(u'inforequests:appeal:AppealLegalDateStep:legal_date:error:too_far_from_future') raise ValidationError(msg) except ValidationError as e: self.add_error(u'legal_date', e) return cleaned_data
def clean(self): cleaned_data = super(Categorized, self).clean() branch = self.wizard.values[u'branch'] delivered_date = self.wizard.values[u'delivered_date'] legal_date = cleaned_data.get(u'legal_date', None) last_action_dd = cleaned_data.get(u'last_action_dd', None) if legal_date is not None: try: if legal_date > delivered_date: msg = _(u'inforequests:obligee_action:Categorized:legal_date:error:newer_than_delivered_date') raise ValidationError(msg) if legal_date < branch.last_action.legal_date: msg = _(u'inforequests:obligee_action:Categorized:legal_date:error:older_than_previous') raise ValidationError(msg) if legal_date > local_today(): msg = _(u'inforequests:obligee_action:Categorized:legal_date:error:from_future') raise ValidationError(msg) if legal_date < local_today() - relativedelta(months=1): msg = _(u'inforequests:obligee_action:Categorized:legal_date:error:older_than_month') raise ValidationError(msg) except ValidationError as e: self.add_error(u'legal_date', e) if last_action_dd is not None: try: if legal_date and last_action_dd > legal_date: msg = _(u'inforequests:obligee_action:Categorized:last_action_dd:error:newer_than_legal_date') raise ValidationError(msg) if last_action_dd < branch.last_action.legal_date: msg = _(u'inforequests:obligee_action:Categorized:last_action_dd:error:older_than_last_action_legal_date') raise ValidationError(msg) if last_action_dd > local_today(): msg = _(u'inforequests:obligee_action:Categorized:last_action_dd:error:from_future') raise ValidationError(msg) pass except ValidationError as e: self.add_error(u'last_action_dd', e) return cleaned_data
def clean(self): cleaned_data = super(AppealLegalDateStep, self).clean() branch = self.wizard.branch legal_date = cleaned_data.get(u'legal_date', None) if legal_date is not None: try: if legal_date < branch.last_action.legal_date: msg = _(u'inforequests:appeal:AppealLegalDateStep:legal_date:error:older_than_last_action') raise ValidationError(msg) if legal_date < local_today(): msg = _(u'inforequests:appeal:AppealLegalDateStep:legal_date:error:from_past') raise ValidationError(msg) if legal_date > local_today() + relativedelta(days=5): msg = _(u'inforequests:appeal:AppealLegalDateStep:legal_date:error:too_far_from_future') raise ValidationError(msg) except ValidationError as e: if u'legal_date' in cleaned_data: self.add_error(u'legal_date', e) return cleaned_data
def clean(self): cleaned_data = super(AppealPaperStep, self).clean() branch = self.wizard.branch effective_date = cleaned_data.get(u'effective_date', None) if effective_date: try: if effective_date < branch.last_action.effective_date: raise ValidationError( _(u'inforequests:AppealPaperStep:effective_date:older_than_last_action_error' )) if effective_date < local_today(): raise ValidationError( _(u'inforequests:AppealPaperStep:effective_date:from_past_error' )) if effective_date > local_today() + relativedelta(days=5): raise ValidationError( _(u'inforequests:AppealPaperStep:effective_date:too_far_from_future_error' )) except ValidationError as e: self.add_error(u'effective_date', e) return cleaned_data
def clean(self): cleaned_data = super(BasicsStep, self).clean() branch = cleaned_data.get(u'branch', None) effective_date = cleaned_data.get(u'effective_date', None) if effective_date is not None: try: if branch and effective_date < branch.last_action.effective_date: raise ValidationError( _(u'inforequests:obligee_action:BasicsStep:effective_date:older_than_previous_error' )) if effective_date > local_today(): raise ValidationError( _(u'inforequests:obligee_action:BasicsStep:effective_date:from_future_error' )) if effective_date < local_today() - relativedelta(months=1): raise ValidationError( _(u'inforequests:obligee_action:BasicsStep:effective_date:older_than_month_error' )) except ValidationError as e: self.add_error(u'effective_date', e) return cleaned_data
def finish(self): today = local_today() action = Action.create( branch=self.branch, type=Action.TYPES.CLARIFICATION_RESPONSE, subject=self.values[u'subject'], content=self.values[u'content'], sent_date=today, legal_date=today, attachments=self.values[u'attachments'], ) action.save() action.send_by_email() return action.get_absolute_url()
def undecided_email_reminder(): with translation(settings.LANGUAGE_CODE): inforequests = (Inforequest.objects .not_closed() .with_undecided_email() .prefetch_related(Inforequest.prefetch_newest_undecided_email()) ) filtered = [] for inforequest in inforequests: try: email = inforequest.newest_undecided_email last = inforequest.last_undecided_email_reminder if last and last > email.processed: continue days = workdays.between(local_date(email.processed), local_today()) if days < 5: continue filtered.append(inforequest) except Exception: msg = u'Checking if undecided email reminder should be sent failed: {}\n{}' trace = unicode(traceback.format_exc(), u'utf-8') cron_logger.error(msg.format(inforequest, trace)) if not filtered: return filtered = (Inforequest.objects .select_related(u'applicant') .select_undecided_emails_count() .prefetch_related(Inforequest.prefetch_main_branch(None, Branch.objects.select_related(u'historicalobligee'))) .prefetch_related(Inforequest.prefetch_newest_undecided_email()) .filter(pk__in=(o.pk for o in filtered)) ) for inforequest in filtered: try: with transaction.atomic(): inforequest.send_undecided_email_reminder() cron_logger.info(u'Sent undecided email reminder: {}'.format(inforequest)) except Exception: msg = u'Sending undecided email reminder failed: {}\n{}' trace = unicode(traceback.format_exc(), u'utf-8') cron_logger.error(msg.format(inforequest, trace))
def undecided_email_reminder(): with translation(settings.LANGUAGE_CODE): inforequests = (Inforequest.objects.not_closed().with_undecided_email( ).prefetch_related(Inforequest.prefetch_newest_undecided_email())) filtered = [] for inforequest in inforequests: try: email = inforequest.newest_undecided_email last = inforequest.last_undecided_email_reminder if last and last > email.processed: continue days = workdays.between(local_date(email.processed), local_today()) if days < 5: continue nop() # To let tests raise testing exception here. filtered.append(inforequest) except Exception: cron_logger.error( u'Checking if undecided email reminder should be sent failed: %s\n%s' % (repr(inforequest), traceback.format_exc())) if not filtered: return filtered = (Inforequest.objects.select_related( u'applicant').select_undecided_emails_count().prefetch_related( Inforequest.prefetch_main_branch( None, Branch.objects.select_related(u'historicalobligee')) ).prefetch_related( Inforequest.prefetch_newest_undecided_email()).filter( pk__in=(o.pk for o in filtered))) for inforequest in filtered: try: with transaction.atomic(): inforequest.send_undecided_email_reminder() nop() # To let tests raise testing exception here. cron_logger.info(u'Sent undecided email reminder: %s' % repr(inforequest)) # pragma: no branch except Exception: cron_logger.error( u'Sending undecided email reminder failed: %s\n%s' % (repr(inforequest), traceback.format_exc()))
def undecided_email_reminder(): with translation(settings.LANGUAGE_CODE): inforequests = (Inforequest.objects.not_closed().with_undecided_email( ).prefetch_related(Inforequest.prefetch_newest_undecided_email())) filtered = [] for inforequest in inforequests: try: email = inforequest.newest_undecided_email last = inforequest.last_undecided_email_reminder if last and last > email.processed: continue days = workdays.between(local_date(email.processed), local_today()) if days < 5: continue filtered.append(inforequest) except Exception: msg = u'Checking if undecided email reminder should be sent failed: {}\n{}' trace = unicode(traceback.format_exc(), u'utf-8') cron_logger.error(msg.format(inforequest, trace)) if not filtered: return filtered = (Inforequest.objects.select_related( u'applicant').select_undecided_emails_count().prefetch_related( Inforequest.prefetch_main_branch( None, Branch.objects.select_related(u'historicalobligee')) ).prefetch_related( Inforequest.prefetch_newest_undecided_email()).filter( pk__in=(o.pk for o in filtered))) for inforequest in filtered: try: with transaction.atomic(): inforequest.send_undecided_email_reminder() cron_logger.info( u'Sent undecided email reminder: {}'.format( inforequest)) except Exception: msg = u'Sending undecided email reminder failed: {}\n{}' trace = unicode(traceback.format_exc(), u'utf-8') cron_logger.error(msg.format(inforequest, trace))
def undecided_email_reminder(): with translation(settings.LANGUAGE_CODE): inforequests = (Inforequest.objects .not_closed() .with_undecided_email() .prefetch_related(Inforequest.prefetch_newest_undecided_email()) ) filtered = [] for inforequest in inforequests: try: email = inforequest.newest_undecided_email last = inforequest.last_undecided_email_reminder if last and last > email.processed: continue days = workdays.between(local_date(email.processed), local_today()) if days < 5: continue nop() # To let tests raise testing exception here. filtered.append(inforequest) except Exception: cron_logger.error(u'Checking if undecided email reminder should be sent failed: %s\n%s' % (repr(inforequest), traceback.format_exc())) if not filtered: return filtered = (Inforequest.objects .select_related(u'applicant') .select_undecided_emails_count() .prefetch_related(Inforequest.prefetch_main_branch(None, Branch.objects.select_related(u'historicalobligee'))) .prefetch_related(Inforequest.prefetch_newest_undecided_email()) .filter(pk__in=(o.pk for o in filtered)) ) for inforequest in filtered: try: with transaction.atomic(): inforequest.send_undecided_email_reminder() nop() # To let tests raise testing exception here. cron_logger.info(u'Sent undecided email reminder: %s' % repr(inforequest)) # pragma: no branch except Exception: cron_logger.error(u'Sending undecided email reminder failed: %s\n%s' % (repr(inforequest), traceback.format_exc()))
def clean(self): cleaned_data = super(InputBasics, self).clean() branch = self.wizard.values[u'branch'] delivered_date = cleaned_data.get(u'delivered_date', None) if delivered_date is not None: try: if delivered_date < branch.last_action.legal_date: msg = _( u'inforequests:obligee_action:InputBasics:delivered_date:error:older_than_previous' ) raise ValidationError( msg.format(date=branch.last_action.legal_date)) if delivered_date > local_today(): msg = _( u'inforequests:obligee_action:InputBasics:delivered_date:error:from_future' ) raise ValidationError(msg) except ValidationError as e: if u'delivered_date' in cleaned_data: self.add_error(u'delivered_date', e) return cleaned_data
def deadline_details_live_aux(cls, effective_date, deadline, extension): try: deadline = int(deadline) extension = int(extension or '0') except (ValueError, TypeError): return u'--' for format in get_format(u'DATE_INPUT_FORMATS'): try: effective_date = datetime.datetime.strptime(effective_date, format).date() break except (ValueError, TypeError): continue else: return u'--' days_passed = workdays.between(effective_date, local_today()) deadline_remaining = deadline + extension - days_passed deadline_missed = (deadline_remaining < 0) if deadline_missed: return u'Deadline was missed {days} working days ago.'.format(days=-deadline_remaining) else: return u'Deadline will be missed in {days} working days.'.format(days=deadline_remaining)
def test_deadline_remaining_property_and_deadline_remaining_at_method_with_extension( self): with self._test_deadline_missed_aux(deadline=15, extension=4) as action: self.assertEqual(action.deadline_remaining, 14) self.assertEqual(action.deadline_remaining_at(local_today()), 14)
def test_days_passed_property_and_days_passed_at_method(self): with self._test_deadline_missed_aux() as action: self.assertEqual(action.days_passed, 5) self.assertEqual(action.days_passed_at(local_today()), 5)
def test_deadline_missed_property_and_deadline_missed_at_method_without_deadline(self): with self._test_deadline_missed_aux(type=Action.TYPES.REVERSION) as action: self.assertIsNone(action.deadline) self.assertFalse(action.deadline_missed) self.assertFalse(action.deadline_missed_at(local_today()))
def test_local_today_with_day_change(self): with mock.patch(u'django.utils.timezone.datetime', test_datetime(2014, 9, 10, 23, 20)): # in UTC value = local_today() self._check_date(value, u'2014-09-11')
def days_passed(self): return self.days_passed_at(local_today())
def test_deadline_missed_property_and_deadline_missed_at_method_with_not_missed_deadline( self): with self._test_deadline_missed_aux(deadline=15) as action: self.assertFalse(action.deadline_missed) self.assertFalse(action.deadline_missed_at(local_today()))
def test_deadline_remaining_property_and_deadline_remaining_at_method_with_extension(self): with self._test_deadline_missed_aux(deadline=15, extension=4) as action: self.assertEqual(action.deadline_remaining, 14) self.assertEqual(action.deadline_remaining_at(local_today()), 14)
def _new_action(request, inforequest_pk, form_class): assert form_class.action_type in Action.APPLICANT_ACTION_TYPES inforequest = ( Inforequest.objects.not_closed() .owned_by(request.user) .prefetch_related(Inforequest.prefetch_branches(None, Branch.objects.select_related(u"historicalobligee"))) .prefetch_related(Branch.prefetch_last_action(u"branches")) .get_or_404(pk=inforequest_pk) ) if request.method != u"POST": # The user can save a draft even if he may not submit. if inforequest.has_undecided_emails: return HttpResponseNotFound() if not inforequest.can_add_action(form_class.action_type): return HttpResponseNotFound() draft = inforequest.actiondraft_set.filter(type=form_class.action_type).order_by_pk().first() session = Session.objects.get(session_key=request.session.session_key) attached_to = (session, draft) if draft else (session,) if request.method != u"POST": form = form_class(inforequest=inforequest, attached_to=attached_to) if draft: form.load_from_draft(draft) return render_form(request, form, inforequest=inforequest) if form_class.action_type in Action.APPLICANT_EMAIL_ACTION_TYPES: button = clean_button(request.POST, [u"email", u"print", u"draft"]) else: button = clean_button(request.POST, [u"print", u"draft"]) if button == u"draft": form = form_class(request.POST, inforequest=inforequest, attached_to=attached_to, draft=True) if not form.is_valid(): return json_form(request, form, inforequest=inforequest) if not draft: draft = ActionDraft(inforequest=inforequest, type=form_class.action_type) form.save_to_draft(draft) draft.save() return json_draft() if button in [u"email", u"print"]: form = form_class(request.POST, inforequest=inforequest, attached_to=attached_to) if not form.is_valid(): return json_form(request, form, inforequest=inforequest) if form_class.action_type == Action.TYPES.APPEAL: form.cleaned_data[u"branch"].add_expiration_if_expired() action = Action(effective_date=local_today(), type=form_class.action_type) form.save(action) action.save() if draft: draft.delete() # The inforequest was changed, we need to refetch it. inforequest = Inforequest.objects.prefetch_detail().get(pk=inforequest.pk) action.branch = inforequest.branch_by_pk(action.branch_id) if button == u"email": action.send_by_email() return json_success(request, inforequest, action, button == u"print") return HttpResponseBadRequest()
def test_deadline_missed_property_and_deadline_missed_at_method_with_not_missed_deadline(self): with self._test_deadline_missed_aux(deadline=15) as action: self.assertFalse(action.deadline_missed) self.assertFalse(action.deadline_missed_at(local_today()))
def test_deadline_missed_property_and_deadline_missed_at_method_with_extended_missed_deadline_missed_again(self): with self._test_deadline_missed_aux(deadline=2, extension=2) as action: self.assertTrue(action.deadline_missed) self.assertTrue(action.deadline_missed_at(local_today()))
def test_deadline_missed_property_and_deadline_missed_at_method_with_extended_missed_deadline_missed_again( self): with self._test_deadline_missed_aux(deadline=2, extension=2) as action: self.assertTrue(action.deadline_missed) self.assertTrue(action.deadline_missed_at(local_today()))
def deadline_missed(self): return self.deadline_missed_at(local_today())
def deadline_remaining(self): return self.deadline_remaining_at(local_today())
def test_local_today_with_tz_as_string(self): with mock.patch(u'django.utils.timezone.datetime', test_datetime(2014, 9, 10, 2, 20)): # in UTC value = local_today(u'America/Montreal') self._check_date(value, u'2014-09-09')
def save(self, action): assert self.is_valid() action.snooze = local_today() + datetime.timedelta(days=3)
def _create_post_data(self, **kwargs): kwargs.setdefault(u'effective_date', local_today()) return super(EffectiveDateFieldTests, self)._create_post_data(**kwargs)