示例#1
0
    def _checkout(self, basket, payment_processor):
        """Perform checkout operations for the given basket.

        If the contents of the basket are free, places an order immediately. Otherwise,
        performs any operations necessary to prepare for payment.

        To prevent stale items from ending up in a basket at checkout, baskets should
        always be frozen during checkout. Baskets with a status of 'Frozen' or 'Submitted'
        are not retrieved when fetching a basket for the user.

        Arguments:
            basket (Basket): The basket on which to perform checkout operations.
            payment_processor (class): An instance of the payment processor class corresponding
                to the payment processor the user will visit to pay for the items in their basket.

        Returns:
            dict: Response data.
        """
        basket.freeze()
        logger.info(
            u"Froze basket [%d]",
            basket.id,
        )

        response_data = self._generate_basic_response(basket)

        if basket.total_excl_tax == AC.FREE:
            order_metadata = data.get_order_metadata(basket)

            logger.info(
                u"Preparing to place order [%s] for the contents of basket [%d]",
                order_metadata[AC.KEYS.ORDER_NUMBER],
                basket.id,
            )

            # Place an order, attempting to fulfill it immediately
            order = self.handle_order_placement(
                order_number=order_metadata[AC.KEYS.ORDER_NUMBER],
                user=basket.owner,
                basket=basket,
                shipping_address=None,
                shipping_method=order_metadata[AC.KEYS.SHIPPING_METHOD],
                shipping_charge=order_metadata[AC.KEYS.SHIPPING_CHARGE],
                billing_address=None,
                order_total=order_metadata[AC.KEYS.ORDER_TOTAL],
            )

            # Note: Our order serializer could be used here, but in an effort to pare down the information
            # returned by this endpoint, simply returning the order number will suffice for now.
            response_data[AC.KEYS.ORDER] = {AC.KEYS.ORDER_NUMBER: order.number}
        else:
            payment_data = {
                AC.KEYS.PAYMENT_PROCESSOR_NAME: payment_processor.NAME,
                AC.KEYS.PAYMENT_FORM_DATA: payment_processor.get_transaction_parameters(basket),
                AC.KEYS.PAYMENT_PAGE_URL: payment_processor.payment_page_url,
            }

            response_data[AC.KEYS.PAYMENT_DATA] = payment_data

        return response_data
示例#2
0
    def create_order_for_invoice(self, basket, coupon_id):
        """Creates an order from the basket and invokes the invoice payment processor."""
        order_metadata = data_api.get_order_metadata(basket)

        response_data = {
            AC.KEYS.COUPON_ID: coupon_id,
            AC.KEYS.BASKET_ID: basket.id,
            AC.KEYS.ORDER: None,
            AC.KEYS.PAYMENT_DATA: None,
        }
        basket.freeze()

        # Invoice payment processor invocation.
        payment_processor = InvoicePayment
        payment_processor().handle_processor_response(response={},
                                                      basket=basket)
        response_data[AC.KEYS.PAYMENT_DATA] = {
            AC.KEYS.PAYMENT_PROCESSOR_NAME: 'Invoice'
        }

        order = self.handle_order_placement(
            order_number=order_metadata[AC.KEYS.ORDER_NUMBER],
            user=basket.owner,
            basket=basket,
            shipping_address=None,
            shipping_method=order_metadata[AC.KEYS.SHIPPING_METHOD],
            shipping_charge=order_metadata[AC.KEYS.SHIPPING_CHARGE],
            billing_address=None,
            order_total=order_metadata[AC.KEYS.ORDER_TOTAL])

        response_data[AC.KEYS.ORDER] = order.id
        logger.info('Created new order number [%s] from basket [%d]',
                    order_metadata[AC.KEYS.ORDER_NUMBER], basket.id)

        return response_data
