Ejemplo n.º 1
0
 def mutate(cls, root, info, id, input):
     restock = input.get('restock')
     fulfillment = get_node(info, id, only_type=Fulfillment)
     order = fulfillment.order
     errors = []
     if not fulfillment.can_edit():
         errors.append(
             Error(
                 field='fulfillment',
                 message=pgettext_lazy(
                     'Cancel fulfillment mutation error',
                     'This fulfillment can\'t be canceled')))
     if errors:
         return cls(errors=errors)
     cancel_fulfillment(fulfillment, restock)
     if restock:
         msg = npgettext_lazy(
             'Dashboard message',
             'Restocked %(quantity)d item',
             'Restocked %(quantity)d items',
             'quantity') % {'quantity': fulfillment.get_total_quantity()}
     else:
         msg = pgettext_lazy(
             'Dashboard message',
             'Fulfillment #%(fulfillment)s canceled') % {
                 'fulfillment': fulfillment.composed_id}
     order.history.create(content=msg, user=info.context.user)
     return FulfillmentCancel(fulfillment=fulfillment)
Ejemplo n.º 2
0
    def mutate(cls, root, info, id, input):
        errors = []
        restock = input.get('restock')
        fulfillment = cls.get_node_or_error(info, id, errors, 'id',
                                            Fulfillment)
        if fulfillment:
            order = fulfillment.order
            if not fulfillment.can_edit():
                err_msg = pgettext_lazy('Cancel fulfillment mutation error',
                                        'This fulfillment can\'t be canceled')
                cls.add_error(errors, 'fulfillment', err_msg)

        if errors:
            return cls(errors=errors)

        cancel_fulfillment(fulfillment, restock)
        if restock:
            msg = npgettext_lazy(
                'Dashboard message', 'Restocked %(quantity)d item',
                'Restocked %(quantity)d items', 'quantity') % {
                    'quantity': fulfillment.get_total_quantity()
                }
        else:
            msg = pgettext_lazy('Dashboard message',
                                'Fulfillment #%(fulfillment)s canceled') % {
                                    'fulfillment': fulfillment.composed_id
                                }
        order.history.create(content=msg, user=info.context.user)
        return FulfillmentCancel(fulfillment=fulfillment)
Ejemplo n.º 3
0
 def action_present(count):
     return npgettext_lazy(
         "Action to perform (the instance is currently running)",
         u"Shut Off Instance",
         u"Shut Off Instances",
         count
     )
Ejemplo n.º 4
0
def cancel_fulfillment(request, order_pk, fulfillment_pk):
    orders = Order.objects.confirmed().prefetch_related('fulfillments')
    order = get_object_or_404(orders, pk=order_pk)
    fulfillment = get_object_or_404(order.fulfillments, pk=fulfillment_pk)
    status = 200
    form = CancelFulfillmentForm(request.POST or None, fulfillment=fulfillment)
    if form.is_valid():
        msg = pgettext_lazy(
            'Dashboard message', 'Fulfillment #%(fulfillment)s canceled') % {
                'fulfillment': fulfillment.composed_id}
        with transaction.atomic():
            form.cancel_fulfillment()
            if form.cleaned_data.get('restock'):
                restock_msg = npgettext_lazy(
                    'Dashboard message',
                    'Restocked %(quantity)d item',
                    'Restocked %(quantity)d items',
                    'quantity') % {
                        'quantity': fulfillment.get_total_quantity()}
                order.history.create(content=restock_msg, user=request.user)
            order.history.create(content=msg, user=request.user)
        messages.success(request, msg)
        return redirect('dashboard:order-details', order_pk=order.pk)
    elif form.errors:
        status = 400
    ctx = {'form': form, 'order': order, 'fulfillment': fulfillment}
    return TemplateResponse(
        request, 'dashboard/order/modal/cancel_fulfillment.html', ctx,
        status=status)
Ejemplo n.º 5
0
 def action_past(count):
     return npgettext_lazy(
         "Past action (the instance is currently already Shut Off)",
         u"Shut Off Instance",
         u"Shut Off Instances",
         count
     )
Ejemplo n.º 6
0
 def action_present(count):
     return npgettext_lazy(
         "Action to perform (the volume is currently attached)",
         u"Detach Volume",
         u"Detach Volumes",
         count
     )
Ejemplo n.º 7
0
 def action_past(count):
     return npgettext_lazy(
         "Past action (the volume is currently being detached)",
         u"Detaching Volume",
         u"Detaching Volumes",
         count
     )
Ejemplo n.º 8
0
 def action_present(count):
     return npgettext_lazy(
         "Action to perform (the instance is currently running)",
         u"Shut Off Instance",
         u"Shut Off Instances",
         count
     )
Ejemplo n.º 9
0
def cancel_order(request, order_pk):
    order = get_object_or_404(Order.objects.confirmed(), pk=order_pk)
    status = 200
    form = CancelOrderForm(request.POST or None, order=order)
    if form.is_valid():
        msg = pgettext_lazy('Dashboard message', 'Order canceled')
        with transaction.atomic():
            form.cancel_order()
            if form.cleaned_data.get('restock'):
                restock_msg = npgettext_lazy(
                    'Dashboard message',
                    'Restocked %(quantity)d item',
                    'Restocked %(quantity)d items',
                    'quantity') % {'quantity': order.get_total_quantity()}
                order.history.create(content=restock_msg, user=request.user)
            order.history.create(content=msg, user=request.user)
        messages.success(request, msg)
        return redirect('dashboard:order-details', order_pk=order.pk)
        # TODO: send status confirmation email
    elif form.errors:
        status = 400
    ctx = {'form': form, 'order': order}
    return TemplateResponse(
        request, 'dashboard/order/modal/cancel_order.html', ctx,
        status=status)
Ejemplo n.º 10
0
 def action_past(count):
     return npgettext_lazy(
         "Past action (the volume is currently being detached)",
         "Detaching Volume",
         "Detaching Volumes",
         count
     )
Ejemplo n.º 11
0
 def mutate(cls, root, info, id, input):
     restock = input.get('restock')
     fulfillment = get_node(info, id, only_type=Fulfillment)
     order = fulfillment.order
     errors = []
     if not fulfillment.can_edit():
         errors.append(
             Error(field='fulfillment',
                   message=pgettext_lazy(
                       'Cancel fulfillment mutation error',
                       'This fulfillment can\'t be canceled')))
     if errors:
         return cls(errors=errors)
     cancel_fulfillment(fulfillment, restock)
     if restock:
         msg = npgettext_lazy(
             'Dashboard message', 'Restocked %(quantity)d item',
             'Restocked %(quantity)d items', 'quantity') % {
                 'quantity': fulfillment.get_total_quantity()
             }
     else:
         msg = pgettext_lazy('Dashboard message',
                             'Fulfillment #%(fulfillment)s canceled') % {
                                 'fulfillment': fulfillment.composed_id
                             }
     order.history.create(content=msg, user=info.context.user)
     return FulfillmentCancel(fulfillment=fulfillment)
