Esempio n. 1
0
    def mutate_and_get_payload(cls, root, info, **input):
        order_number = input.get("order_number", None)
        try:
            order = Order.objects.get(order_number=order_number)
            if order.status != OrderStatus.OFFERED:
                raise VenepaikkaGraphQLError(
                    _("The order is not valid anymore") +
                    f": {OrderStatus(order.status).label}")
            application = order.lease.application if order.lease else None
            if (isinstance(application, WinterStorageApplication)
                    and application.area_type == ApplicationAreaType.UNMARKED):
                raise VenepaikkaGraphQLError(
                    _("Cannot cancel Unmarked winter storage order"))
            order.set_status(OrderStatus.REJECTED,
                             _("Order rejected by customer"))
            order.invalidate_tokens()
            # annotations aren’t reloaded if using refresh_from_db, so use get() since we need
            # to have the updated value of rejected_at in the notice
            order = Order.objects.get(pk=order.pk)
            send_cancellation_notice(order)
        except (
                Order.DoesNotExist,
                ValidationError,
                AnymailError,
                OSError,
        ) as e:
            raise VenepaikkaGraphQLError(e)

        return CancelOrderMutation()
    def mutate_and_get_payload(cls, root, info, **input):
        pier = get_node_from_global_id(
            info, input.pop("id"), only_type=PierNode, nullable=False,
        )

        if input.get("harbor_id"):
            harbor = get_node_from_global_id(
                info, input.pop("harbor_id"), only_type=HarborNode, nullable=False,
            )
            input["harbor"] = harbor

        boat_types = set()
        for boat_type_id in input.pop("suitable_boat_types", []):
            try:
                boat_type = BoatType.objects.get(pk=boat_type_id)
            except BoatType.DoesNotExist as e:
                raise VenepaikkaGraphQLError(e)
            boat_types.add(boat_type)

        try:
            update_object(pier, input)
            pier.suitable_boat_types.set(boat_types)
        except IntegrityError as e:
            raise VenepaikkaGraphQLError(e)

        return UpdatePierMutation(pier=pier)
Esempio n. 3
0
    def mutate_and_get_payload(cls, root, info, application_id, new_berth_id,
                               **input):
        try:
            application = get_node_from_global_id(
                info,
                application_id,
                only_type=BerthApplicationNode,
                nullable=False)

            if not application.customer:
                raise VenepaikkaGraphQLError(
                    _("Application must be connected to a customer"))

            if not application.berth_switch:
                raise VenepaikkaGraphQLError(
                    _("Application must be a switch application"))

            new_berth = get_node_from_global_id(info,
                                                new_berth_id,
                                                only_type=BerthNode,
                                                nullable=False)
            if old_lease_id := input.get("old_lease_id"):
                old_lease = get_node_from_global_id(info,
                                                    old_lease_id,
                                                    only_type=BerthLeaseNode,
                                                    nullable=False)
            else:
    def mutate_and_get_payload(cls, root, info, **input):
        profile = get_node_from_global_id(info,
                                          input.pop("id"),
                                          only_type=ProfileNode,
                                          nullable=False)

        delete_organization = input.pop("delete_organization", False)
        if delete_organization:
            if "organization" in input:
                raise VenepaikkaGraphQLError(
                    _("You cannot pass deleteOrganization: true and organization input"
                      ))
            if not profile.organization:
                raise VenepaikkaGraphQLError(
                    _("The passed Profile is not associated with an Organization"
                      ))
            profile.organization.delete()
            profile.refresh_from_db()
        elif "organization" in input:
            Organization.objects.update_or_create(
                customer=profile, defaults=input.pop("organization"))
            profile.refresh_from_db()

        try:
            update_object(profile, input)
        except ValidationError as e:
            # Flatten all the error messages on a single list
            errors = sum(e.message_dict.values(), [])
            raise VenepaikkaGraphQLError(errors)

        return UpdateBerthServicesProfileMutation(profile=profile)
    def mutate_and_get_payload(cls, root, info, **input):
        try:
            order = Order.objects.get(order_number=input.get("order_number"))
        except Order.DoesNotExist:
            raise VenepaikkaGraphQLError(_("No order found for given order number"))

        try:
            contract = order.lease.contract
        except Exception:
            raise VenepaikkaGraphQLError(_("No contract found for given order"))

        try:
            URLValidator()(input.get("return_url"))
        except ValidationError:
            raise VenepaikkaGraphQLError(_("return_url is not a valid URL"))

        auth_method_identifiers = map(
            lambda auth_method: auth_method["identifier"],
            get_contract_service().get_auth_methods(),
        )
        if input.get("auth_service") not in auth_method_identifiers:
            raise VenepaikkaGraphQLError(
                _("auth_service is not a supported authentication service")
            )

        signing_url = get_contract_service().fulfill_contract(
            contract, input.get("auth_service"), input.get("return_url"),
        )
        return FulfillContractMutation(signing_url=signing_url)
