# models.py
from django.db import models
from django.utils import timezone
from ralph.lib.dj_choices import Choices
from ralph.lib.transitions.fields import TransitionField
from ralph.lib.transitions.models import TransitionWorkflowBase
from ralph.lib.transitions.decorators import transition_action
from ralph.lib.mixins.models import AdminAbsoluteUrlMixin, TimeStampMixin
class OrderStatus(Choices):
_ = Choices.Choice
NEW = _('New')
PROCESSING = _('Processing')
PACKED = _('Packed')
SHIPPED = _('Shipped')
DELIVERED = _('Delivered')
CANCELLED = _('Cancelled')
class Order(AdminAbsoluteUrlMixin, TimeStampMixin, models.Model, metaclass=TransitionWorkflowBase):
name = models.CharField(max_length=255)
customer = models.ForeignKey('Customer', on_delete=models.CASCADE)
status = TransitionField(
default=OrderStatus.NEW.id,
choices=OrderStatus(),
)
tracking_number = models.CharField(max_length=100, blank=True)
shipped_at = models.DateTimeField(null=True, blank=True)
def items_in_stock(self):
return all(item.in_stock for item in self.items.all())
@classmethod
@transition_action(
verbose_name='Validate and Process',
precondition=lambda instances, requester: {
instance: 'Items out of stock'
for instance in instances
if not instance.items_in_stock()
}
)
def process_order(cls, instances, request, **kwargs):
for instance in instances:
instance.allocate_items()
notify_warehouse(instance)
@classmethod
@transition_action(
form_fields={
'tracking_number': {'field': forms.CharField()},
'carrier': {'field': forms.ChoiceField(
choices=[('ups', 'UPS'), ('fedex', 'FedEx')]
)}
},
return_attachment=True
)
def ship_order(cls, instances, request, tracking_number, carrier, **kwargs):
attachments = []
for instance in instances:
instance.tracking_number = tracking_number
instance.carrier = carrier
instance.shipped_at = timezone.now()
# Generate shipping label
pdf = create_shipping_label(instance)
attachment = Attachment.objects.create(
file=ContentFile(pdf, name=f'label_{instance.id}.pdf')
)
attachments.append(attachment)
send_tracking_email(instance)
return attachments
# admin.py
from ralph.admin import RalphAdmin, register
from ralph.lib.transitions.admin import TransitionAdminMixin
@register(Order)
class OrderAdmin(TransitionAdminMixin, RalphAdmin):
list_display = ['name', 'customer', 'status', 'created']
list_filter = ['status']
search_fields = ['name', 'tracking_number']
show_transition_history = True