Ejemplo n.º 12
0
 def action_present(count):
     return npgettext_lazy(
         "Action to perform (the volume is currently attached)",
         "Detach Volume",
         "Detach Volumes",
         count
     )
Ejemplo n.º 13
0
def customer_list(request):
    customers = (
        User.objects
        .prefetch_related('orders', 'addresses')
        .select_related('default_billing_address', 'default_shipping_address')
        .annotate(
            num_orders=Count('orders', distinct=True),
            last_order=Max('orders', distinct=True)))

    form = CustomerSearchForm(request.GET or None, queryset=customers)
    form_values = [(field.name, field.value() or '') for field in form]
    if form.is_valid():
        customers = form.search()
    else:
        customers = customers.filter(
            orders__status__in=[
                OrderStatus.NEW, OrderStatus.PAYMENT_PENDING,
                OrderStatus.FULLY_PAID])
    title = npgettext_lazy(
        'Customer list page title',
        '%d result',
        'Results (%d)') % len(customers)

    customers = get_paginator_items(customers, 30, request.GET.get('page'))
    ctx = {'customers': customers, 'form': form, 'title': title,
           'default_pagination_params': form_values}
    return TemplateResponse(request, 'dashboard/customer/list.html', ctx)
Ejemplo n.º 14
0
def cancel_fulfillment(request, order_pk, fulfillment_pk):
    status = 200
    order = get_object_or_404(Order, pk=order_pk)
    fulfillment = get_object_or_404(order.fulfillments.all(),
                                    pk=fulfillment_pk)
    form = CancelFulfillmentForm(request.POST or None, fulfillment=fulfillment)
    if form.is_valid():
        msg = pgettext_lazy('Dashboard message',
                            'Fulfillment #%(fulfillment)s canceled') % {
                                'fulfillment': fulfillment.composed_id
                            }
        with transaction.atomic():
            form.cancel_fulfillment()
            if form.cleaned_data.get('restock'):
                restock_msg = npgettext_lazy(
                    'Dashboard message', 'Restocked %(quantity)d item',
                    'Restocked %(quantity)d items', 'quantity') % {
                        'quantity': fulfillment.get_total_quantity()
                    }
                order.history.create(content=restock_msg, user=request.user)
            order.history.create(content=msg, user=request.user)
        messages.success(request, msg)
        return redirect('dashboard:order-details', order_pk=order.pk)
    elif form.errors:
        status = 400
    ctx = {'form': form, 'order': order, 'fulfillment': fulfillment}
    return TemplateResponse(request,
                            'dashboard/order/modal/cancel_fulfillment.html',
                            ctx,
                            status=status)
Ejemplo n.º 15
0
def cancel_order(request, order_pk):
    status = 200
    order = get_object_or_404(Order, pk=order_pk)
    form = CancelOrderForm(request.POST or None, order=order)
    if form.is_valid():
        msg = pgettext_lazy('Dashboard message', 'Order canceled')
        with transaction.atomic():
            form.cancel_order()
            if form.cleaned_data.get('restock'):
                restock_msg = npgettext_lazy(
                    'Dashboard message', 'Restocked %(quantity)d item',
                    'Restocked %(quantity)d items', 'quantity') % {
                        'quantity': order.get_total_quantity()
                    }
                order.history.create(content=restock_msg, user=request.user)
            order.history.create(content=msg, user=request.user)
        messages.success(request, msg)
        return redirect('dashboard:order-details', order_pk=order.pk)
        # TODO: send status confirmation email
    elif form.errors:
        status = 400
    ctx = {'form': form, 'order': order}
    return TemplateResponse(request,
                            'dashboard/order/modal/cancel_order.html',
                            ctx,
                            status=status)
Ejemplo n.º 16
0
 def action_past(count):
     return npgettext_lazy(
         "Past action (the instance is currently already Shut Off)",
         u"Shut Off Instance",
         u"Shut Off Instances",
         count
     )
Ejemplo n.º 17
0
def fulfill_order_lines(request, order_pk):
    orders = Order.objects.confirmed().prefetch_related('lines')
    order = get_object_or_404(orders, pk=order_pk)
    unfulfilled_lines = order.lines.filter(
        quantity_fulfilled__lt=F('quantity'))
    status = 200
    form = FulfillmentForm(
        request.POST or None, order=order, instance=Fulfillment())
    FulfillmentLineFormSet = modelformset_factory(
        FulfillmentLine, form=FulfillmentLineForm,
        extra=len(unfulfilled_lines), formset=BaseFulfillmentLineFormSet)
    initial = [
        {'order_line': line, 'quantity': line.quantity_unfulfilled}
        for line in unfulfilled_lines]
    formset = FulfillmentLineFormSet(
        request.POST or None, queryset=FulfillmentLine.objects.none(),
        initial=initial)
    all_forms_valid = all([line_form.is_valid() for line_form in formset])
    if all_forms_valid and form.is_valid():
        forms_to_save = [
            line_form for line_form in formset
            if line_form.cleaned_data.get('quantity') > 0]
        if forms_to_save:
            fulfillment = form.save()
            quantity_fulfilled = 0
            for line_form in forms_to_save:
                line = line_form.save(commit=False)
                line.fulfillment = fulfillment
                line.save()
                quantity_fulfilled += line_form.cleaned_data.get('quantity')
            # update to refresh prefetched lines quantity_fulfilled
            order = orders.get(pk=order_pk)
            update_order_status(order)
            msg = npgettext_lazy(
                'Dashboard message related to an order',
                'Fulfilled %(quantity_fulfilled)d item',
                'Fulfilled %(quantity_fulfilled)d items',
                'quantity_fulfilled') % {
                    'quantity_fulfilled': quantity_fulfilled}
            order.history.create(content=msg, user=request.user)
            if form.cleaned_data.get('send_mail'):
                send_fulfillment_confirmation.delay(order.pk, fulfillment.pk)
                send_mail_msg = pgettext_lazy(
                    'Dashboard message related to an order',
                    'Shipping confirmation email was sent to user'
                    '(%(email)s)') % {'email': order.get_user_current_email()}
                order.history.create(content=send_mail_msg, user=request.user)
        else:
            msg = pgettext_lazy(
                'Dashboard message related to an order', 'No items fulfilled')
        messages.success(request, msg)
        return redirect('dashboard:order-details', order_pk=order.pk)
    elif form.errors:
        status = 400
    ctx = {
        'form': form, 'formset': formset, 'order': order,
        'unfulfilled_lines': unfulfilled_lines}
    template = 'dashboard/order/fulfillment.html'
    return TemplateResponse(request, template, ctx, status=status)