Esempio n. 6
0
    def mutate_and_get_payload(cls, root, info, **input):
        if input.get("customer_id") and input.get("lease_id"):
            raise VenepaikkaGraphQLError(
                _("Cannot receive both Lease and Customer"))

        # TODO: until the price input is added, the customer input won't have an effect
        # _customer = input.pop("customer_id", None)
        input.pop("customer_id", None)

        if lease_id := input.pop("lease_id", None):
            lease = None
            try:
                lease = get_node_from_global_id(info,
                                                lease_id,
                                                BerthLeaseNode,
                                                nullable=True)
            # If a different node type is received get_node raises an assertion error
            # when trying to validate the type
            except AssertionError:
                lease = get_node_from_global_id(info,
                                                lease_id,
                                                WinterStorageLeaseNode,
                                                nullable=True)
            finally:
                if not lease:
                    raise VenepaikkaGraphQLError(
                        _("Lease with the given ID does not exist"))
                input["lease"] = lease
                input["customer"] = lease.customer
    def validate_application_status(cls, application, info, input):
        if application.status != ApplicationStatus.PENDING:
            if is_customer(info.context.user):
                raise VenepaikkaGraphQLError(
                    _("Cannot modify the application once it has been processed"
                      ))

            # If the input receives explicitly customerId: None
            if "customer_id" in input and input.get("customer_id") is None:
                raise VenepaikkaGraphQLError(
                    _("Customer cannot be disconnected from processed applications"
                      ))
def remove_boat_certificates(certificates, boat):
    try:
        for cert_id in certificates:
            cert_id = from_global_id(cert_id)
            BoatCertificate.objects.get(pk=cert_id, boat=boat).delete()
    except BoatCertificate.DoesNotExist as e:
        raise VenepaikkaGraphQLError(e)
Esempio n. 9
0
    def resolve_berths(self,
                       info,
                       harbor: GlobalID = None,
                       pier: GlobalID = None,
                       min_width: Decimal = 0,
                       min_length: Decimal = 0,
                       **kwargs):
        if pier and harbor:
            raise VenepaikkaGraphQLError(
                _("Cannot pass both pier and harbor filters"))

        filters = Q()
        if harbor:
            filters &= Q(pier__harbor_id=from_global_id(harbor, HarborNode))
        if pier:
            filters &= Q(pier_id=from_global_id(pier, PierNode))
        if min_width:
            filters &= Q(berth_type__width__gte=min_width)
        if min_length:
            filters &= Q(berth_type__length__gte=min_length)
        if "is_available" in kwargs:
            filters &= Q(is_available=kwargs.get("is_available"))
        if "is_invoiceable" in kwargs:
            filters &= Q(is_invoiceable=kwargs.get("is_invoiceable"))

        return info.context.berth_loader.load_many(
            keys=Berth.objects.filter(filters).values_list("id", flat=True))
