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
示例#2
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
示例#4
0
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)
示例#5
0
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
示例#7
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'),
                     _('&rarr; 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]),
                     _('&rarr; 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)
示例#9
0
 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
示例#10
0
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
示例#11
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')
示例#12
0
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')
示例#13
0
 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',
     )
示例#14
0
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')
示例#15
0
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')
示例#16
0
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')
示例#17
0
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)
示例#18
0
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')))
示例#20
0
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')
示例#21
0
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")
示例#22
0
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)
示例#23
0
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'))
示例#24
0
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)
示例#25
0
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')
示例#26
0
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)
示例#27
0
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)...'
示例#28
0
    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,
                      })
示例#29
0
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')
示例#30
0
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()