Ejemplo n.º 18
0
def fulfill_order_lines(request, order_pk):
    orders = Order.objects.confirmed().prefetch_related('lines')
    order = get_object_or_404(orders, pk=order_pk)
    unfulfilled_lines = order.lines.filter(
        quantity_fulfilled__lt=F('quantity'))
    status = 200
    form = FulfillmentForm(
        request.POST or None, order=order, instance=Fulfillment())
    FulfillmentLineFormSet = modelformset_factory(
        FulfillmentLine, form=FulfillmentLineForm,
        extra=len(unfulfilled_lines), formset=BaseFulfillmentLineFormSet)
    initial = [
        {'order_line': line, 'quantity': line.quantity_unfulfilled}
        for line in unfulfilled_lines]
    formset = FulfillmentLineFormSet(
        request.POST or None, queryset=FulfillmentLine.objects.none(),
        initial=initial)
    all_forms_valid = all([line_form.is_valid() for line_form in formset])
    if all_forms_valid and form.is_valid():
        forms_to_save = [
            line_form for line_form in formset
            if line_form.cleaned_data.get('quantity') > 0]
        if forms_to_save:
            fulfillment = form.save()
            quantity_fulfilled = 0
            for line_form in forms_to_save:
                line = line_form.save(commit=False)
                line.fulfillment = fulfillment
                line.save()
                quantity_fulfilled += line_form.cleaned_data.get('quantity')
            # update to refresh prefetched lines quantity_fulfilled
            order = orders.get(pk=order_pk)
            update_order_status(order)
            msg = npgettext_lazy(
                'Dashboard message related to an order',
                'Fulfilled %(quantity_fulfilled)d item',
                'Fulfilled %(quantity_fulfilled)d items',
                'quantity_fulfilled') % {
                    'quantity_fulfilled': quantity_fulfilled}
            order.history.create(content=msg, user=request.user)
            if form.cleaned_data.get('send_mail'):
                send_fulfillment_confirmation.delay(order.pk, fulfillment.pk)
                send_mail_msg = pgettext_lazy(
                    'Dashboard message related to an order',
                    'Shipping confirmation email was sent to user'
                    '(%(email)s)') % {'email': order.get_user_current_email()}
                order.history.create(content=send_mail_msg, user=request.user)
        else:
            msg = pgettext_lazy(
                'Dashboard message related to an order', 'No items fulfilled')
        messages.success(request, msg)
        return redirect('dashboard:order-details', order_pk=order.pk)
    elif form.errors:
        status = 400
    ctx = {
        'form': form, 'formset': formset, 'order': order,
        'unfulfilled_lines': unfulfilled_lines}
    template = 'dashboard/order/fulfillment.html'
    return TemplateResponse(request, template, ctx, status=status)
Ejemplo n.º 19
0
 def __init__(self, *args, **kwargs):
     self.order = kwargs.pop('order')
     super().__init__(*args, **kwargs)
     self.fields['restock'].label = npgettext_lazy(
         'Cancel order form action',
         'Restock %(quantity)d item',
         'Restock %(quantity)d items',
         number='quantity') % {'quantity': self.order.get_total_quantity()}
Ejemplo n.º 20
0
 def __init__(self, *args, **kwargs):
     self.fulfillment = kwargs.pop('fulfillment')
     super().__init__(*args, **kwargs)
     self.fields['restock'].label = npgettext_lazy(
         'Cancel fulfillment form action',
         'Restock %(quantity)d item',
         'Restock %(quantity)d items',
         'quantity') % {'quantity': self.fulfillment.get_total_quantity()}
Ejemplo n.º 21
0
 def __init__(self, *args, **kwargs):
     self.order = kwargs.pop('order')
     super().__init__(*args, **kwargs)
     self.fields['restock'].label = npgettext_lazy(
         'Cancel order form action',
         'Restock %(quantity)d item',
         'Restock %(quantity)d items',
         number='quantity') % {'quantity': self.order.get_total_quantity()}
Ejemplo n.º 22
0
 def __init__(self, *args, **kwargs):
     self.task = kwargs.pop('task')
     super().__init__(*args, **kwargs)
     self.fields['reavail'].label = npgettext_lazy(
         'Cancel task form action',
         'Reavail %(quantity)d item',
         'Reavail %(quantity)d items',
         number='quantity') % {'quantity': self.task.get_total_quantity()}
Ejemplo n.º 23
0
 def __init__(self, *args, **kwargs):
     self.fulfillment = kwargs.pop("fulfillment")
     super().__init__(*args, **kwargs)
     self.fields["restock"].label = npgettext_lazy(
         "Cancel fulfillment form action",
         "Restock %(quantity)d item",
         "Restock %(quantity)d items",
         number="quantity",
     ) % {"quantity": self.fulfillment.get_total_quantity()}
Ejemplo n.º 24
0
 def __init__(self, *args, **kwargs):
     self.fulfillment = kwargs.pop("fulfillment")
     super().__init__(*args, **kwargs)
     self.fields["restock"].label = npgettext_lazy(
         "Cancel fulfillment form action",
         "Restock %(quantity)d item",
         "Restock %(quantity)d items",
         number="quantity",
     ) % {"quantity": self.fulfillment.get_total_quantity()}
 def clean_lines(cls, order_lines, quantities):
     for order_line, quantity in zip(order_lines, quantities):
         if quantity > order_line.quantity_unfulfilled:
             msg = npgettext_lazy(
                 'Fulfill order line mutation error',
                 'Only %(quantity)d item remaining to fulfill: %(order_line)s.',
                 'Only %(quantity)d items remaining to fulfill: %(order_line)s.',
                 number='quantity') % {
                     'quantity': order_line.quantity_unfulfilled,
                     'order_line': order_line}
             raise ValidationError({'order_line_id': msg})
Ejemplo n.º 26
0
 def clean_quantity(self):
     quantity = self.cleaned_data.get('quantity')
     task_line = self.cleaned_data.get('task_line')
     if quantity > task_line.quantity_unfulfilled:
         raise forms.ValidationError(npgettext_lazy(
             'Fulfill task line form error',
             '%(quantity)d item remaining to fulfill.',
             '%(quantity)d items remaining to fulfill.',
             number='quantity') % {
                 'quantity': task_line.quantity_unfulfilled,
                 'task_line': task_line})
     return quantity
Ejemplo n.º 27
0
def product_bulk_update(request):
    form = forms.ProductBulkUpdate(request.POST)
    if form.is_valid():
        form.save()
        count = len(form.cleaned_data['products'])
        msg = npgettext_lazy(
            'Dashboard message',
            '%(count)d product has been updated',
            '%(count)d products have been updated',
            number='count') % {'count': count}
        messages.success(request, msg)
    return redirect('dashboard:product-list')
