Skip to content

Commit 558f307

Browse files
authored
553 add segment filter option for last order date and order count (#561)
* Add option to filter segments by order_count, has_ordered and months_since_last_order
1 parent 8995808 commit 558f307

1 file changed

Lines changed: 71 additions & 4 deletions

File tree

bakeup/newsletter/models.py

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,19 @@
88
from django.contrib.auth.tokens import PasswordResetTokenGenerator
99
from django.core.mail import send_mail
1010
from django.db import connection, models
11-
from django.db.models import Exists, OuterRef, Q, UniqueConstraint
11+
from django.db.models import (
12+
Count,
13+
Exists,
14+
ExpressionWrapper,
15+
F,
16+
IntegerField,
17+
Max,
18+
OuterRef,
19+
Q,
20+
UniqueConstraint,
21+
Value,
22+
)
23+
from django.db.models.functions import ExtractDay, Now
1224
from django.http import HttpResponse, HttpResponseNotFound
1325
from django.template.loader import render_to_string
1426
from django.urls import reverse
@@ -18,7 +30,7 @@
1830
from djangoql.exceptions import DjangoQLParserError
1931
from djangoql.parser import DjangoQLParser
2032
from djangoql.queryset import DjangoQLQuerySet
21-
from djangoql.schema import BoolField, DjangoQLSchema
33+
from djangoql.schema import BoolField, DjangoQLSchema, IntField
2234
from modelcluster.models import ClusterableModel
2335
from wagtail.admin.forms import WagtailAdminPageForm
2436
from wagtail.admin.panels import FieldPanel, ObjectList, TabbedInterface
@@ -31,7 +43,7 @@
3143
from bakeup.newsletter.panels import NewsletterPanel
3244
from bakeup.pages.blocks import AllBlocks
3345
from bakeup.pages.models import BrandSettings, EmailSettings
34-
from bakeup.shop.models import Customer, PointOfSale
46+
from bakeup.shop.models import Customer, CustomerOrder, PointOfSale
3547
from bakeup.users.models import User
3648

3749
from .blocks import StoryBlock
@@ -372,7 +384,19 @@ def members(self):
372384
members = self.audience.contacts.all()
373385
if self.filter_query:
374386
members = members.annotate(
375-
is_customer=Exists(Customer.objects.filter(user=OuterRef("user")))
387+
is_customer=Exists(Customer.objects.filter(user=OuterRef("user"))),
388+
has_ordered=Exists(
389+
CustomerOrder.objects.filter(customer__user=OuterRef("user"))
390+
),
391+
order_count=Count("user__customer__orders"),
392+
)
393+
members = members.annotate(
394+
last_order_date=Max("user__customer__orders__created"),
395+
).annotate(
396+
months_since_last_order=ExpressionWrapper(
397+
ExtractDay(Now() - F("last_order_date")) / Value(30),
398+
output_field=IntegerField(),
399+
),
376400
)
377401
members = members.djangoql(self.filter_query, ContactSchema)
378402
return members
@@ -548,6 +572,46 @@ def _make_hash_value(self, contact, timestamp):
548572
return str(bool(contact.is_active)) + str(contact.pk) + str(timestamp)
549573

550574

575+
class MonthsSinceLastOrderField(IntField):
576+
"""
577+
Allows filtering like:
578+
months_since_last_order > 12
579+
months_since_last_order = 0 (ordered this month)
580+
"""
581+
582+
name = "months_since_last_order"
583+
584+
def get_lookup_name(self):
585+
return "months_since_last_order"
586+
587+
588+
class OrderCountField(IntField):
589+
"""
590+
Allows filtering like:
591+
order_count = 0 (never ordered)
592+
order_count > 5 (more than 5 orders)
593+
order_count >= 1 (has ordered at least once)
594+
"""
595+
596+
name = "order_count"
597+
598+
def get_lookup_name(self):
599+
return "order_count"
600+
601+
602+
class HasOrderedField(BoolField):
603+
"""
604+
Allows filtering like:
605+
has_ordered = True
606+
has_ordered = False
607+
"""
608+
609+
name = "has_ordered"
610+
611+
def get_lookup_name(self):
612+
return "has_ordered"
613+
614+
551615
class ContactSchema(DjangoQLSchema):
552616
exclude = (NewsletterPage, Receipt)
553617

@@ -560,6 +624,9 @@ def get_fields(self, model):
560624
"email",
561625
"user",
562626
"is_active",
627+
HasOrderedField(),
628+
OrderCountField(),
629+
MonthsSinceLastOrderField(),
563630
]
564631
if model == Group:
565632
return ["name"]

0 commit comments

Comments
 (0)