Esempio n. 10
0
    def mutate_and_get_payload(cls, root, info, offer_number, is_accepted,
                               **input):
        offer = BerthSwitchOffer.objects.get(offer_number=offer_number)
        if is_accepted:
            if offer.status == OfferStatus.ACCEPTED:
                # do not proceed with db updates in exchange_berth_for_lease
                raise VenepaikkaGraphQLError(_("Offer is already accepted"))
            offer.set_status(OfferStatus.ACCEPTED)

            old_lease, new_lease = exchange_berth_for_lease(
                old_lease=offer.lease,
                new_berth=offer.berth,
                switch_date=max(today().date(), offer.lease.start_date),
                old_lease_comment=_(
                    "Lease terminated due to a berth switch offer"),
                new_lease_comment=_("Lease created from a berth switch offer"),
            )
            new_lease.application = offer.application
            new_lease.save()
            if old_lease.order:
                new_lease.orders.add(old_lease.order)
        else:
            # Reject offer
            offer.set_status(OfferStatus.REJECTED)

        return AcceptBerthSwitchOfferMutation()
Esempio n. 11
0
    def mutate_and_get_payload(cls, root, info, **input):
        order_number = input.get("order_number", None)
        try:
            order = Order.objects.get(order_number=order_number)
            if order.status not in (OrderStatus.OFFERED, OrderStatus.REJECTED):
                raise VenepaikkaGraphQLError(
                    _("The order is not valid anymore") +
                    f": {OrderStatus(order.status).label}")
            payment_url = get_payment_provider(
                info.context,
                ui_return_url=settings.VENE_UI_RETURN_URL).initiate_payment(
                    order)
        except Order.DoesNotExist as e:
            raise VenepaikkaGraphQLError(e)

        return ConfirmPaymentMutation(url=payment_url)
def add_map_files(model, map_files, instance):
    try:
        for map_file in map_files:
            map_instance = model(map_file=map_file)
            instance.maps.add(map_instance, bulk=False)
    except IntegrityError as e:
        raise VenepaikkaGraphQLError(e)
Esempio n. 13
0
    def mutate_and_get_payload(cls, root, info, order_id, **input):
        profile_token = input.get("profile_token", None)
        try:
            order = get_node_from_global_id(info,
                                            order_id,
                                            OrderNode,
                                            nullable=False)
            refund = get_payment_provider(info.context).initiate_refund(order)

            if profile_token:
                # order.customer_email and order.customer_phone could be stale, if contact
                # info in profile service has been changed.
                profile = fetch_order_profile(order, profile_token)
                update_order_from_profile(order, profile)

            send_refund_notice(order)
        except (
                AnymailError,
                OSError,
                Order.DoesNotExist,
                ValidationError,
                VenepaikkaGraphQLError,
                VenepaikkaPaymentError,
        ) as e:
            # If there's an error with either the validated data or the VismaPay service
            raise VenepaikkaGraphQLError(str(e)) from e

        return RefundOrderMutation(order_refund=refund)
    def mutate_and_get_payload(cls, root, info, **input):
        from customers.schema import ProfileNode

        application = get_node_from_global_id(
            info, input.pop("id"), only_type=WinterStorageApplicationNode)

        cls.validate_application_status(application, info, input)

        # This allows for getting explicit None values
        if "customer_id" in input:
            customer_id = input.pop("customer_id", None)

            if is_customer(info.context.user):
                raise VenepaikkaGraphQLError(
                    _("A customer cannot modify the customer connected to the application"
                      ))

            input["customer"] = get_node_from_global_id(info,
                                                        customer_id,
                                                        only_type=ProfileNode,
                                                        nullable=True)

        if remove_choices := input.pop("remove_choices", []):
            for choice_id in remove_choices:
                try:
                    choice = WinterStorageAreaChoice.objects.get(
                        id=from_global_id(
                            choice_id, node_type=WinterStorageAreaChoiceType))
                    choice.delete()
                except WinterStorageAreaChoice.DoesNotExist:
                    pass