示例#3
0
    def get(self, request):
        """
        Looks up the passed code and adds the matching product to a basket,
        then applies the voucher and if the basket total is FREE places the order and
        enrolls the user in the course.
        """
        template_name = 'coupons/offer.html'
        code = request.GET.get('code', None)

        if not code:
            return render(request, template_name,
                          {'error': _('Code not provided')})

        voucher, product = get_voucher(code=code)
        valid_voucher, msg = voucher_is_valid(voucher, product, request)
        if not valid_voucher:
            return render(request, template_name, {'error': msg})

        basket = self._prepare_basket(request.site, request.user, product,
                                      voucher)
        if basket.total_excl_tax == AC.FREE:
            basket.freeze()
            order_metadata = data_api.get_order_metadata(basket)

            logger.info(
                u"Preparing to place order [%s] for the contents of basket [%d]",
                order_metadata[AC.KEYS.ORDER_NUMBER],
                basket.id,
            )

            # Place an order. If order placement succeeds, the order is committed
            # to the database so that it can be fulfilled asynchronously.
            order = self.handle_order_placement(
                order_number=order_metadata[AC.KEYS.ORDER_NUMBER],
                user=basket.owner,
                basket=basket,
                shipping_address=None,
                shipping_method=order_metadata[AC.KEYS.SHIPPING_METHOD],
                shipping_charge=order_metadata[AC.KEYS.SHIPPING_CHARGE],
                billing_address=None,
                order_total=order_metadata[AC.KEYS.ORDER_TOTAL],
            )
        else:
            return render(
                request, template_name, {
                    'error':
                    _('Basket total not $0, current value = ${basket_price}'.
                      format(basket_price=basket.total_excl_tax))
                })

        if order.status is ORDER.COMPLETE:
            return HttpResponseRedirect(get_lms_url(''))
        else:
            logger.error('Order was not completed [%s]', order.id)
            return render(request, template_name,
                          {'error': _('Error when trying to redeem code')})
示例#4
0
    def get(self, request):
        """
        Looks up the passed code and adds the matching product to a basket,
        then applies the voucher and if the basket total is FREE places the order and
        enrolls the user in the course.
        """
        template_name = 'coupons/offer.html'
        code = request.GET.get('code', None)

        if not code:
            return render(request, template_name, {'error': _('Code not provided')})

        voucher, product = get_voucher(code=code)
        valid_voucher, msg = voucher_is_valid(voucher, product, request)
        if not valid_voucher:
            return render(request, template_name, {'error': msg})

        basket = self._prepare_basket(request.site, request.user, product, voucher)
        if basket.total_excl_tax == AC.FREE:
            basket.freeze()
            order_metadata = data_api.get_order_metadata(basket)

            logger.info(
                u"Preparing to place order [%s] for the contents of basket [%d]",
                order_metadata[AC.KEYS.ORDER_NUMBER],
                basket.id,
            )

            # Place an order. If order placement succeeds, the order is committed
            # to the database so that it can be fulfilled asynchronously.
            order = self.handle_order_placement(
                order_number=order_metadata[AC.KEYS.ORDER_NUMBER],
                user=basket.owner,
                basket=basket,
                shipping_address=None,
                shipping_method=order_metadata[AC.KEYS.SHIPPING_METHOD],
                shipping_charge=order_metadata[AC.KEYS.SHIPPING_CHARGE],
                billing_address=None,
                order_total=order_metadata[AC.KEYS.ORDER_TOTAL],
            )
        else:
            return render(
                request,
                template_name,
                {'error': _('Basket total not $0, current value = ${basket_price}'.format(
                    basket_price=basket.total_excl_tax
                ))}
            )

        if order.status is ORDER.COMPLETE:
            return HttpResponseRedirect(get_lms_url(''))
        else:
            logger.error('Order was not completed [%s]', order.id)
            return render(request, template_name, {'error': _('Error when trying to redeem code')})
示例#5
0
    def create_order_for_invoice(self,
                                 basket,
                                 coupon_id,
                                 client,
                                 invoice_data=None,
                                 request=None):
        """Creates an order from the basket and invokes the invoice payment processor."""
        order_metadata = data_api.get_order_metadata(basket)

        response_data = {
            'coupon_id': coupon_id,
            'id': basket.id,
            'order': None,
            'payment_data': None,
        }
        basket.freeze()

        order = self.handle_order_placement(
            basket=basket,
            billing_address=None,
            order_number=order_metadata['number'],
            order_total=order_metadata['total'],
            request=request,
            shipping_address=None,
            shipping_charge=order_metadata['shipping_charge'],
            shipping_method=order_metadata['shipping_method'],
            user=basket.owner)

        # Invoice payment processor invocation.
        payment_processor = InvoicePayment
        payment_processor().handle_processor_response(
            response={},
            order=order,
            business_client=client,
            invoice_data=invoice_data)
        response_data['payment_data'] = {'payment_processor_name': 'Invoice'}

        response_data['order'] = order.id
        logger.info('Created new order number [%s] from basket [%d]',
                    order_metadata['number'], basket.id)

        return response_data
