class FutureSubscriptionTypeInline(admin.TabularInline): model = Subscription.future_types.through verbose_name = _('Zukunft {0}-Typ').format( Config.vocabulary('subscription')) verbose_name_plural = _('Zukunft {0}-Typen').format( Config.vocabulary('subscription')) extra = 0
class SubscriptionPart(JuntagricoBaseModel, SimpleStateModel): subscription = models.ForeignKey( 'Subscription', related_name='parts', on_delete=models.CASCADE, verbose_name=Config.vocabulary('subscription')) type = models.ForeignKey('SubscriptionType', related_name='subscription_parts', on_delete=models.PROTECT, verbose_name=_('{0}-Typ').format( Config.vocabulary('subscription'))) @property def can_cancel(self): return self.cancellation_date is None and self.subscription.future_parts.count( ) > 1 def clean(self): check_sub_part_consistency(self) @notifiable class Meta: verbose_name = _('{} Bestandteil').format( Config.vocabulary('subscription')) verbose_name_plural = _('{} Bestandteile').format( Config.vocabulary('subscription'))
def excel_export_subscriptions(request): filename = '{}_{}.xlsx'.format(Config.vocabulary('subscription_pl'), timezone.now().date()) response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') response['Content-Disposition'] = 'attachment; filename=' + filename wb = Workbook() # Sheet 1: Subscriptions with prices ws1 = wb.active ws1.title = Config.vocabulary('subscription_pl') # header ws1.cell(1, 1, u"{}".format(Config.vocabulary('member_pl'))) ws1.column_dimensions['A'].width = 40 ws1.cell(1, 2, u"{}".format(_('E-Mail'))) ws1.column_dimensions['B'].width = 30 ws1.cell(1, 3, u"{}".format(_('Gesamtpreis [{}]').format(Config.currency()))) ws1.column_dimensions['C'].width = 17 for column, subs_type in enumerate(SubscriptionTypeDao.get_all(), 4): ws1.cell(1, column, u"EAT {}".format(subs_type.price)) ws1.column_dimensions[get_column_letter(column)].width = 17 # data for row, subscription in enumerate(SubscriptionDao.all_active_subscritions(), 2): ws1.cell(row, 1, ", ".join([member.get_name() for member in subscription.members.all()])) ws1.cell(row, 2, subscription.primary_member.email) ws1.cell(row, 3, subscription.price) for column, subs_type in enumerate(SubscriptionTypeDao.get_all(), 4): ws1.cell(row, column, subscription.types.filter(id=subs_type.id).count()) ws1.freeze_panes = ws1['A2'] wb.save(response) return response
class SubscriptionMembershipInline(admin.TabularInline): model = SubscriptionMembership form = SubscriptionMembershipAdminForm formset = SubscriptionMembershipInlineFormset fields = ['member', 'join_date', 'leave_date', 'share_count'] readonly_fields = ['share_count'] verbose_name = _('{} Mitgliedschaft').format(Config.vocabulary('subscription')) verbose_name_plural = _('{} Mitgliedschaften').format(Config.vocabulary('subscription')) extra = 0 def share_count(self, instance): return instance.member.usable_shares_count share_count.short_description = Config.vocabulary('share_pl') def get_formset(self, request, obj=None, **kwargs): self.parent_obj = obj return super(SubscriptionMembershipInline, self).get_formset(request, obj, **kwargs) def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == 'member': if self.parent_obj is None: kwargs['queryset'] = MemberDao.members_for_create_subscription() elif self.parent_obj.state == 'waiting': kwargs['queryset'] = MemberDao.members_for_future_subscription(self.parent_obj) elif self.parent_obj.state == 'inactive': kwargs['queryset'] = MemberDao.all_members() else: kwargs['queryset'] = MemberDao.members_for_subscription(self.parent_obj) return super().formfield_for_foreignkey(db_field, request, **kwargs)
class MemberAdminForm(forms.ModelForm): class Meta: model = Member fields = '__all__' def __init__(self, *a, **k): forms.ModelForm.__init__(self, *a, **k) member = k.get('instance') if member is not None: link = self.get_subscription_link(member, member.subscription) self.fields['subscription_link'].initial = link link = self.get_subscription_link(member, member.future_subscription) self.fields['future_subscription_link'].initial = link old_links = [ self.get_subscription_link(member, old_sub) for old_sub in member.old_subscriptions.all() ] self.fields['old_subscription_link'].initial = '<br>'.join( old_links) share_link = [ self.get_share_link(share) for share in member.share_set.all() ] self.fields['share_link'].initial = '<br>'.join(share_link) @staticmethod def get_subscription_link(member, subscription): if member is None: link = '' elif subscription: url = reverse('admin:juntagrico_subscription_change', args=(subscription.id, )) link = '<a href={}>{}</a>'.format(url, subscription) else: link = _('Kein/e/n {0}').format(Config.vocabulary('subscription')) return link @staticmethod def get_share_link(share): link = '' if share: url = reverse('admin:juntagrico_share_change', args=(share.id, )) link = '<a href={}>{}</a>'.format(url, share) return link subscription_link = forms.URLField(widget=MyHTMLWidget(), required=False, label=Config.vocabulary('subscription')) future_subscription_link = forms.URLField( widget=MyHTMLWidget(), required=False, label=_('Zukünftige/r/s {0}').format( Config.vocabulary('subscription'))) old_subscription_link = forms.URLField( widget=MyHTMLWidget(), required=False, label=_('Alte {0}').format(Config.vocabulary('subscription_pl'))) share_link = forms.URLField(widget=MyHTMLWidget(), required=False, label=_(Config.vocabulary('share_pl')))
class SubscriptionTypeInline(admin.TabularInline): formset = SubscriptionTypeInlineFormset model = Subscription.types.through verbose_name = _('{0}-Typ').format(Config.vocabulary('subscription')) verbose_name_plural = _('{0}-Typen').format( Config.vocabulary('subscription')) extra = 0
def clean(self): selected = self.get_selected() # check if members in subscription have sufficient shares if self.subscription.all_shares < sum([ sub_type.shares * amount for sub_type, amount in selected.items() ]): share_error_message = mark_safe( _('Es sind zu wenig {} vorhanden für diese Grösse!{}').format( Config.vocabulary('share_pl'), '<br/><a href="{}" class="alert-link">{}</a>'.format( reverse('share-order'), _('→ Bestelle hier mehr {}').format( Config.vocabulary('share_pl'))))) raise ValidationError(share_error_message, code='share_error') # check that at least one subscription was selected if sum(selected.values()) == 0: amount_error_message = mark_safe( _('Wähle mindestens 1 {} aus.{}').format( Config.vocabulary('subscription'), '<br/><a href="{}" class="alert-link">{}</a>'.format( reverse('sub-cancel', args=[self.subscription.id]), _('→ Oder {} komplett künden').format( Config.vocabulary('subscription'))))) raise ValidationError(amount_error_message, code='amount_error') return super().clean()
class SubscriptionAdmin(BaseAdmin): form = SubscriptionAdminForm readonly_fields = ('creation_date', ) list_display = [ '__str__', 'recipients_names', 'primary_member_nullsave', 'depot', 'active' ] search_fields = [ 'members__user__username', 'members__first_name', 'members__last_name', 'members_future__user__username', 'members_future__first_name', 'members_future__last_name', 'members_old__user__username', 'members_old__first_name', 'members_old__last_name', 'depot__name' ] inlines = [ SubscriptionTypeInline, FutureSubscriptionTypeInline, ExtraSubscriptionInline ] add_inlines = [SubscriptionTypeInline, ExtraSubscriptionInline] fieldsets = [ (Config.vocabulary('member_pl'), { 'fields': ['primary_member', 'subscription_members'] }), (_('Depot'), { 'fields': ['depot', 'future_depot'] }), (_('Status'), { 'fields': [ 'creation_date', 'start_date', 'active', 'activation_date', 'canceled', 'cancelation_date', 'end_date', 'deactivation_date' ] }), (_('Administration'), { 'fields': ['notes'] }), ] add_fieldsets = [ (Config.vocabulary('member_pl'), { 'fields': ['subscription_members'] }), (Config.vocabulary('depot'), { 'fields': ['depot'] }), (_('Status'), { 'fields': ['start_date'] }), (_('Administration'), { 'fields': ['notes'] }), ] def get_fieldsets(self, request, obj=None): if not obj: return self.add_fieldsets return super().get_fieldsets(request, obj) def get_inlines(self, request, obj): if not obj: return self.add_inlines return super().get_inlines(request, obj)
def clean_email(self): email = self.cleaned_data['email'] if email in self.existing_emails: raise ValidationError( mark_safe( _('Diese E-Mail-Adresse wird bereits von dir oder deinen {} verwendet.' ).format(Config.vocabulary('co_member_pl')))) existing_member = MemberDao.member_by_email(email) if existing_member: if existing_member.blocked: raise ValidationError( mark_safe( escape( _('Die Person mit dieser E-Mail-Adresse ist bereits aktiv\ {}-BezierIn. Bitte meldet euch bei {}, wenn ihr bestehende {} als {} hinzufügen möchtet.' )).format( Config.vocabulary('subscription'), '<a href="mailto:{0}">{0}</a>'.format( Config.info_email()), Config.vocabulary('member_type_pl'), Config.vocabulary('co_member_pl')))) else: # store existing member for reevaluation self.existing_member = existing_member return email
class SubscriptionPartInline(admin.TabularInline): formset = SubscriptionPartInlineFormset model = SubscriptionPart verbose_name = _('{} Bestandteil').format( Config.vocabulary('subscription')) verbose_name_plural = _('{} Bestandteile').format( Config.vocabulary('subscription')) extra = 0
class Bill(JuntagricoBaseModel): """ Bill (invoice) class. Consists of several BillItems currently for subscription parts and extrasubscriptions. """ business_year = models.ForeignKey(BusinessYear, related_name='bills', null=False, blank=False, on_delete=models.PROTECT, verbose_name=_('Business Year')) member = models.ForeignKey(Member, related_name='bills', null=False, blank=False, on_delete=models.PROTECT, verbose_name=_('Member')) bill_date = models.DateField( _('Billing date')) booking_date = models.DateField( _('Booking date')) amount = models.FloatField(_('Amount'), null=False, blank=False, default=0.0) paid = models.BooleanField(_('Paid'), null=False, blank=False, default=False) public_notes = models.TextField(_('Notes visible to {}').format(Config.vocabulary('member_pl')), null=True, blank=True) private_notes = models.TextField(_('Notes not visible to {}').format(Config.vocabulary('member_pl')), null=True, blank=True) notification_sent = models.BooleanField(_('Notification sent'), null=False, blank=False, default=False) # derived properties @property def amount_paid(self): return sum([p.amount for p in self.payments.all()]) amount_paid.fget.short_description = _('Amount paid') @property def item_kinds(self): """ List the kind of items on the bill. short description for displaying in lists. """ return ', '.join([itm.item_kind for itm in self.items.all()]) @property def description(self): """ Concatenation of the BillItem descriptions, joined by line breaks. """ return "\n".join([itm.description for itm in self.items.all()]) def __str__(self): return '{}'.format(self.id) class Meta: verbose_name = _('Bill') verbose_name_plural = _('Bills')
def check_sub_consistency(instance): if instance._old['deactivation_date'] is not None and instance.deactivation_date is None: raise ValidationError( _('Deaktivierte {0} koennen nicht wieder aktiviert werden').format(Config.vocabulary('subscription_pl')), code='invalid') pm_waiting = instance.primary_member in instance.recipients_all_for_state('waiting') pm_active = instance.primary_member in instance.recipients_all_for_state('active') pm_form = instance._future_members and instance.primary_member in instance._future_members if instance.primary_member is not None and not (pm_waiting or pm_active or pm_form): raise ValidationError( _('HauptbezieherIn muss auch {}-BezieherIn sein').format(Config.vocabulary('subscription')), code='invalid')
class Meta: verbose_name = _('{0}-Grösse').format( Config.vocabulary('subscription')) verbose_name_plural = _('{0}-Grössen').format( Config.vocabulary('subscription')) unique_together = ( 'name', 'product', ) unique_together = ( 'units', 'product', )
def check_member_consistency(instance): if instance._old['inactive'] != instance.inactive and instance.inactive is True: if instance.is_cooperation_member: raise ValidationError( _('Diese/r/s {} hat mindestens noch ein/e/n aktive/n/s {}').format(Config.vocabulary('member'), Config.vocabulary('share')), code='invalid') if instance.future_subscription is not None and instance.future_subscription.primary_member.pk == instance.pk: raise ValidationError( _('Diese/r/s {} ist noch HauptbezieherIn in einer/m {}').format(Config.vocabulary('member'), Config.vocabulary('subscription')), code='invalid') if instance.subscription is not None and instance.subscription.primary_member.pk == instance.pk: raise ValidationError( _('Diese/r/s {} ist noch HauptbezieherIn in einer/m {}').format(Config.vocabulary('member'), Config.vocabulary('subscription')), code='invalid')
def check_sub_primary(instance): pm_sub = instance.primary_member in instance.recipients pm_form = instance.future_members and instance.primary_member in instance.future_members if instance.primary_member is not None and not (pm_sub or pm_form): raise ValidationError( _('HauptbezieherIn muss auch {}-BezieherIn sein').format( Config.vocabulary('subscription')), code='invalid') if instance.parts.count() > 0 and instance.future_parts.count( ) == 0 and instance.cancellation_date is None: raise ValidationError(_( 'Nicht gekündigte {0} brauchen mindestens einen aktiven oder wartenden {0}-Bestandteil' ).format(Config.vocabulary('subscription')), code='invalid')
def check_sub_membership_consistency_ms(member, subscription, asof): from juntagrico.dao.subscriptionmembershipdao import SubscriptionMembershipDao if subscription.state == 'waiting' and SubscriptionMembershipDao.get_other_waiting_for_member(member, subscription).count() > 0: raise ValidationError( _('Diese/r/s {} hat bereits ein/e/n zukünftige/n/s {}').format(Config.vocabulary('member'), Config.vocabulary('subscription')), code='invalid') if subscription.state == 'active' and SubscriptionMembershipDao.get_other_active_for_member(member, subscription, asof).count() > 0: raise ValidationError( _('Diese/r/s {} hat bereits ein/e/n {}').format(Config.vocabulary('member'), Config.vocabulary('subscription')), code='invalid')
def filter_subscriptions_depot(request, depot_id): depot = get_object_or_404(Depot, id=int(depot_id)) renderdict = get_menu_dict(request) renderdict['can_send_mails'] = True renderdict.update({ 'subscriptions': SubscriptionDao.active_subscritions_by_depot(depot), 'title': _('Alle aktiven {} im {} {}').format( Config.vocabulary('subscription_pl'), Config.vocabulary('depot'), depot.name) }) return render(request, 'subscriptions.html', renderdict)
def check_sub_primary(instance): pm_sub = instance.primary_member in instance.recipients pm_form = instance.future_members and instance.primary_member in instance.future_members if instance.primary_member is not None and not (pm_sub or pm_form): raise ValidationError( _('HauptbezieherIn muss auch {}-BezieherIn sein').format( Config.vocabulary('subscription')), code='invalid') if instance.parts.count() > 0 and instance.future_parts.count( ) == 0 and instance.cancellation_date is None: raise ValidationError(_( 'Nicht gekündigte {0} brauchen mindestens einen aktiven oder wartenden {0}-Bestandteil.' ' Um die Kündigung rückgängig zu machen, leere und speichere zuerst das Kündigungsdatum des Bestandteils und dann jenes vom {0}.' ).format(Config.vocabulary('subscription')), code='invalid')
class MemberAdminForm(forms.ModelForm): class Meta: model = Member fields = '__all__' def __init__(self, *a, **k): forms.ModelForm.__init__(self, *a, **k) member = k.get('instance') if member is None: link = '' elif member.subscription: url = reverse('admin:juntagrico_subscription_change', args=(member.subscription.id, )) link = '<a href=%s>%s</a>' % (url, member.subscription) else: link = _('Kein/e/n {0}').format(Config.vocabulary('subscription')) self.fields['subscription_link'].initial = link if member is None: link = '' elif member.future_subscription: url = reverse('admin:juntagrico_subscription_change', args=(member.future_subscription.id, )) link = '<a href=%s>%s</a>' % (url, member.future_subscription) else: link = _('Kein/e/n {0}').format(Config.vocabulary('subscription')) self.fields['future_subscription_link'].initial = link subscription_link = forms.URLField(widget=MyHTMLWidget(), required=False, label='Abo') future_subscription_link = forms.URLField( widget=MyHTMLWidget(), required=False, label=_('Zukünftige/r/s {0}').format( Config.vocabulary('subscription')))
class Assignment(JuntagricoBaseModel): ''' Single assignment (work unit). ''' job = models.ForeignKey(Job, on_delete=models.PROTECT) member = models.ForeignKey('Member', on_delete=models.PROTECT, verbose_name=Config.vocabulary('member')) core_cache = models.BooleanField(_('Kernbereich'), default=False) job_extras = models.ManyToManyField(JobExtra, related_name='assignments', blank=True, verbose_name=_('Job Extras')) amount = models.FloatField(_('Wert')) def __str__(self): return '%s #%s' % (Config.vocabulary('assignment'), self.id) def time(self): return self.job.time time.admin_order_field = 'job__time' def is_core(self): return self.job.type.activityarea.core @classmethod def pre_save(cls, sender, instance, **kwargs): instance.core_cache = instance.is_core() class Meta: verbose_name = Config.vocabulary('assignment') verbose_name_plural = Config.vocabulary('assignment_pl')
class Delivery(JuntagricoBaseModel): """ Delivery with a specific date (usually Tuesday or Thursday) """ delivery_date = models.DateField(_('Lieferdatum')) subscription_size = models.ForeignKey( SubscriptionSize, verbose_name=_('{0}-Grösse').format(Config.vocabulary('subscription')), on_delete=models.PROTECT) def __str__(self): return u"%s - %s" % (self.delivery_date, self.subscription_size.long_name) def weekday(self): return self.delivery_date.isoweekday() def weekday_shortname(self): day = self.delivery_date.isoweekday() return weekday_short(day, 2) class Meta: verbose_name = _('Lieferung') verbose_name_plural = _('Lieferungen') unique_together = ("delivery_date", "subscription_size")
def size_change(request, subscription_id): """ change the size of a subscription """ subscription = get_object_or_404(Subscription, id=subscription_id) parts_order_allowed = subscription.waiting or subscription.active if request.method == 'POST': if not parts_order_allowed: raise ValidationError( _('Für gekündigte {} können keine Bestandteile bestellt werden' ).format(Config.vocabulary('subscription_pl')), code='invalid') form = SubscriptionPartOrderForm(subscription, request.POST) if form.is_valid(): create_subscription_parts(subscription, form.get_selected()) return return_to_previous_location(request) else: form = SubscriptionPartOrderForm() renderdict = get_menu_dict(request) renderdict.update({ 'form': form, 'subscription': subscription, 'hours_used': Config.assignment_unit() == 'HOURS', 'next_cancel_date': temporal.next_cancelation_date(), 'parts_order_allowed': parts_order_allowed, }) return render(request, 'size_change.html', renderdict)
def simple_get_size_name(types=[]): size_dict = [] for type in types.all(): size_dict.append(type.size.name + " " + type.size.product.name) if len(size_dict) > 0: return '<br>'.join(size_dict) return _('kein/e/n {0}').format(Config.vocabulary('subscription'))
def size_change(request, subscription_id): """ Overriden from core change the size of a subscription """ subscription = get_object_or_404(Subscription, id=subscription_id) parts_order_allowed = subscription.waiting or subscription.active if request.method == 'POST' and int(timezone.now().strftime( "%m")) <= Config.business_year_cancelation_month(): if not parts_order_allowed: raise ValidationError( _('Für gekündigte {} können keine Bestandteile bestellt werden' ).format(Config.vocabulary('subscription_pl')), code='invalid') form = SubscriptionPartOrderForm(subscription, request.POST) if form.is_valid(): selected = form.get_selected() err_msg = quantity_error(selected, subscription.active_and_future_parts) if not err_msg: create_subscription_parts(subscription, selected) return redirect("content_edit", subscription_id=subscription_id) else: form.add_error(None, err_msg) else: form = SubscriptionPartOrderForm() renderdict = { 'form': form, 'subscription': subscription, 'hours_used': Config.assignment_unit() == 'HOURS', 'next_cancel_date': temporal.next_cancelation_date(), 'parts_order_allowed': parts_order_allowed, } return render(request, 'size_change.html', renderdict)
class Share(Billable): member = models.ForeignKey('Member', blank=True, on_delete=models.PROTECT) creation_date = models.DateField(_('Erzeugt am'), null=True, blank=True, default=timezone.now) paid_date = models.DateField(_('Bezahlt am'), null=True, blank=True) issue_date = models.DateField(_('Ausgestellt am'), null=True, blank=True) booking_date = models.DateField(_('Eingebucht am'), null=True, blank=True) cancelled_date = models.DateField(_('Gekündigt am'), null=True, blank=True) termination_date = models.DateField(_('Gekündigt auf'), null=True, blank=True) payback_date = models.DateField(_('Zurückbezahlt am'), null=True, blank=True) number = models.IntegerField(_('Anteilschein Nummer'), null=True, blank=True) sent_back = models.BooleanField(_('Zurückgesandt'), default=False) notes = models.TextField( _('Notizen'), max_length=1000, default='', blank=True, help_text=_('Notizen für Administration. Nicht sichtbar für {}'.format( Config.vocabulary('member')))) __state_text_dict = { 0: _('unbezahlt'), 1: _('bezahlt'), 3: _('gekündigt'), 7: _('zurückerstattet') } @property def state_text(self): now = timezone.now().date() paid = (self.paid_date is not None and self.paid_date <= now) << 0 cancelled = (self.cancelled_date is not None and self.cancelled_date <= now) << 1 paid_back = (self.payback_date is not None and self.payback_date <= now) << 2 state_code = paid + cancelled + paid_back return Share.__state_text_dict.get(state_code, _('Fehler!')) @property def identifier(self): return self.number if self.number is not None else self.pk def clean(self): check_share_consistency(self) def __str__(self): return _('Anteilschein {0}').format(self.id) @notifiable class Meta: verbose_name = Config.vocabulary('share') verbose_name_plural = Config.vocabulary('share_pl')
def extra_change(request, subscription_id): ''' change an extra subscription ''' subscription = get_object_or_404(Subscription, id=subscription_id) extra_order_allowed = subscription.waiting or subscription.active if request.method == 'POST': if not extra_order_allowed: raise ValidationError( _('Für gekündigte {} können keine Zusatzabos bestellt werden' ).format(Config.vocabulary('subscription_pl')), code='invalid') for type in ExtraSubscriptionTypeDao.all_visible_extra_types(): value = int(request.POST.get('extra' + str(type.id))) if value > 0: for x in range(value): ExtraSubscription.objects.create( main_subscription=subscription, type=type) return redirect('extra-change', subscription_id=subscription.id) renderdict = get_menu_dict(request) renderdict.update({ 'types': ExtraSubscriptionTypeDao.all_visible_extra_types(), 'extras': subscription.extra_subscription_set.all(), 'sub_id': subscription_id, 'extra_order_allowed': extra_order_allowed, }) return render(request, 'extra_change.html', renderdict)
class MemberAdmin(admin.ModelAdmin): form = MemberAdminForm list_display = ['email', 'first_name', 'last_name'] search_fields = ['first_name', 'last_name', 'email'] # raw_id_fields = ['subscription'] exclude = ['future_subscription', 'subscription', 'old_subscriptions'] readonly_fields = ['user'] actions = ['impersonate_job'] inlines = [] def __init__(self, *args, **kwargs): self.inlines.extend(get_member_inlines()) super(MemberAdmin, self).__init__(*args, **kwargs) def impersonate_job(self, request, queryset): if queryset.count() != 1: self.message_user(request, 'Genau 1 ' + Config.vocabulary('member') + ' auswählen!', level=messages.ERROR) return HttpResponseRedirect('') inst, = queryset.all() return HttpResponseRedirect('/impersonate/%s/' % inst.user.id) impersonate_job.short_description = Config.vocabulary( 'member') + ' imitieren (impersonate)...'
def mass_edit_share_dates(self, request, queryset): if 'apply' in request.POST: form = EditShareDatesForm(request.POST) if form.is_valid(): target_field = form.cleaned_data['target_field'] date = form.cleaned_data['date'] overwrite = form.cleaned_data['overwrite'] input_count = queryset.count() if not overwrite: queryset = queryset.filter(**{target_field: None}) filter_count = queryset.count() # add note before setting date as queryset may be empty afterward due to applied filters additional_note = form.cleaned_data['note'] if additional_note: for share in queryset: share.notes += ('\n' if share.notes else '') + additional_note share.save() # update dates queryset.update(**{target_field: date}) self.message_user( request, _('{} von {} {} bearbeitet').format( filter_count, input_count, Config.vocabulary('share_pl'))) return HttpResponseRedirect(request.get_full_path()) else: form = EditShareDatesForm() return render(request, 'admin/mass_edit_share_dates_intermediate.html', context={ 'shares': queryset, 'form': form, })
def check_sub_reactivation(instance): if instance._old[ 'deactivation_date'] is not None and instance.deactivation_date is None: raise ValidationError( _('Deaktivierte {0} können nicht wieder aktiviert werden').format( Config.vocabulary('subscription_pl')), code='invalid')
def member_canceled(member, end_date, message): EmailSender.get_sender(organisation_subject( _('{} gekündigt').format(Config.vocabulary('member_type'))), get_email_content('m_canceled', base_dict(locals())), bcc=get_emails_by_permission( 'notified_on_member_cancellation')).send()