Esempio n. 15
0
def return_queryset_if_user_has_permissions(queryset,
                                            user,
                                            *models,
                                            customer_queryset=None):
    """
    Checks whether the user has permissions to access the queryset.

    1. If the passed queryset is falsy, we return None.
    2. If the user making the request is a customer, the elements on the
        queryset belonging to it are returned.
    4. If the user is not a customer, but the user has permissions to view
        the necessary models, the whole queryset is returned.
    5. If the user has no permissions to view it, an error is raised.

    :param queryset: Django QuerySet being accessed
    :param user: the user from the current request / session
    :param models: Django models that user has to have permissions to
    :param customer_queryset: [Optional] If the customer property is nested on the model,
    a custom filtered queryset can be passed
    :return: None | Django QuerySet | Exception raised
    """
    from users.utils import is_customer, user_has_view_permission

    if is_customer(user):
        if customer_queryset:
            return customer_queryset
        return queryset.filter(customer__user=user)

    if user_has_view_permission(*models)(user):
        return queryset

    raise VenepaikkaGraphQLError(
        _("You do not have permission to perform this action."))
Esempio n. 16
0
def return_node_if_user_has_permissions(node, user, *models):
    """
    Checks whether the user has permissions to access this node / model.

    1. If the passed node is falsy, we return None.
    2. Otherwise, try to get the user this node belongs to (get_node_user)
    3. If the node belongs to the user making the request,
       the node / model is returned.
    4. If the node does not belong to the user, but the user has
       permissions to view the necessary models, the node / model
       is still returned.
    5. If the node does not belong to the user and the user has no
       permissions to view it, an error is raised.

    :param node: Graphene Node or Django Model being accessed
    :param user: the user from the current request / session
    :param models: Django models that user has to have permissions to
    :return: None | Django Model or Graphene Node | Exception raised
    """
    from users.utils import user_has_view_permission

    if not node:
        return None

    node_user = get_node_user(node)

    if (node_user
            and node_user == user) or user_has_view_permission(*models)(user):
        return node
    else:
        raise VenepaikkaGraphQLError(
            _("You do not have permission to perform this action."))
 def validate_switch_date(cls, switch_date):
     if isinstance(switch_date, datetime):
         switch_date = switch_date.date()
     if switch_date < date.today() - relativedelta(months=6):
         raise VenepaikkaGraphQLError(
             _("Switch date is more than 6 months in the past")
         )
Esempio n. 18
0
    def mutate_and_get_payload(cls, root, info, **input):
        try:
            product = BerthProduct.objects.create(**input)
        except (ValidationError, IntegrityError) as e:
            raise VenepaikkaGraphQLError(e)

        return CreateBerthProductMutation(berth_product=product)
 def validate_availability_level_id(cls, input):
     if availability_level_id := input.pop("availability_level_id", None):
         try:
             input["availability_level"] = AvailabilityLevel.objects.get(
                 pk=availability_level_id
             )
         except AvailabilityLevel.DoesNotExist as e:
             raise VenepaikkaGraphQLError(e)
    def mutate_and_get_payload(cls, root, info, **input):
        lease = get_node_from_global_id(
            info,
            input.pop("lease_id"),
            only_type=WinterStorageLeaseNode,
            nullable=False,
        )
        if lease.status != LeaseStatus.PAID:
            raise VenepaikkaGraphQLError(_("Lease must be in PAID status"))
        elif lease.application.area_type != ApplicationAreaType.UNMARKED:
            raise VenepaikkaGraphQLError(_("Lease must refer to unmarked area"))

        new_sticker_number = get_next_sticker_number(lease.start_date)
        lease.sticker_number = new_sticker_number
        lease.sticker_posted = None
        lease.save()

        return AssignNewStickerNumberMutation(sticker_number=new_sticker_number)