示例#6
0
    def place_free_order(self, basket, request=None):
        """Fulfill a free order.

        Arguments:
            basket(Basket): the free basket.

        Returns:
            order(Order): the fulfilled order.

        Raises:
            BasketNotFreeError: if the basket is not free.
        """

        if basket.total_incl_tax != 0:
            raise BasketNotFreeError

        basket.freeze()

        order_metadata = data_api.get_order_metadata(basket)

        logger.info(
            'Preparing to place order [%s] for the contents of basket [%d]',
            order_metadata['number'],
            basket.id,
        )

        # Place an order. If order placement succeeds, the order is committed
        # to the database so that it can be fulfilled asynchronously.
        order = self.handle_order_placement(
            basket=basket,
            billing_address=None,
            order_number=order_metadata['number'],
            order_total=order_metadata['total'],
            request=request,
            shipping_address=None,
            shipping_charge=order_metadata['shipping_charge'],
            shipping_method=order_metadata['shipping_method'],
            user=basket.owner
        )

        return order
示例#7
0
    def create_order_for_invoice(self, basket, coupon_id, client, invoice_data=None):
        """Creates an order from the basket and invokes the invoice payment processor."""
        order_metadata = data_api.get_order_metadata(basket)

        response_data = {
            'coupon_id': coupon_id,
            'id': basket.id,
            'order': None,
            'payment_data': None,
        }
        basket.freeze()

        order = self.handle_order_placement(
            basket=basket,
            billing_address=None,
            order_number=order_metadata['number'],
            order_total=order_metadata['total'],
            request=self.request,
            shipping_address=None,
            shipping_charge=order_metadata['shipping_charge'],
            shipping_method=order_metadata['shipping_method'],
            user=basket.owner
        )

        # Invoice payment processor invocation.
        payment_processor = InvoicePayment
        payment_processor(self.request.site).handle_processor_response(
            response={}, order=order, business_client=client, invoice_data=invoice_data
        )
        response_data['payment_data'] = {
            'payment_processor_name': 'Invoice'
        }

        response_data['order'] = order.id
        logger.info(
            'Created new order number [%s] from basket [%d]',
            order_metadata['number'],
            basket.id
        )

        return response_data
示例#8
0
    def place_free_order(self, basket, request=None):
        """Fulfill a free order.

        Arguments:
            basket(Basket): the free basket.

        Returns:
            order(Order): the fulfilled order.

        Raises:
            BasketNotFreeError: if the basket is not free.
        """

        if basket.total_incl_tax != 0:
            raise BasketNotFreeError

        basket.freeze()

        order_metadata = data_api.get_order_metadata(basket)

        logger.info(
            'Preparing to place order [%s] for the contents of basket [%d]',
            order_metadata['number'],
            basket.id,
        )

        # Place an order. If order placement succeeds, the order is committed
        # to the database so that it can be fulfilled asynchronously.
        order = self.handle_order_placement(
            basket=basket,
            billing_address=None,
            order_number=order_metadata['number'],
            order_total=order_metadata['total'],
            request=request,
            shipping_address=None,
            shipping_charge=order_metadata['shipping_charge'],
            shipping_method=order_metadata['shipping_method'],
            user=basket.owner
        )

        return order
示例#9
0
    def place_free_order(self, basket):
        """Fulfill a free order.

        Arguments:
            basket(Basket): the free basket.

        Returns:
            order(Order): the fulfilled order.

        Raises:
            BasketNotFreeError: if the basket is not free.
        """

        if basket.total_incl_tax != AC.FREE:
            raise BasketNotFreeError

        basket.freeze()

        order_metadata = data_api.get_order_metadata(basket)

        logger.info(
            'Preparing to place order [%s] for the contents of basket [%d]',
            order_metadata[AC.KEYS.ORDER_NUMBER],
            basket.id,
        )

        # Place an order. If order placement succeeds, the order is committed
        # to the database so that it can be fulfilled asynchronously.
        order = self.handle_order_placement(
            order_number=order_metadata[AC.KEYS.ORDER_NUMBER],
            user=basket.owner,
            basket=basket,
            shipping_address=None,
            shipping_method=order_metadata[AC.KEYS.SHIPPING_METHOD],
            shipping_charge=order_metadata[AC.KEYS.SHIPPING_CHARGE],
            billing_address=None,
            order_total=order_metadata[AC.KEYS.ORDER_TOTAL],
        )

        return order
示例#10
0
    def place_free_order(self, basket):
        """Fulfill a free order.

        Arguments:
            basket(Basket): the free basket.

        Returns:
            order(Order): the fulfilled order.

        Raises:
            BasketNotFreeError: if the basket is not free.
        """

        if basket.total_incl_tax != AC.FREE:
            raise BasketNotFreeError

        basket.freeze()

        order_metadata = data_api.get_order_metadata(basket)

        logger.info(
            'Preparing to place order [%s] for the contents of basket [%d]',
            order_metadata[AC.KEYS.ORDER_NUMBER],
            basket.id,
        )

        # Place an order. If order placement succeeds, the order is committed
        # to the database so that it can be fulfilled asynchronously.
        order = self.handle_order_placement(
            order_number=order_metadata[AC.KEYS.ORDER_NUMBER],
            user=basket.owner,
            basket=basket,
            shipping_address=None,
            shipping_method=order_metadata[AC.KEYS.SHIPPING_METHOD],
            shipping_charge=order_metadata[AC.KEYS.SHIPPING_CHARGE],
            billing_address=None,
            order_total=order_metadata[AC.KEYS.ORDER_TOTAL],
        )

        return order
