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')