Ejemplo n.º 28
0
 def clean_quantity(self):
     quantity = self.cleaned_data.get('quantity')
     order_line = self.cleaned_data.get('order_line')
     if quantity > order_line.quantity_unfulfilled:
         raise forms.ValidationError(npgettext_lazy(
             'Fulfill order line form error',
             '%(quantity)d item remaining to fulfill.',
             '%(quantity)d items remaining to fulfill.',
             'quantity') % {
                 'quantity': order_line.quantity_unfulfilled,
                 'order_line': order_line})
     return quantity
Ejemplo n.º 29
0
def product_bulk_update(request):
    form = forms.ProductBulkUpdate(request.POST)
    if form.is_valid():
        form.save()
        count = len(form.cleaned_data['products'])
        msg = npgettext_lazy(
            'Dashboard message',
            '%(count)d product has been updated',
            '%(count)d products have been updated',
            number='count') % {'count': count}
        messages.success(request, msg)
    return redirect('dashboard:product-list')
Ejemplo n.º 30
0
def clean_lines_quantities(order_lines, quantities):
    errors = []
    for order_line, quantity in zip(order_lines, quantities):
        if quantity > order_line.quantity_unfulfilled:
            msg = npgettext_lazy(
                'Fulfill order line mutation error',
                '%(quantity)d item remaining to fulfill.',
                '%(quantity)d items remaining to fulfill.',
                'quantity') % {
                    'quantity': order_line.quantity_unfulfilled,
                    'order_line': order_line}
            errors.append((order_line.variant.name, msg))
    return errors
Ejemplo n.º 31
0
 def clean_quantity(self):
     quantity = self.cleaned_data['quantity']
     delta = quantity - self.initial_quantity
     try:
         self.variant.check_quantity(delta)
     except InsufficientStock as e:
         raise forms.ValidationError(
             npgettext_lazy(
                 'Change quantity form error',
                 'Only %(remaining)d remaining in stock.',
                 'Only %(remaining)d remaining in stock.',
                 'remaining') % {'remaining': e.item.get_stock_quantity()})
     return quantity
Ejemplo n.º 32
0
 def clean_quantity(self):
     quantity = self.cleaned_data['quantity']
     delta = quantity - self.initial_quantity
     try:
         self.variant.check_quantity(delta)
     except InsufficientStock as e:
         raise forms.ValidationError(
             npgettext_lazy('Change quantity form error',
                            'Only %(remaining)d remaining in stock.',
                            'Only %(remaining)d remaining in stock.',
                            'remaining') %
             {'remaining': e.item.get_stock_quantity()})
     return quantity
Ejemplo n.º 33
0
 def clean_quantity(self):
     quantity = self.cleaned_data['quantity']
     delta = quantity - self.initial_quantity
     stock = self.instance.stock
     if stock and delta > stock.quantity_available:
         raise forms.ValidationError(
             npgettext_lazy(
                 'Change quantity form error',
                 'Only %(remaining)d remaining in stock.',
                 'Only %(remaining)d remaining in stock.',
                 'remaining') % {'remaining': (
                     self.initial_quantity + stock.quantity_available)})
     return quantity
Ejemplo n.º 34
0
def clean_lines_quantities(order_lines, quantities):
    errors = []
    for order_line, quantity in zip(order_lines, quantities):
        if quantity > order_line.quantity_unfulfilled:
            msg = npgettext_lazy(
                'Fulfill order line mutation error',
                '%(quantity)d item remaining to fulfill.',
                '%(quantity)d items remaining to fulfill.', 'quantity') % {
                    'quantity': order_line.quantity_unfulfilled,
                    'order_line': order_line
                }
            errors.append((order_line.variant.name, msg))
    return errors
Ejemplo n.º 35
0
 def clean_lines(cls, order_lines, quantities):
     for order_line, quantity in zip(order_lines, quantities):
         if quantity > order_line.quantity_unfulfilled:
             msg = npgettext_lazy(
                 "Fulfill order line mutation error",
                 "Only %(quantity)d item remaining to fulfill: %(order_line)s.",
                 "Only %(quantity)d items remaining to fulfill: %(order_line)s.",
                 number="quantity",
             ) % {
                 "quantity": order_line.quantity_unfulfilled,
                 "order_line": order_line,
             }
             raise ValidationError({"order_line_id": msg})
Ejemplo n.º 36
0
def product_bulk_update(request):
    form = forms.ProductBulkUpdate(request.POST)
    if form.is_valid():
        form.save()
        count = len(form.cleaned_data["products"])
        msg = npgettext_lazy(
            "Dashboard message",
            "%(count)d product has been updated",
            "%(count)d products have been updated",
            number="count",
        ) % {"count": count}
        messages.success(request, msg)
    return redirect("dashboard:product-list")
Ejemplo n.º 37
0
 def clean_quantity(self):
     quantity = self.cleaned_data['quantity']
     delta = quantity - self.initial_quantity
     variant = self.instance.variant
     if variant and delta > variant.quantity_available:
         raise forms.ValidationError(
             npgettext_lazy(
                 'Change quantity form error',
                 'Only %(remaining)d remaining in stock.',
                 'Only %(remaining)d remaining in stock.',
                 'remaining') % {
                     'remaining': (
                         self.initial_quantity + variant.quantity_available)})  # noqa
     return quantity
Ejemplo n.º 38
0
 def test_second_before_equal_first_humanize_time_strings(self):
     time_strings = {
         'minute':
         npgettext_lazy('naturaltime-future', '%d minute', '%d minutes'),
     }
     with translation.override('cs'):
         for now in [
                 self.t, self.t - self.onemicrosecond, self.t - self.oneday
         ]:
             with self.subTest(now):
                 self.assertEqual(
                     timesince(self.t, now, time_strings=time_strings),
                     '0\xa0minut',
                 )
Ejemplo n.º 39
0
 def clean_quantity(self):
     quantity = self.cleaned_data['quantity']
     delta = quantity - self.initial_quantity
     variant = self.instance.variant
     if variant and delta > variant.quantity_available:
         raise forms.ValidationError(
             npgettext_lazy(
                 'Change quantity form error',
                 'Only %(remaining)d remaining in availability.',
                 'Only %(remaining)d remaining in availability.',
                 number='remaining') % {
                     'remaining': (
                         self.initial_quantity + variant.quantity_available)})  # noqa
     return quantity
Ejemplo n.º 40
0
 def clean_quantity(self):
     quantity = self.cleaned_data["quantity"]
     delta = quantity - self.initial_quantity
     variant = self.instance.variant
     if variant and delta > variant.quantity_available:
         raise forms.ValidationError(
             npgettext_lazy(
                 "Change quantity form error",
                 "Only %(remaining)d remaining in stock.",
                 "Only %(remaining)d remaining in stock.",
                 number="remaining",
             )
             % {"remaining": (self.initial_quantity + variant.quantity_available)}
         )  # noqa
     return quantity
