Skip to content
Permalink
Browse files

Core: add signal and notify event when order status changes

Bump mock to latest to be able to use mock call test correctly

Refs HEAL-34
  • Loading branch information...
chessbr committed Jun 12, 2019
1 parent e4bd2df commit 2dda66caafe96b7c50ebdcfbc0cf1260dfb0397f
@@ -40,7 +40,7 @@
from shuup.core.pricing import TaxfulPrice, TaxlessPrice
from shuup.core.settings_provider import ShuupSettings
from shuup.core.signals import (
payment_created, refund_created, shipment_created,
order_status_changed, payment_created, refund_created, shipment_created,
shipment_created_and_processed
)
from shuup.utils.analog import define_log_model, LogEntryKind
@@ -527,14 +527,23 @@ def save(self, *args, **kwargs):
"when SHUUP_ALLOW_ANONYMOUS_ORDERS is not enabled.")
self._cache_values()
first_save = (not self.pk)
old_status = self.status

if not first_save:
old_status = Order.objects.only("status").get(pk=self.pk).status

super(Order, self).save(*args, **kwargs)

if first_save: # Have to do a double save the first time around to be able to save identifiers
self._save_identifiers()
self._cache_contact_values_post_create()

for line in self.lines.exclude(product_id=None):
line.supplier.module.update_stock(line.product_id)

if self.status != old_status:
order_status_changed.send(type(self), order=self, old_status=old_status, new_status=self.status)

def delete(self, using=None):
if not self.deleted:
self.deleted = True
@@ -20,6 +20,7 @@
pre_clean = Signal(providing_args=["instance"], use_caching=True)
post_clean = Signal(providing_args=["instance"], use_caching=True)
context_cache_item_bumped = Signal(providing_args=["item"], use_caching=True)
order_status_changed = Signal(providing_args=["order", "old_status", "new_status"], use_caching=True)

#: Send from supplier module after the stocks updated have
#: been triggered after order, shipment and shop product change.
@@ -30,6 +30,7 @@ class ShuupFrontAppConfig(AppConfig):
],
"notify_event": [
"shuup.front.notify_events:OrderReceived",
"shuup.front.notify_events:OrderStatusChanged",
"shuup.front.notify_events:ShipmentCreated",
"shuup.front.notify_events:ShipmentDeleted",
"shuup.front.notify_events:PaymentCreated",
@@ -11,10 +11,11 @@
from shuup.core.models import PaymentStatus, ShipmentStatus, ShippingStatus
from shuup.core.order_creator.signals import order_creator_finished
from shuup.core.signals import (
payment_created, refund_created, shipment_created_and_processed,
shipment_deleted
order_status_changed, payment_created, refund_created,
shipment_created_and_processed, shipment_deleted
)
from shuup.notify.base import Event, Variable
from shuup.notify.models import Script
from shuup.notify.typology import Email, Enum, Language, Model, Phone


@@ -30,6 +31,20 @@ class OrderReceived(Event):
language = Variable(_("Language"), type=Language)


class OrderStatusChanged(Event):
identifier = "order_status_changed"
name = _("Order Status Changed")

order = Variable(_("Order"), type=Model("shuup.Order"))
customer_email = Variable(_("Customer Email"), type=Email)
customer_phone = Variable(_("Customer Phone"), type=Phone)
shop_email = Variable(_("Shop Email"), type=Email)
shop_phone = Variable(_("Shop Phone"), type=Phone)
old_status = Variable(_("Old Status"), type=Model("shuup.OrderStatus"))
new_status = Variable(_("New Status"), type=Model("shuup.OrderStatus"))
language = Variable(_("Language"), type=Language)


class ShipmentCreated(Event):
identifier = "shipment_created"
name = _("Shipment Created")
@@ -148,3 +163,34 @@ def send_refund_created_notification(order, refund_lines, **kwargs):
language=order.language,
payment_status=order.payment_status
).run(shop=order.shop)


@receiver(order_status_changed)
def send_order_status_changed_notification(order, old_status, new_status, **kwargs):
# no script for this event configured
enabled_scripts = Script.objects.filter(
shop=order.shop,
event_identifier=OrderStatusChanged.identifier,
enabled=True
)
if not enabled_scripts.exists():
return

params = dict(
order=order,
customer_email=order.email,
customer_phone=order.phone,
shop_email=None,
shop_phone=None,
language=order.language,
old_status=old_status,
new_status=new_status
)

if order.shop.contact_address:
params.update(dict(
shop_email=order.shop.contact_address.email,
shop_phone=order.shop.contact_address.phone
))

OrderStatusChanged(**params).run(shop=order.shop)
@@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
# This file is part of Shuup.
#
# Copyright (c) 2012-2019, Shoop Commerce Ltd. All rights reserved.
#
# This source code is licensed under the OSL-3.0 license found in the
# LICENSE file in the root directory of this source tree.
from __future__ import unicode_literals

from datetime import datetime

import mock
import pytest
import pytz

from shuup.core.models import OrderStatus, OrderStatusManager
from shuup.notify.models import Script
from shuup.testing import factories
from shuup.utils.i18n import get_locally_formatted_datetime


@pytest.mark.django_db
def test_class_refunded():
shop = factories.get_default_shop()
supplier = factories.get_default_supplier()
customer = factories.create_random_person("en")
OrderStatusManager().ensure_default_statuses()

product = factories.create_product("p", shop, supplier, 1.0)
order = factories.create_order_with_product(product, supplier, 1, 1, shop=shop)

# make sure to have some script enabled
Script.objects.create(shop=shop, event_identifier="order_status_changed", name="Script", enabled=True)

def get_mocked_cls():
return mock.MagicMock(identifier="order_status_changed")

with mock.patch("shuup.front.notify_events.OrderStatusChanged", new_callable=get_mocked_cls) as mocked:
order.status = OrderStatus.objects.get_default_processing()
order.save()
mocked.assert_called()
order.refresh_from_db()
assert mocked.call_args.kwargs["order"] == order
assert mocked.call_args.kwargs["old_status"] == OrderStatus.objects.get_default_initial()
assert mocked.call_args.kwargs["new_status"] == OrderStatus.objects.get_default_processing()
assert order.status == OrderStatus.objects.get_default_processing()

# nothing changes
with mock.patch("shuup.front.notify_events.OrderStatusChanged", new_callable=get_mocked_cls) as mocked:
order.status = OrderStatus.objects.get_default_processing()
order.save()
mocked.assert_not_called()
@@ -33,7 +33,7 @@ deps =
# BEGIN testing deps
beautifulsoup4==4.5.3
html5lib==0.999999999
mock==2.0.0
mock==3.0.5
pytest-cache==1.0
pytest==3.0.6
pytest-cov==2.4.0

0 comments on commit 2dda66c

Please sign in to comment.
You can’t perform that action at this time.