Example #1
0
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")
    ]
Example #2
0
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.",
    }
Example #3
0
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
Example #4
0
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
Example #7
0
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
Example #9
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,
    )
Example #13
0
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,
    )
Example #14
0
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,
    )