Ejemplo n.º 41
0
 def mutate(cls, root, info, id, restock):
     order = get_node(info, id, only_type=Order)
     cancel_order(order=order, restock=restock)
     if restock:
         restock_msg = npgettext_lazy(
             'Dashboard message related to an order',
             'Restocked %(quantity)d item',
             'Restocked %(quantity)d items',
             'quantity') % {'quantity': order.get_total_quantity()}
         order.history.create(content=restock_msg, user=info.context.user)
     else:
         msg = pgettext_lazy(
             'Dashboard message related to an order', 'Order canceled')
         order.history.create(content=msg, user=info.context.user)
     return OrderCancel(order=order)
Ejemplo n.º 42
0
 def clean_quantity(self):
     quantity = self.cleaned_data.get("quantity")
     order_line = self.cleaned_data.get("order_line")
     if quantity > order_line.quantity_unfulfilled:
         raise forms.ValidationError(
             npgettext_lazy(
                 "Fulfill order line form error",
                 "%(quantity)d item remaining to fulfill.",
                 "%(quantity)d items remaining to fulfill.",
                 number="quantity",
             ) % {
                 "quantity": order_line.quantity_unfulfilled,
                 "order_line": order_line,
             })
     return quantity
Ejemplo n.º 43
0
 def clean_quantity(self):
     quantity = self.cleaned_data["quantity"]
     delta = quantity - self.initial_quantity
     variant = self.instance.variant
     if variant and delta > variant.quantity_available:
         raise forms.ValidationError(
             npgettext_lazy(
                 "Change quantity form error",
                 "Only %(remaining)d remaining in stock.",
                 "Only %(remaining)d remaining in stock.",
                 number="remaining",
             )
             % {"remaining": (self.initial_quantity + variant.quantity_available)}
         )  # noqa
     return quantity
Ejemplo n.º 44
0
 def mutate(cls, root, info, id, restock):
     order = get_node(info, id, only_type=Order)
     cancel_order(order=order, restock=restock)
     if restock:
         restock_msg = npgettext_lazy(
             'Dashboard message related to an order',
             'Restocked %(quantity)d item',
             'Restocked %(quantity)d items',
             'quantity') % {'quantity': order.get_total_quantity()}
         order.history.create(content=restock_msg, user=info.context.user)
     else:
         msg = pgettext_lazy(
             'Dashboard message related to an order', 'Order canceled')
         order.history.create(content=msg, user=info.context.user)
     return OrderCancel(order=order)
Ejemplo n.º 45
0
    def clean_lines(cls, order_lines, quantities, errors):
        if errors:
            return errors

        for order_line, quantity in zip(order_lines, quantities):
            if quantity > order_line.quantity_unfulfilled:
                msg = npgettext_lazy(
                    'Fulfill order line mutation error',
                    'Only %(quantity)d item remaining to fulfill.',
                    'Only %(quantity)d items remaining to fulfill.',
                    number='quantity') % {
                        'quantity': order_line.quantity_unfulfilled,
                        'order_line': order_line}
                cls.add_error(errors, order_line, msg)
        return errors
Ejemplo n.º 46
0
    def clean_lines(cls, task_lines, quantities, errors):
        if errors:
            return errors

        for task_line, quantity in zip(task_lines, quantities):
            if quantity > task_line.quantity_unfulfilled:
                msg = npgettext_lazy(
                    'Fulfill task line mutation error',
                    'Only %(quantity)d item remaining to fulfill.',
                    'Only %(quantity)d items remaining to fulfill.',
                    number='quantity') % {
                        'quantity': task_line.quantity_unfulfilled,
                        'task_line': task_line
                    }
                cls.add_error(errors, task_line, msg)
        return errors
Ejemplo n.º 47
0
 def clean_lines(cls, order_lines, quantities, errors):
     for order_line, quantity in zip(order_lines, quantities):
         if quantity <= 0:
             cls.add_error(errors, order_line,
                           'Quantity must be larger than 0.')
         elif quantity > order_line.quantity_unfulfilled:
             msg = npgettext_lazy(
                 'Fulfill order line mutation error',
                 'Only %(quantity)d item remaining to fulfill.',
                 'Only %(quantity)d items remaining to fulfill.',
                 number='quantity') % {
                     'quantity': order_line.quantity_unfulfilled,
                     'order_line': order_line
                 }
             cls.add_error(errors, order_line, msg)
     return errors
Ejemplo n.º 48
0
 def clean_quantity(self):
     quantity = self.cleaned_data.get("quantity")
     order_line = self.cleaned_data.get("order_line")
     if quantity > order_line.quantity_unfulfilled:
         raise forms.ValidationError(
             npgettext_lazy(
                 "Fulfill order line form error",
                 "%(quantity)d item remaining to fulfill.",
                 "%(quantity)d items remaining to fulfill.",
                 number="quantity",
             )
             % {
                 "quantity": order_line.quantity_unfulfilled,
                 "order_line": order_line,
             }
         )
     return quantity
Ejemplo n.º 49
0
    def save(cls, info, instance, cleaned_input):
        order_lines = cleaned_input.get('order_lines')
        quantities = cleaned_input.get('quantities')
        super().save(info, instance, cleaned_input)
        order = instance.order
        if order_lines and quantities:
            quantity_fulfilled = 0
            lines_to_fulfill = [
                (order_line, quantity)
                for order_line, quantity in zip(order_lines, quantities)
                if quantity > 0
            ]
            for line in lines_to_fulfill:
                order_line = line[0]
                quantity = line[1]
                fulfill_order_line(order_line, quantity)
                quantity_fulfilled += quantity
            fulfillment_lines = [
                models.FulfillmentLine(order_line=line[0],
                                       fulfillment=instance,
                                       quantity=line[1])
                for line in lines_to_fulfill
            ]
            models.FulfillmentLine.objects.bulk_create(fulfillment_lines)
            update_order_status(order)
            msg = npgettext_lazy('Dashboard message related to an order',
                                 'Fulfilled %(quantity_fulfilled)d item',
                                 'Fulfilled %(quantity_fulfilled)d items',
                                 'quantity_fulfilled') % {
                                     'quantity_fulfilled': quantity_fulfilled
                                 }
            order.history.create(content=msg, user=info.context.user)
        super().save(info, instance, cleaned_input)

        if cleaned_input.get('notify_customer'):
            send_fulfillment_confirmation.delay(order.pk, instance.pk)
            send_mail_msg = pgettext_lazy(
                'Dashboard message related to an order',
                'Shipping confirmation email was sent to user'
                '(%(email)s)') % {
                    'email': order.get_user_current_email()
                }
            order.history.create(content=send_mail_msg, user=info.context.user)
