def test_approve_order_one_success_one_failure( superuser_api_client, order: Order, payment_provider, notification_template_orders_approved, ): order.status = OrderStatus.DRAFTED order.save(update_fields=["status"]) due_date = (today() + relativedelta(days=14)).date() failure_order_id = to_global_id(OrderNode, uuid.uuid4()) variables = { "dueDate": due_date, "orders": [ { "orderId": failure_order_id, "email": "*****@*****.**" }, { "orderId": to_global_id(OrderNode, order.id), "email": order.lease.application.email, }, ], } with mock.patch( "customers.services.profile.requests.post", side_effect=mocked_response_profile(count=1, data=None, use_edges=False), ): executed = superuser_api_client.execute(APPROVE_ORDER_MUTATION, input=variables) payment_url = payment_provider.get_payment_email_url( order, lang=order.lease.application.language) order = Order.objects.get(id=order.id) assert len(executed["data"]["approveOrders"]["failedOrders"]) == 1 assert executed["data"]["approveOrders"]["failedOrders"][0] == { "id": failure_order_id, "error": "Order matching query does not exist.", } assert order.due_date == due_date assert order.lease.status == LeaseStatus.OFFERED assert order.lease.application.status == ApplicationStatus.OFFER_SENT assert len(mail.outbox) == 1 assert (mail.outbox[0].subject == f"test order approved subject, event: {order.order_number}!") assert mail.outbox[0].body == f"{ order.order_number } { payment_url }" assert mail.outbox[0].to == [order.lease.application.email] assert mail.outbox[0].alternatives == [ (f"<b>{ order.order_number } { payment_url }</b>", "text/html") ]
def test_approve_order_does_not_exist( superuser_api_client, payment_provider, notification_template_orders_approved, ): order_id = to_global_id(OrderNode, uuid.uuid4()) variables = { "orders": [{ "orderId": order_id, "email": "*****@*****.**" }], } with mock.patch( "customers.services.profile.requests.post", side_effect=mocked_response_profile(count=1, data=None, use_edges=False), ): executed = superuser_api_client.execute(APPROVE_ORDER_MUTATION, input=variables) assert len(executed["data"]["approveOrders"]["failedOrders"]) == 1 assert executed["data"]["approveOrders"]["failedOrders"][0] == { "id": order_id, "error": "Order matching query does not exist.", }
def test_approve_order_default_due_date( api_client, order: Order, payment_provider, notification_template_orders_approved, ): order.status = OrderStatus.DRAFTED order.save(update_fields=["status"]) order.due_date = today().date() order.save() variables = { "orders": [{ "orderId": to_global_id(OrderNode, order.id), "email": order.lease.application.email, }], } expected_due_date = today().date() + relativedelta(weeks=2) assert order.due_date != expected_due_date with mock.patch( "customers.services.profile.requests.post", side_effect=mocked_response_profile(count=1, data=None, use_edges=False), ): api_client.execute(APPROVE_ORDER_MUTATION, input=variables) order = Order.objects.get(id=order.id) assert order.due_date == expected_due_date
def test_approve_order_sms_not_sent( api_client, order: Order, payment_provider, notification_template_orders_approved, ): order.status = OrderStatus.DRAFTED order.save(update_fields=["status"]) order.customer_phone = None order.save() due_date = (today() + relativedelta(days=14)).date() variables = { "dueDate": due_date, "orders": [{ "orderId": to_global_id(OrderNode, order.id), "email": order.lease.application.email, }], } with mock.patch( "customers.services.profile.requests.post", side_effect=mocked_response_profile(count=1, data=None, use_edges=False), ), mock.patch.object(SMSNotificationService, "send", return_value=None) as mock_send_sms: api_client.execute(APPROVE_ORDER_MUTATION, input=variables) # Assert that the SMS is not sent mock_send_sms.assert_not_called()
def _send_invoices(data): invoicing_service = BerthInvoicingService( request=RequestFactory().request(), profile_token="token") with mock.patch( "customers.services.profile.requests.post", side_effect=mocked_response_profile(count=0, data=data), ): invoicing_service.send_invoices() return invoicing_service
def test_send_berth_invoices_invalid_limit_reached( notification_template_orders_approved, ): first_lease = _lease_with_contract( boat=None, status=LeaseStatus.PAID, start_date=today() - relativedelta(years=1), end_date=today() + relativedelta(years=-1, months=5), ) for _ in range(2): _lease_with_contract( boat=None, status=LeaseStatus.PAID, start_date=today() - relativedelta(years=1), end_date=today() + relativedelta(years=-1, months=5), ) customer = first_lease.customer BerthProductFactory( min_width=first_lease.berth.berth_type.width - 1, max_width=first_lease.berth.berth_type.width + 1, ) user = UserFactory() data = { "id": to_global_id(ProfileNode, customer.id), "first_name": user.first_name, "last_name": user.last_name, "primary_email": { "email": "*****@*****.**" }, "primary_phone": { "phone": faker.phone_number() }, } assert Order.objects.count() == 0 invoicing_service = BerthInvoicingService( request=RequestFactory().request(), profile_token="token") with mock.patch( "customers.services.profile.requests.post", side_effect=mocked_response_profile(count=1, data=data), ): with mock.patch.object( invoicing_service, "email_admins", wraps=invoicing_service.email_admins, ) as email_admins_mock: invoicing_service.MAXIMUM_FAILURES = 1 invoicing_service.send_invoices() email_admins_mock.assert_called_once_with( True) # called with exited_with_errors=True assert invoicing_service.failure_count == 1
def test_create_berth_switch_offer_refresh_profile(api_client, berth_application, berth): faker = Faker("fi_FI") berth_lease = BerthLeaseFactory( start_date=calculate_season_start_date(), end_date=calculate_season_end_date(), status=LeaseStatus.PAID, ) berth_application.customer = berth_lease.customer berth_application.berth_switch = BerthSwitchFactory( berth=berth_lease.berth) berth_application.save() first_name = faker.first_name() last_name = faker.last_name() email = faker.email() phone = faker.phone_number() data = { "id": to_global_id(ProfileNode, berth_lease.customer.id), "first_name": first_name, "last_name": last_name, "primary_email": { "email": email }, "primary_phone": { "phone": phone }, } variables = { "applicationId": to_global_id(BerthApplicationNode, berth_application.id), "newBerthId": to_global_id(BerthNode, berth.id), "profileToken": "profile-token", } with mock.patch( "customers.services.profile.requests.post", side_effect=mocked_response_profile(count=0, data=data, use_edges=False), ): executed = api_client.execute( CREATE_BERTH_SWITCH_OFFER_MUTATION_CUSTOMER_FIELDS, input=variables) assert executed["data"]["createBerthSwitchOffer"]["berthSwitchOffer"] == { "customerFirstName": first_name, "customerLastName": last_name, "customerEmail": email, "customerPhone": phone, }
def test_resend_order_not_fixed_in_error( order: Order, superuser_api_client, notification_template_orders_approved, ): order.status = OrderStatus.ERROR order.lease.status = LeaseStatus.ERROR order.lease.save() order.product.pricing_category = get_berth_product_pricing_category(order) order.product.save() order.save() profile_data = { "id": to_global_id(ProfileNode, order.customer.id), "first_name": "Foo", "last_name": "Bar", "primary_email": { "email": None }, "primary_phone": { "phone": None }, } variables = { "orders": [to_global_id(OrderNode, order.id)], "profileToken": "token" } with mock.patch( "requests.post", side_effect=mocked_response_profile(count=0, data=profile_data, use_edges=False), ): executed = superuser_api_client.execute(RESEND_ORDER_MUTATION, input=variables) order.refresh_from_db() order.lease.refresh_from_db() assert len(executed["data"]["resendOrder"]["failedOrders"]) == 1 failed_order = executed["data"]["resendOrder"]["failedOrders"][0] assert failed_order["id"] == to_global_id(OrderNode, order.id) assert "Missing customer email" in str(failed_order["error"]) assert order.lease.status == LeaseStatus.ERROR assert order.status == OrderStatus.ERROR assert len(mail.outbox) == 0
def test_approve_order_anymail_error( superuser_api_client, payment_provider, notification_template_orders_approved, order: Order, ): order.status = OrderStatus.DRAFTED order.save(update_fields=["status"]) order_id = to_global_id(OrderNode, order.id) previous_order_status = order.status previous_lease_status = order.lease.status previous_application_status = order.lease.application.status variables = { "orders": [{ "orderId": order_id, "email": "*****@*****.**" }], } with patch( "customers.services.profile.requests.post", side_effect=mocked_response_profile(count=1, data=None, use_edges=False), ): with patch( "payments.utils.send_notification", side_effect=AnymailError("Anymail error"), ) as mock: executed = superuser_api_client.execute(APPROVE_ORDER_MUTATION, input=variables) mock.assert_called_once() assert len(executed["data"]["approveOrders"]["failedOrders"]) == 1 assert executed["data"]["approveOrders"]["failedOrders"][0] == { "id": order_id, "error": "Anymail error", } order = Order.objects.get(id=order.id) assert order.status == previous_order_status assert order.lease.status == previous_lease_status.value assert order.lease.application.status == previous_application_status
def test_send_berth_invoices_send_error(notification_template_orders_approved): lease = _lease_with_contract( boat=None, status=LeaseStatus.PAID, start_date=today() - relativedelta(years=1), end_date=today() + relativedelta(years=-1, months=5), ) customer = lease.customer user = UserFactory() data = { "id": to_global_id(ProfileNode, customer.id), "first_name": user.first_name, "last_name": user.last_name, "primary_email": { "email": user.email }, "primary_phone": { "phone": faker.phone_number() }, } assert Order.objects.count() == 0 with mock.patch( "customers.services.profile.requests.post", side_effect=mocked_response_profile(count=0, data=data), ): with mock.patch( "payments.utils.send_notification", side_effect=AnymailError("Anymail error"), ): invoicing_service = BerthInvoicingService( request=RequestFactory().request(), profile_token="token") invoicing_service.send_invoices() assert len(invoicing_service.successful_orders) == 0 assert len(invoicing_service.failed_orders) == 1 assert len(invoicing_service.failed_leases) == 0 assert Order.objects.count() == 1 order = Order.objects.first() assert order.id in invoicing_service.failed_orders[0].keys() assert order.comment == "01-01-2020 10:00:00: Anymail error" assert order.due_date is None assert invoicing_service.failed_orders[0].get(order.id) == "Anymail error" assert len(mail.outbox) == 0 leases = BerthLease.objects.exclude(id=lease.id) assert leases.count() == 1 lease: BerthLease = leases.first() assert lease.status == LeaseStatus.ERROR assert "Error with the order, check the order first" in lease.comment assert lease.start_date.isoformat() == "2020-06-10" assert lease.end_date.isoformat() == "2020-09-14" assert order.status == OrderStatus.ERROR assert (order.log_entries.get(to_status=OrderStatus.ERROR).comment == "Lease renewing failed: Anymail error")
def test_resend_order( api_client, order: Order, order_has_contact_info, request_has_profile_token, notification_template_orders_approved, berth_product, winter_storage_product, payment_provider, order_status, ): order.status = order_status order.order_type = OrderType.LEASE_ORDER.value initial_price = decimal.Decimal( "00.42") # a price that is different from the price in BerthProduct order.price = initial_price order_original_email = "*****@*****.**" if order_has_contact_info: order.customer_phone = "+358505658789" order.customer_email = order_original_email else: order.customer_phone = "" # trigger update from profile service order.customer_email = "" order.save() order.lease.status = LeaseStatus.OFFERED order.lease.save() orders = [order] if isinstance(order.lease, WinterStorageLease): winter_storage_product.winter_storage_area = ( order.lease.get_winter_storage_area()) berth_product.min_width = decimal.Decimal("0.0") berth_product.max_width = decimal.Decimal("999.0") berth_product.tier_1_price = decimal.Decimal("100.0") berth_product.tier_2_price = decimal.Decimal("200.0") berth_product.tier_3_price = decimal.Decimal("300.0") berth_product.pricing_category = get_berth_product_pricing_category(order) berth_product.save() variables = { "orders": [to_global_id(OrderNode, o.id) for o in orders], "dueDate": "2020-01-31", } if request_has_profile_token: variables["profileToken"] = "token" customer_profile = CustomerProfileFactory() profile_data = { "id": to_global_id(ProfileNode, customer_profile.id), "first_name": order.lease.application.first_name, "last_name": order.lease.application.last_name, "primary_email": { "email": order.lease.application.email }, "primary_phone": { "phone": order.lease.application.phone_number }, } with mock.patch( "requests.post", side_effect=mocked_response_profile(count=0, data=profile_data, use_edges=False), ), mock.patch.object(SMSNotificationService, "send", return_value=None) as mock_send_sms: executed = api_client.execute(RESEND_ORDER_MUTATION, input=variables) if request_has_profile_token or order_has_contact_info: # there was sufficient customer info available for invoicing assert executed["data"]["resendOrder"]["failedOrders"] == [] assert executed["data"]["resendOrder"]["sentOrders"] == [str(order.id)] order.refresh_from_db() assert order.price != initial_price order.lease.refresh_from_db() assert order.status == OrderStatus.OFFERED assert order.lease.status == LeaseStatus.OFFERED assert len(mail.outbox) == 1 assert (mail.outbox[0].subject == f"test order approved subject, event: {order.order_number}!") assert order.order_number in mail.outbox[0].body if request_has_profile_token: # always when profile_token is supplied, fetch customer info from profile assert mail.outbox[0].to == [order.lease.application.email] else: assert mail.outbox[0].to == [order_original_email] assert order.order_number in mail.outbox[0].alternatives[0][0] assert mail.outbox[0].alternatives[0][1] == "text/html" # Assert that the SMS is being sent payment_url = payment_provider.get_payment_email_url( order, lang=order.lease.application.language) sms_context = { "product_name": order.product.name, "due_date": format_date(order.due_date, locale=order.lease.application.language), "payment_url": payment_url, } mock_send_sms.assert_called_with( NotificationType.SMS_INVOICE_NOTICE, sms_context, order.customer_phone, language=order.lease.application.language, ) else: # no profile_token and no contact info assert len(executed["data"]["resendOrder"]["failedOrders"]) == 1 assert ("Profile token is required" in executed["data"]["resendOrder"]["failedOrders"][0]["error"]) assert executed["data"]["resendOrder"]["sentOrders"] == [] # Assert that the SMS is not sent mock_send_sms.assert_not_called()
def test_resend_order_in_error( order: Order, superuser_api_client, notification_template_orders_approved, payment_provider, ): order.customer_email = "*****@*****.**" order.status = OrderStatus.ERROR order.lease.status = LeaseStatus.ERROR order.lease.save() order.product.pricing_category = get_berth_product_pricing_category(order) order.product.save() order.save() profile_data = { "id": to_global_id(ProfileNode, order.customer.id), "first_name": order.lease.application.first_name, "last_name": order.lease.application.last_name, "primary_email": { "email": order.lease.application.email }, "primary_phone": { "phone": order.lease.application.phone_number }, } variables = {"orders": [to_global_id(OrderNode, order.id)]} with mock.patch( "requests.post", side_effect=mocked_response_profile(count=0, data=profile_data, use_edges=False), ), mock.patch.object(SMSNotificationService, "send", return_value=None) as mock_send_sms: executed = superuser_api_client.execute(RESEND_ORDER_MUTATION, input=variables) order.refresh_from_db() order.lease.refresh_from_db() assert executed["data"]["resendOrder"]["sentOrders"] == [str(order.id)] assert order.lease.status == LeaseStatus.OFFERED assert order.status == OrderStatus.OFFERED assert len(mail.outbox) == 1 assert (mail.outbox[0].subject == f"test order approved subject, event: {order.order_number}!") assert order.order_number in mail.outbox[0].body assert mail.outbox[0].to == ["*****@*****.**"] assert order.order_number in mail.outbox[0].alternatives[0][0] assert mail.outbox[0].alternatives[0][1] == "text/html" # Assert that the SMS is being sent payment_url = payment_provider.get_payment_email_url( order, lang=order.lease.application.language) sms_context = { "product_name": order.product.name, "due_date": format_date(order.due_date, locale=order.lease.application.language), "payment_url": payment_url, } mock_send_sms.assert_called_with( NotificationType.SMS_INVOICE_NOTICE, sms_context, order.customer_phone, language=order.lease.application.language, )
def test_approve_ap_order( api_client, order: Order, payment_provider, notification_template_orders_approved, ): order.status = OrderStatus.DRAFTED order.save(update_fields=["status"]) due_date = (today() + relativedelta(days=14)).date() email = "*****@*****.**" variables = { "dueDate": str(due_date), "orders": [{ "orderId": to_global_id(OrderNode, order.id), "email": email }], "profileToken": "mock_token", } with mock.patch( "customers.services.profile.requests.post", side_effect=mocked_response_profile(count=1, data=None, use_edges=False), ), mock.patch.object(SMSNotificationService, "send", return_value=None) as mock_send_sms: executed = api_client.execute(APPROVE_ORDER_MUTATION, input=variables) payment_url = payment_provider.get_payment_email_url( order, lang=order.lease.application.language) order = Order.objects.get(id=order.id) assert order.due_date == due_date # approving additional product order should not touch the lease assert order.lease.status != LeaseStatus.OFFERED assert order.lease.application.status != ApplicationStatus.OFFER_SENT # customer data should be filled assert len(order.customer_first_name) > 0 assert len(order.customer_last_name) > 0 assert len(order.customer_email) > 0 assert order.customer_address == MOCK_HKI_PROFILE_ADDRESS.get("address") assert order.customer_zip_code == MOCK_HKI_PROFILE_ADDRESS.get( "postal_code") assert order.customer_city == MOCK_HKI_PROFILE_ADDRESS.get("city") assert len(executed["data"]["approveOrders"]["failedOrders"]) == 0 assert len(mail.outbox) == 1 assert (mail.outbox[0].subject == f"test order approved subject, event: {order.order_number}!") assert mail.outbox[0].body == f"{ order.order_number } { payment_url }" assert mail.outbox[0].to == [email] assert mail.outbox[0].alternatives == [ (f"<b>{ order.order_number } { payment_url }</b>", "text/html") ] product_name = ", ".join([ str(ProductServiceType(order_line.product.service).label) for order_line in order.order_lines.all() ]) # Assert that the SMS is being sent sms_context = { "product_name": product_name, "due_date": format_date(order.due_date, locale=order.lease.application.language), "payment_url": payment_url, } mock_send_sms.assert_called_with( NotificationType.SMS_INVOICE_NOTICE, sms_context, order.customer_phone, language=order.lease.application.language, )
def test_approve_order( api_client, order: Order, payment_provider, notification_template_orders_approved, ): order.status = OrderStatus.DRAFTED order.save(update_fields=["status"]) due_date = (today() + relativedelta(days=14)).date() variables = { "dueDate": due_date, "orders": [{ "orderId": to_global_id(OrderNode, order.id), "email": order.lease.application.email, }], } phone = Faker(["fi_FI"]).phone_number() order.customer_phone = phone order.save() with mock.patch( "customers.services.profile.requests.post", side_effect=mocked_response_profile(count=1, data=None, use_edges=False), ), mock.patch.object(SMSNotificationService, "send", return_value=None) as mock_send_sms: executed = api_client.execute(APPROVE_ORDER_MUTATION, input=variables) payment_url = payment_provider.get_payment_email_url( order, lang=order.lease.application.language) order = Order.objects.get(id=order.id) assert order.due_date == due_date assert order.lease.status == LeaseStatus.OFFERED assert order.lease.application.status == ApplicationStatus.OFFER_SENT assert len(executed["data"]["approveOrders"]["failedOrders"]) == 0 assert len(mail.outbox) == 1 assert (mail.outbox[0].subject == f"test order approved subject, event: {order.order_number}!") assert mail.outbox[0].body == f"{ order.order_number } { payment_url }" assert mail.outbox[0].to == [order.lease.application.email] assert mail.outbox[0].alternatives == [ (f"<b>{ order.order_number } { payment_url }</b>", "text/html") ] # Assert that the SMS is being sent sms_context = { "product_name": order.product.name, "due_date": format_date(order.due_date, locale=order.lease.application.language), "payment_url": payment_url, } mock_send_sms.assert_called_with( NotificationType.SMS_INVOICE_NOTICE, sms_context, phone, language=order.lease.application.language, )