예제 #1
0
    def _initial_charge_timeout(self, order):
        ordering_client = OrderingClient()
        raw_order = ordering_client.get_order(order.order_id)

        # Setting all the items as Failed, set the whole order as failed
        # ordering_client.update_state(raw_order, 'Failed')
        ordering_client.update_items_state(raw_order, 'Failed')

        order.delete()
    def create(self, request):
        """
        Receives notifications from the ordering API when a new order is created
        :param request:
        :return:
        """
        user = request.user
        try:
            order = json.loads(request.body)
        except:
            return build_response(
                request, 400, 'The provided data is not a valid JSON object')

        client = OrderingClient()
        client.update_state(order, 'InProgress')

        try:
            # Check that the user has a billing address
            response = None

            om = OrderingManager()
            redirect_url = om.process_order(user, order)

            if redirect_url is not None:

                client.update_state(order, 'Pending')

                response = HttpResponse(
                    json.dumps({'redirectUrl': redirect_url}),
                    status=200,
                    mimetype='application/json; charset=utf-8')

            else:
                # All the order items are free so digital assets can be set as Completed
                digital_items = []
                order_model = Order.objects.get(order_id=order['id'])

                for item in order['orderItem']:
                    contract = order_model.get_item_contract(
                        item_id=item['id'])
                    if contract.offering.is_digital:
                        digital_items.append(item)

                client.update_items_state(order, 'Completed', digital_items)

                response = build_response(request, 200, 'OK')

        except OrderingError as e:
            response = build_response(request, 400, unicode(e.value))
            client.update_items_state(order, 'Failed')
        except Exception as e:
            response = build_response(request, 500,
                                      'Your order could not be processed')
            client.update_items_state(order, 'Failed')

        return response
    def create(self, request):
        # In case the user cancels the payment is necessary to update
        # the database in order to avoid an inconsistent state
        try:
            data = json.loads(request.body)
            order = Order.objects.get(pk=data['reference'])

            client = OrderingClient()
            raw_order = client.get_order(order.order_id)

            # Set the order to failed in the ordering API
            # Set all items as Failed, mark the whole order as Failed
            # client.update_state(raw_order, 'Failed')
            client.update_items_state(raw_order, 'Failed')

            order.delete()
        except:
            return build_response(request, 400, 'Invalid request')

        return build_response(request, 200, 'Ok')
    def create(self, request):

        order = None
        concept = None
        self.ordering_client = OrderingClient()
        try:
            # Extract payment information
            data = json.loads(request.body)

            if 'reference' not in data or 'paymentId' not in data or 'payerId' not in data:
                raise ValueError('Missing required field. It must contain reference, paymentId, and payerId')

            reference = data['reference']
            token = data['paymentId']
            payer_id = data['payerId']

            if not Order.objects.filter(pk=reference):
                raise ValueError('The provided reference does not identify a valid order')

            db = get_database_connection()

            # Uses an atomic operation to get and set the _lock value in the purchase
            # document
            pre_value = db.wstore_order.find_one_and_update(
                {'_id': ObjectId(reference)},
                {'$set': {'_lock': True}}
            )

            # If the value of _lock before setting it to true was true, means
            # that the time out function has acquired it previously so the
            # view ends
            if not pre_value or '_lock' in pre_value and pre_value['_lock']:
                raise PaymentError('The timeout set to process the payment has finished')

            order = Order.objects.get(pk=reference)
            raw_order = self.ordering_client.get_order(order.order_id)
            pending_info = order.pending_payment
            concept = pending_info.concept

            # If the order state value is different from pending means that
            # the timeout function has completely ended before acquiring the resource
            # so _lock is set to false and the view ends
            if pre_value['state'] != 'pending':
                db.wstore_order.find_one_and_update(
                    {'_id': ObjectId(reference)},
                    {'$set': {'_lock': False}}
                )
                raise PaymentError('The timeout set to process the payment has finished')

            # Check that the request user is authorized to end the payment
            if request.user.userprofile.current_organization != order.owner_organization or request.user != order.customer:
                raise PaymentError('You are not authorized to execute the payment')

            transactions = pending_info.transactions

            # Get the payment client
            # Load payment client
            cln_str = settings.PAYMENT_CLIENT
            client_package, client_class = cln_str.rsplit('.', 1)

            payment_client = getattr(importlib.import_module(client_package), client_class)

            # build the payment client
            client = payment_client(order)
            order.sales_ids = client.end_redirection_payment(token, payer_id)
            order.save()

            charging_engine = ChargingEngine(order)
            charging_engine.end_charging(transactions, pending_info.free_contracts, concept)

        except Exception as e:

            # Rollback the purchase if existing
            if order is not None and raw_order is not None:
                if concept == 'initial':
                    # Set the order to failed in the ordering API
                    # Set all items as Failed, mark the whole order as failed
                    self.ordering_client.update_items_state(raw_order, 'Failed')
                    order.delete()
                else:
                    order.state = 'paid'
                    order.pending_payment = None
                    order.save()

            expl = ' due to an unexpected error'
            err_code = 500
            if isinstance(e, PaymentError) or isinstance(e, ValueError):
                expl = ': ' + unicode(e)
                err_code = 403

            msg = 'The payment has been canceled' + expl
            return build_response(request, err_code, msg)

        # Change states of TMForum resources (orderItems, products, etc)
        # depending on the concept of the payment

        states_processors = {
            'initial': self._set_initial_states,
            'recurring': self._set_renovation_states,
            'usage': self._set_renovation_states
        }
        # Include the free contracts as transactions in order to activate them
        ext_transactions = deepcopy(transactions)
        ext_transactions.extend([{'item': contract.item_id} for contract in pending_info.free_contracts])

        states_processors[concept](ext_transactions, raw_order, order)

        # _lock is set to false
        db.wstore_order.find_one_and_update(
            {'_id': ObjectId(reference)},
            {'$set': {'_lock': False}}
        )

        return build_response(request, 200, 'Ok')