Esempio n. 21
0
    def mutate_and_get_payload(cls, root, info, orders, **input):

        successful_orders = []
        failed_orders = []

        for order_input in orders:
            order_id = order_input.pop("id")
            try:
                with transaction.atomic():
                    order = get_node_from_global_id(info,
                                                    order_id,
                                                    only_type=OrderNode,
                                                    nullable=False)
                    if lease_id := order_input.pop("lease_id", None):
                        lease = None
                        try:
                            lease = get_node_from_global_id(info,
                                                            lease_id,
                                                            BerthLeaseNode,
                                                            nullable=True)
                        # If a different node type is received get_node raises an assertion error
                        # when trying to validate the type
                        except AssertionError:
                            lease = get_node_from_global_id(
                                info,
                                lease_id,
                                WinterStorageLeaseNode,
                                nullable=True)
                        finally:
                            if not lease:
                                raise VenepaikkaGraphQLError(
                                    _("Lease with the given ID does not exist")
                                )
                            order_input["lease"] = lease

                    # handle case where order_input has both lease and status.
                    # set order status only after changing the lease, because setting order status
                    # usually triggers a change in lease status.
                    new_status = order_input.pop("status", None)
                    update_object(order, order_input)
                    if new_status:
                        order.set_status(new_status,
                                         _("Manually updated by admin"))

            except (
                    ValidationError,
                    IntegrityError,
                    VenepaikkaGraphQLError,
                    OrderStatusTransitionError,
            ) as e:
                failed_orders.append(FailedOrderType(id=order_id,
                                                     error=str(e)))
            else:
                successful_orders.append(order)
        return UpdateOrdersMutation(successful_orders=successful_orders,
                                    failed_orders=failed_orders)
    def lookup_application_and_customer(cls, info, input):
        from customers.schema import ProfileNode  # import here avoid circular import

        if application_id := input.pop("application_id", None):
            if "customer_id" in input:
                raise VenepaikkaGraphQLError(
                    _(
                        "Can not specify both application and customer when creating a new berth lease"
                    )
                )
            application: BerthApplication = get_node_from_global_id(
                info, application_id, only_type=BerthApplicationNode, nullable=False,
            )
            if not application.customer:
                raise VenepaikkaGraphQLError(
                    _("Application must be connected to an existing customer first")
                )
            input["application"] = application
            input["customer"] = application.customer
 def mutate_and_get_payload(cls, root, info, **input):
     winter_storage_place_type = get_node_from_global_id(
         info, input.get("id"), only_type=WinterStoragePlaceTypeNode, nullable=False,
     )
     if place_count := winter_storage_place_type.places.count():
         raise VenepaikkaGraphQLError(
             _(
                 f"Cannot delete WinterStoragePlaceType because it has {place_count} related places"
             )
         )
Esempio n. 24
0
 def mutate_and_get_payload(cls, root, info, **input):
     product = get_node_from_global_id(info,
                                       input.pop("id"),
                                       only_type=AdditionalProductNode,
                                       nullable=False)
     try:
         update_object(product, input)
     except (ValidationError, IntegrityError) as e:
         raise VenepaikkaGraphQLError(e)
     return UpdateAdditionalProductMutation(additional_product=product)
Esempio n. 25
0
 def mutate_and_get_payload(cls, root, info, **input):
     if AdditionalProduct.objects.filter(
             service=input.get("service"),
             period=input.get("period")).exists():
         raise VenepaikkaGraphQLWarning(
             _("Additional product already exists"))
     try:
         product = AdditionalProduct.objects.create(**input)
     except (ValidationError, IntegrityError) as e:
         raise VenepaikkaGraphQLError(e)
     return CreateAdditionalProductMutation(additional_product=product)