示例#11
0
    def create_order_for_invoice(self, basket, coupon_id, client, invoice_data=None):
        """Creates an order from the basket and invokes the invoice payment processor."""
        order_metadata = data_api.get_order_metadata(basket)

        response_data = {
            AC.KEYS.COUPON_ID: coupon_id,
            AC.KEYS.BASKET_ID: basket.id,
            AC.KEYS.ORDER: None,
            AC.KEYS.PAYMENT_DATA: None,
        }
        basket.freeze()

        order = self.handle_order_placement(
            order_number=order_metadata[AC.KEYS.ORDER_NUMBER],
            user=basket.owner,
            basket=basket,
            shipping_address=None,
            shipping_method=order_metadata[AC.KEYS.SHIPPING_METHOD],
            shipping_charge=order_metadata[AC.KEYS.SHIPPING_CHARGE],
            billing_address=None,
            order_total=order_metadata[AC.KEYS.ORDER_TOTAL]
        )

        # Invoice payment processor invocation.
        payment_processor = InvoicePayment
        payment_processor().handle_processor_response(
            response={}, order=order, business_client=client, invoice_data=invoice_data
        )
        response_data[AC.KEYS.PAYMENT_DATA] = {
            AC.KEYS.PAYMENT_PROCESSOR_NAME: 'Invoice'
        }

        response_data[AC.KEYS.ORDER] = order.id
        logger.info(
            'Created new order number [%s] from basket [%d]',
            order_metadata[AC.KEYS.ORDER_NUMBER],
            basket.id
        )

        return response_data
示例#12
0
    def _checkout(self, basket, payment_processor):
        """Perform checkout operations for the given basket.

        If the contents of the basket are free, places an order immediately. Otherwise,
        performs any operations necessary to prepare for payment.

        To prevent stale items from ending up in a basket at checkout, baskets should
        always be frozen during checkout. Baskets with a status of 'Frozen' or 'Submitted'
        are not retrieved when fetching a basket for the user.

        Arguments:
            basket (Basket): The basket on which to perform checkout operations.
            payment_processor (class): An instance of the payment processor class corresponding
                to the payment processor the user will visit to pay for the items in their basket.

        Returns:
            dict: Response data.
        """
        basket.freeze()

        audit_log(
            'basket_frozen',
            amount=basket.total_excl_tax,
            basket_id=basket.id,
            currency=basket.currency,
            user_id=basket.owner.id
        )

        response_data = self._generate_basic_response(basket)

        if basket.total_excl_tax == AC.FREE:
            order_metadata = data_api.get_order_metadata(basket)

            logger.info(
                'Preparing to place order [%s] for the contents of basket [%d]',
                order_metadata[AC.KEYS.ORDER_NUMBER],
                basket.id,
            )

            # Place an order. If order placement succeeds, the order is committed
            # to the database so that it can be fulfilled asynchronously.
            order = self.handle_order_placement(
                order_number=order_metadata[AC.KEYS.ORDER_NUMBER],
                user=basket.owner,
                basket=basket,
                shipping_address=None,
                shipping_method=order_metadata[AC.KEYS.SHIPPING_METHOD],
                shipping_charge=order_metadata[AC.KEYS.SHIPPING_CHARGE],
                billing_address=None,
                order_total=order_metadata[AC.KEYS.ORDER_TOTAL],
            )

            # Note: Our order serializer could be used here, but in an effort to pare down the information
            # returned by this endpoint, simply returning the order number will suffice for now.
            response_data[AC.KEYS.ORDER] = {AC.KEYS.ORDER_NUMBER: order.number}
        else:
            parameters = payment_processor.get_transaction_parameters(basket, request=self.request)
            payment_page_url = parameters.pop('payment_page_url')

            response_data[AC.KEYS.PAYMENT_DATA] = {
                AC.KEYS.PAYMENT_PROCESSOR_NAME: payment_processor.NAME,
                AC.KEYS.PAYMENT_FORM_DATA: parameters,
                AC.KEYS.PAYMENT_PAGE_URL: payment_page_url,
            }

        return response_data