Ejemplo n.º 50
0
    def save(cls, info, instance, cleaned_input):
        order_lines = cleaned_input.get('order_lines')
        quantities = cleaned_input.get('quantities')
        super().save(info, instance, cleaned_input)
        order = instance.order
        if order_lines and quantities:
            quantity_fulfilled = 0
            lines_to_fulfill = [
                (order_line, quantity) for order_line, quantity
                in zip(order_lines, quantities) if quantity > 0]
            for line in lines_to_fulfill:
                order_line = line[0]
                quantity = line[1]
                fulfill_order_line(order_line, quantity)
                quantity_fulfilled += quantity
            fulfillment_lines = [
                models.FulfillmentLine(
                    order_line=line[0],
                    fulfillment=instance,
                    quantity=line[1]) for line in lines_to_fulfill]
            models.FulfillmentLine.objects.bulk_create(fulfillment_lines)
            update_order_status(order)
            msg = npgettext_lazy(
                'Dashboard message related to an order',
                'Fulfilled %(quantity_fulfilled)d item',
                'Fulfilled %(quantity_fulfilled)d items',
                'quantity_fulfilled') % {
                    'quantity_fulfilled': quantity_fulfilled}
            order.history.create(content=msg, user=info.context.user)
        super().save(info, instance, cleaned_input)

        if cleaned_input.get('notify_customer'):
            send_fulfillment_confirmation.delay(order.pk, instance.pk)
            send_mail_msg = pgettext_lazy(
                'Dashboard message related to an order',
                'Shipping confirmation email was sent to user'
                '(%(email)s)') % {'email': order.get_user_current_email()}
            order.history.create(content=send_mail_msg, user=info.context.user)
Ejemplo n.º 51
0
def fulfill_order_lines(request, order_pk):
    orders = Order.objects.confirmed().prefetch_related("lines")
    order = get_object_or_404(orders, pk=order_pk)
    unfulfilled_lines = order.lines.filter(quantity_fulfilled__lt=F("quantity"))
    status = 200
    form = FulfillmentForm(request.POST or None, order=order, instance=Fulfillment())
    FulfillmentLineFormSet = modelformset_factory(
        FulfillmentLine,
        form=FulfillmentLineForm,
        extra=len(unfulfilled_lines),
        formset=BaseFulfillmentLineFormSet,
    )
    initial = [
        {"order_line": line, "quantity": line.quantity_unfulfilled}
        for line in unfulfilled_lines
    ]
    formset = FulfillmentLineFormSet(
        request.POST or None, queryset=FulfillmentLine.objects.none(), initial=initial
    )
    all_line_forms_valid = all([line_form.is_valid() for line_form in formset])
    if all_line_forms_valid and formset.is_valid() and form.is_valid():
        forms_to_save = [
            line_form
            for line_form in formset
            if line_form.cleaned_data.get("quantity") > 0
        ]
        if forms_to_save:
            fulfillment = form.save()
            quantities = []
            order_lines = []
            quantity_fulfilled = 0
            for line_form in forms_to_save:
                line = line_form.save(commit=False)
                line.fulfillment = fulfillment
                line.save()

                quantity = line_form.cleaned_data.get("quantity")
                quantity_fulfilled += quantity
                quantities.append(quantity)
                order_lines.append(line)
            # update to refresh prefetched lines quantity_fulfilled
            order = orders.get(pk=order_pk)
            update_order_status(order)
            msg = npgettext_lazy(
                "Dashboard message related to an order",
                "Fulfilled %(quantity_fulfilled)d item",
                "Fulfilled %(quantity_fulfilled)d items",
                number="quantity_fulfilled",
            ) % {"quantity_fulfilled": quantity_fulfilled}

            events.fulfillment_fulfilled_items_event(
                order=order,
                user=request.user,
                fulfillment_lines=fulfillment.lines.all(),
            )

            if form.cleaned_data.get("send_mail"):
                send_fulfillment_confirmation_to_customer(
                    order, fulfillment, request.user
                )
        else:
            msg = pgettext_lazy(
                "Dashboard message related to an order", "No items fulfilled"
            )
        messages.success(request, msg)
        return redirect("dashboard:order-details", order_pk=order.pk)
    elif form.errors:
        status = 400
    ctx = {
        "form": form,
        "formset": formset,
        "order": order,
        "unfulfilled_lines": unfulfilled_lines,
    }
    template = "dashboard/order/fulfillment.html"
    return TemplateResponse(request, template, ctx, status=status)