def delete_inactive_leases(lease_class, lookup, model_name):
    # Get all the leases related to the resource
    leases = lease_class.objects.filter(lookup)
    # If there's any active lease, raise an error
    if leases.filter(status=LeaseStatus.PAID).count() > 0:
        raise VenepaikkaGraphQLError(
            _(f"Cannot delete {model_name} because it has some related leases")
        )

    # Delete all the leases associated to the Harbor
    leases.delete()
    def mutate_and_get_payload(cls, root, info, **input):
        lease = get_node_from_global_id(
            info, input.pop("id"), only_type=WinterStorageLeaseNode, nullable=False,
        )
        application_id = input.get("application_id")

        if application_id:
            # If the application id was passed, raise an error if it doesn't exist
            application = get_node_from_global_id(
                info,
                application_id,
                only_type=WinterStorageApplicationNode,
                nullable=False,
            )
            if not application.customer:
                raise VenepaikkaGraphQLError(
                    _("Application must be connected to an existing customer first")
                )
            input["application"] = application
            input["customer"] = application.customer

        if input.get("boat_id", False):
            from customers.schema import BoatNode

            boat = get_node_from_global_id(
                info, input.pop("boat_id"), only_type=BoatNode, nullable=False,
            )

            if boat.owner.id != input["customer"].id:
                raise VenepaikkaGraphQLError(
                    _("Boat does not belong to the same customer as the Application")
                )

            input["boat"] = boat

        try:
            update_object(lease, input)
        except ValidationError as e:
            raise VenepaikkaGraphQLError(str(e))

        return UpdateWinterStorageLeaseMutation(winter_storage_lease=lease)
Esempio n. 28
0
def exchange_berth_for_lease(
    old_lease: BerthLease,
    new_berth: Berth,
    switch_date: date,
    old_lease_comment: str,
    new_lease_comment: str,
) -> (BerthLease, BerthLease):
    # Avoid circular imports
    from leases.models import BerthLease

    end_date = old_lease.end_date
    contract = None
    if hasattr(old_lease, "contract"):
        contract = old_lease.contract

    old_lease = terminate_lease(
        lease=old_lease, end_date=switch_date, send_notice=False,
    )
    if len(old_lease.comment) > 0:
        old_lease.comment += f"\n{old_lease_comment}"
    else:
        old_lease.comment = old_lease_comment
    old_lease.save(update_fields=["comment"])

    try:
        new_lease = BerthLease.objects.create(
            berth=new_berth,
            boat=old_lease.boat,
            customer=old_lease.customer,
            status=LeaseStatus.PAID,
            start_date=switch_date,
            end_date=end_date,
            comment=_(
                f"{new_lease_comment}\n"
                f"{_('Previous berth info')}:\n"
                f"{_('Harbor name')}: {old_lease.berth.pier.harbor.name}\n"
                f"{_('Pier ID')}: {old_lease.berth.pier.identifier}\n"
                f"{_('Berth number')}: {old_lease.berth.number}\n"
            ),
        )

        if contract:
            contract.lease = new_lease
            contract.save()
            old_lease.refresh_from_db()
            new_lease.refresh_from_db()

    except ValidationError as e:
        # Flatten all the error messages on a single list
        errors = sum(e.message_dict.values(), [])
        raise VenepaikkaGraphQLError(errors)

    return old_lease, new_lease
Esempio n. 29
0
    def mutate_and_get_payload(cls, root, info, **input):
        order_line = get_node_from_global_id(info,
                                             input.pop("id"),
                                             only_type=OrderLineNode,
                                             nullable=False)

        try:
            update_object(order_line, input)
        except (ValidationError, IntegrityError) as e:
            raise VenepaikkaGraphQLError(e)
        return UpdateOrderLineMutation(order_line=order_line,
                                       order=order_line.order)
def update_boat_certificates(certificates, info):
    try:
        for cert_input in certificates:
            cert = get_node_from_global_id(
                info,
                cert_input.pop("id"),
                only_type=BoatCertificateNode,
                nullable=False,
            )
            update_object(cert, cert_input)
    except IntegrityError as e:
        raise VenepaikkaGraphQLError(e)