Ejemplo n.º 52
0
def display_order_event(order_event: OrderEvent):
    """This function is used to keep the backwards compatibility
        with the old dashboard and new type of order events
        (storing enums instead of messages)
        """
    event_type = order_event.type
    params = order_event.parameters
    if event_type == events.OrderEvents.PLACED_FROM_DRAFT:
        return pgettext_lazy(
            "Dashboard message related to an order", "Order placed from draft order"
        )
    if event_type == events.OrderEvents.PAYMENT_VOIDED:
        return pgettext_lazy(
            "Dashboard message related to an order",
            "Payment was voided by %(user_name)s" % {"user_name": order_event.user},
        )
    if event_type == events.OrderEvents.PAYMENT_REFUNDED:
        amount = get_money_from_params(params["amount"])
        return pgettext_lazy(
            "Dashboard message related to an order",
            "Successfully refunded: %(amount)s"
            % {"amount": prices_i18n.amount(amount)},
        )
    if event_type == events.OrderEvents.PAYMENT_CAPTURED:
        amount = get_money_from_params(params["amount"])
        return pgettext_lazy(
            "Dashboard message related to an order",
            "Successfully captured: %(amount)s"
            % {"amount": prices_i18n.amount(amount)},
        )
    if event_type == events.OrderEvents.ORDER_MARKED_AS_PAID:
        return pgettext_lazy(
            "Dashboard message related to an order", "Order manually marked as paid"
        )
    if event_type == events.OrderEvents.CANCELED:
        return pgettext_lazy(
            "Dashboard message related to an order", "Order was canceled"
        )
    if event_type == events.OrderEvents.FULFILLMENT_RESTOCKED_ITEMS:
        return npgettext_lazy(
            "Dashboard message related to an order",
            "We restocked %(quantity)d item",
            "We restocked %(quantity)d items",
            number="quantity",
        ) % {"quantity": params["quantity"]}
    if event_type == events.OrderEvents.NOTE_ADDED:
        return pgettext_lazy(
            "Dashboard message related to an order",
            "%(user_name)s added note: %(note)s"
            % {"note": params["message"], "user_name": order_event.user},
        )
    if event_type == events.OrderEvents.FULFILLMENT_CANCELED:
        return pgettext_lazy(
            "Dashboard message",
            "Fulfillment #%(fulfillment)s canceled by %(user_name)s",
        ) % {"fulfillment": params["composed_id"], "user_name": order_event.user}
    if event_type == events.OrderEvents.FULFILLMENT_FULFILLED_ITEMS:
        return pgettext_lazy(
            "Dashboard message related to an order", "Fulfilled some items"
        )
    if event_type == events.OrderEvents.PLACED:
        return pgettext_lazy(
            "Dashboard message related to an order", "Order was placed"
        )
    if event_type == events.OrderEvents.ORDER_FULLY_PAID:
        return pgettext_lazy(
            "Dashboard message related to an order", "Order was fully paid"
        )
    if event_type == events.OrderEvents.EMAIL_SENT:
        return pgettext_lazy(
            "Dashboard message related to an order",
            "%(email_type)s email was sent to the customer " "(%(email)s)",
        ) % {
            "email_type": EMAIL_CHOICES[params["email_type"]],
            "email": params["email"],
        }
    if event_type == events.OrderEvents.TRACKING_UPDATED:
        return pgettext_lazy(
            "Dashboard message related to an order",
            "Fulfillment #%(fulfillment)s tracking was updated to"
            " %(tracking_number)s by %(user_name)s",
        ) % {
            "fulfillment": params["composed_id"],
            "tracking_number": params["tracking_number"],
            "user_name": order_event.user,
        }
    if event_type == events.OrderEvents.DRAFT_CREATED:
        return pgettext_lazy(
            "Dashboard message related to an order",
            "The draft was created by %(user_name)s",
        ) % {"user_name": order_event.user}
    if event_type == events.OrderEvents.DRAFT_ADDED_PRODUCTS:
        return pgettext_lazy(
            "Dashboard message related to an order", "%(user_name)s added some products"
        ) % {"user_name": order_event.user}
    if event_type == events.OrderEvents.DRAFT_REMOVED_PRODUCTS:
        return pgettext_lazy(
            "Dashboard message related to an order",
            "%(user_name)s removed some products",
        ) % {"user_name": order_event.user}
    if event_type == events.OrderEvents.OVERSOLD_ITEMS:
        return pgettext_lazy(
            "Dashboard message related to an order",
            "%(user_name)s placed the order by bypassing oversold items",
        ) % {"user_name": order_event.user}
    if event_type == events.OrderEvents.UPDATED_ADDRESS:
        return pgettext_lazy(
            "Dashboard message related to an order",
            "The order address was updated by %(user_name)s",
        ) % {"user_name": order_event.user}
    if event_type == events.OrderEvents.PAYMENT_FAILED:
        return pgettext_lazy(
            "Dashboard message related to an order",
            "The payment was failed by %(user_name)s",
        ) % {"user_name": order_event.user}

    if event_type == events.OrderEvents.OTHER:
        return order_event.parameters["message"]
    raise ValueError("Not supported event type: %s" % (event_type))
Ejemplo n.º 53
0
from django.conf import settings
from django.utils.translation import npgettext_lazy, ugettext_lazy as _

from yummy.utils import import_module_member

# contains id of unit (used in models as choices in Choicesfield), translation function
# based npgettext_lazy, optional shortcut of unit and required form for translation if amount
# is decimal number (standard number for npgettext_lazy or char 'm' for magic transormation that use
# 1 if setting ALLOW_MAGIC_UNITS_TRANSFORM is Flase else 5 and slugify last char of returned val
# from npgettext_lazy)
UNITS = (
    (0, lambda c=1: npgettext_lazy('unit', 'piece', 'pieces', c), lambda c=1: npgettext_lazy('unit', 'pc', 'pcs', c), 'm'),
    (1, lambda c=1: npgettext_lazy('unit', 'gram', 'grams', c), 'g', 'm'),
    (2, lambda c=1: npgettext_lazy('unit', 'dekagram', 'dekagrams', c), 'dkg', 'm'),
    (3, lambda c=1: npgettext_lazy('unit', 'kilogram', 'kilograms', c), 'kg', 'm'),
    (4, lambda c=1: npgettext_lazy('unit', 'mililiter', 'mililiters', c), 'ml', 'm'),
    (5, lambda c=1: npgettext_lazy('unit', 'deciliter', 'deciliters', c), 'dl', 'm'),
    (6, lambda c=1: npgettext_lazy('unit', 'liter', 'liters', c), 'l', 'm'),
    (7, lambda c=1: npgettext_lazy('unit', 'packaging', 'packagings', c), 'pack', 1), #baleni
    (8, lambda c=1: npgettext_lazy('unit', 'package', 'packages', c), 'pkg', 'm'), #balicek
    (9, lambda c=1: npgettext_lazy('unit', 'part', 'parts', c), 'bit', 'm'), #dilek
    (10, lambda c=1: npgettext_lazy('unit', 'cup', 'cups', c), 'm'), #hrnek
    (11, lambda c=1: npgettext_lazy('unit', 'handful', 'handful', c), 2), #hrst
    (12, lambda c=1: npgettext_lazy('unit', 'drop', 'drops', c), 2), #kapka
    (13, lambda c=1: npgettext_lazy('unit', 'crubicle', 'crubicles', c), 'm'), #kelimek
    (14, lambda c=1: npgettext_lazy('unit', 'can', 'cans', c), 2), #plechovka
    (15, lambda c=1: npgettext_lazy('unit', 'scoop', 'scoops', c), 'm'), #kopecek
    (16, lambda c=1: npgettext_lazy('unit', 'cube', 'cubes', c), 2), #kostka
    (17, lambda c=1: npgettext_lazy('unit', 'ball', 'balls', c), 2), #kulicka
    (18, lambda c=1: npgettext_lazy('unit', 'bottle', 'bottles', c), 2), #lahev
    (19, lambda c=1: npgettext_lazy('unit', 'spoon', 'spoons', c), 1), #lzice
Ejemplo n.º 54
0
def display_order_event(order_event):
    """This function is used to keep the  backwards compatibility
    with the old dashboard and new type of order events
    (storing enums instead of messages)
    """
    event_type = order_event.type
    params = order_event.parameters
    if event_type == OrderEvents.PLACED_FROM_DRAFT.value:
        return pgettext_lazy(
            'Dashboard message related to an order',
            'Order created from draft order by %(user_name)s' % {
                'user_name': order_event.user})
    if event_type == OrderEvents.PAYMENT_RELEASED.value:
        return pgettext_lazy(
            'Dashboard message related to an order',
            'Payment was released by %(user_name)s' % {
                'user_name': order_event.user})
    if event_type == OrderEvents.PAYMENT_REFUNDED.value:
        amount = Money(
            amount=params['amount'], currency=settings.DEFAULT_CURRENCY)
        return pgettext_lazy(
            'Dashboard message related to an order',
            'Successfully refunded: %(amount)s' % {
                'amount': prices_i18n.amount(amount)})
    if event_type == OrderEvents.PAYMENT_CAPTURED.value:
        amount = Money(
            amount=params['amount'], currency=settings.DEFAULT_CURRENCY)
        return pgettext_lazy(
            'Dashboard message related to an order',
            'Successfully captured: %(amount)s' % {
                'amount': prices_i18n.amount(amount)})
    if event_type == OrderEvents.ORDER_MARKED_AS_PAID.value:
        return pgettext_lazy(
            'Dashboard message related to an order',
            'Order manually marked as paid by %(user_name)s' % {
                'user_name': order_event.user})
    if event_type == OrderEvents.CANCELED.value:
        return pgettext_lazy(
            'Dashboard message related to an order',
            'Order was canceled by %(user_name)s' % {
                'user_name': order_event.user})
    if event_type == OrderEvents.FULFILLMENT_RESTOCKED_ITEMS.value:
        return npgettext_lazy(
            'Dashboard message related to an order',
            'We restocked %(quantity)d item',
            'We restocked %(quantity)d items',
            'quantity') % {'quantity': params['quantity']}
    if event_type == OrderEvents.NOTE_ADDED.value:
        return pgettext_lazy(
            'Dashboard message related to an order',
            '%(user_name)s added note: %(note)s' % {
                'note': params['message'],
                'user_name': order_event.user})
    if event_type == OrderEvents.FULFILLMENT_CANCELED.value:
        return pgettext_lazy(
            'Dashboard message',
            'Fulfillment #%(fulfillment)s canceled by %(user_name)s') % {
                'fulfillment': params['composed_id'],
                'user_name': order_event.user}
    if event_type == OrderEvents.FULFILLMENT_FULFILLED_ITEMS.value:
        return npgettext_lazy(
            'Dashboard message related to an order',
            'Fulfilled %(quantity_fulfilled)d item',
            'Fulfilled %(quantity_fulfilled)d items',
            'quantity_fulfilled') % {
                'quantity_fulfilled': params['quantity']}
    if event_type == OrderEvents.PLACED.value:
        return pgettext_lazy(
            'Dashboard message related to an order',
            'Order was placed')
    if event_type == OrderEvents.ORDER_FULLY_PAID.value:
        return pgettext_lazy(
            'Dashboard message related to an order',
            'Order was fully paid')
    if event_type == OrderEvents.EMAIL_SENT.value:
        return pgettext_lazy(
            'Dashboard message related to an order',
            '%(email_type)s email was sent to the customer '
            '(%(email)s)') % {
                'email_type': EMAIL_CHOICES[params['email_type']],
                'email': params['email']}
    if event_type == OrderEvents.UPDATED.value:
        return pgettext_lazy(
            'Dashboard message related to an order',
            'Order details were updated by %(user_name)s' % {
                'user_name': order_event.user})
    if event_type == OrderEvents.OTHER.value:
        return order_event.parameters['message']
    raise ValueError('Not supported event type: %s' % (event_type))
Ejemplo n.º 55
0
def naturaltime(value):
    """
    For date and time values show how many seconds, minutes, or hours ago
    compared to current timestamp return representing string.
    """
    if not isinstance(value, date):  # datetime is a subclass of date
        return value

    now = datetime.now(utc if is_aware(value) else None)
    if value < now:
        delta = now - value
        if delta.days != 0:
            # Translators: delta will contain a string like '2 months' or '1 month, 2 weeks'
            return _('%(delta)s ago') % {'delta': defaultfilters.timesince(value, now, time_strings={
                # Translators: 'naturaltime-past' strings will be included in
                # '%(delta)s ago'
                'year': npgettext_lazy('naturaltime-past', '%d year', '%d years'),
                'month': npgettext_lazy('naturaltime-past', '%d month', '%d months'),
                'week': npgettext_lazy('naturaltime-past', '%d week', '%d weeks'),
                'day': npgettext_lazy('naturaltime-past', '%d day', '%d days'),
                'hour': npgettext_lazy('naturaltime-past', '%d hour', '%d hours'),
                'minute': npgettext_lazy('naturaltime-past', '%d minute', '%d minutes')
            })}
        elif delta.seconds == 0:
            return _('now')
        elif delta.seconds < 60:
            return ngettext(
                # Translators: please keep a non-breaking space (U+00A0)
                # between count and time unit.
                'a second ago', '%(count)s seconds ago', delta.seconds
            ) % {'count': delta.seconds}
        elif delta.seconds // 60 < 60:
            count = delta.seconds // 60
            return ngettext(
                # Translators: please keep a non-breaking space (U+00A0)
                # between count and time unit.
                'a minute ago', '%(count)s minutes ago', count
            ) % {'count': count}
        else:
            count = delta.seconds // 60 // 60
            return ngettext(
                # Translators: please keep a non-breaking space (U+00A0)
                # between count and time unit.
                'an hour ago', '%(count)s hours ago', count
            ) % {'count': count}
    else:
        delta = value - now
        if delta.days != 0:
            # Translators: delta will contain a string like '2 months' or '1 month, 2 weeks'
            return _('%(delta)s from now') % {'delta': defaultfilters.timeuntil(value, now, time_strings={
                # Translators: 'naturaltime-future' strings will be included in
                # '%(delta)s from now'
                'year': npgettext_lazy('naturaltime-future', '%d year', '%d years'),
                'month': npgettext_lazy('naturaltime-future', '%d month', '%d months'),
                'week': npgettext_lazy('naturaltime-future', '%d week', '%d weeks'),
                'day': npgettext_lazy('naturaltime-future', '%d day', '%d days'),
                'hour': npgettext_lazy('naturaltime-future', '%d hour', '%d hours'),
                'minute': npgettext_lazy('naturaltime-future', '%d minute', '%d minutes')
            })}
        elif delta.seconds == 0:
            return _('now')
        elif delta.seconds < 60:
            return ngettext(
                # Translators: please keep a non-breaking space (U+00A0)
                # between count and time unit.
                'a second from now', '%(count)s seconds from now', delta.seconds
            ) % {'count': delta.seconds}
        elif delta.seconds // 60 < 60:
            count = delta.seconds // 60
            return ngettext(
                # Translators: please keep a non-breaking space (U+00A0)
                # between count and time unit.
                'a minute from now', '%(count)s minutes from now', count
            ) % {'count': count}
        else:
            count = delta.seconds // 60 // 60
            return ngettext(
                # Translators: please keep a non-breaking space (U+00A0)
                # between count and time unit.
                'an hour from now', '%(count)s hours from now', count
            ) % {'count': count}