def read(self, request, reference): purchase = None try: token = request.GET.get('token') payer_id = request.GET.get('PayerID', '') db = get_database_connection() # Uses an atomic operation to get and set the _lock value in the purchase # document pre_value = db.wstore_purchase.find_and_modify( query={'_id': ObjectId(reference)}, update={'$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 '_lock' in pre_value and pre_value['_lock']: raise Exception('') purchase = Purchase.objects.get(ref=reference) # Check that the request user is authorized to end the payment if request.user.userprofile.current_organization != purchase.owner_organization: raise Exception() # If the purchase state value is different from pending means that # the timeout function has completely ended before acquire the resource # so _lock is set to false and the view ends if purchase.state != 'pending': db.wstore_purchase.find_and_modify( query={'_id': ObjectId(reference)}, update={'$set': {'_lock': False}} ) raise Exception('') pending_info = purchase.contract.pending_payment # Get the payment client # Load payment client cln_str = settings.PAYMENT_CLIENT client_class = cln_str.split('.')[-1] client_package = cln_str.partition('.' + client_class)[0] payment_client = getattr(__import__(client_package, globals(), locals(), [client_class], -1), client_class) # build the payment client client = payment_client(purchase) client.end_redirection_payment(token, payer_id) charging_engine = ChargingEngine(purchase) accounting = None if 'accounting' in pending_info: accounting = pending_info['accounting'] charging_engine.end_charging(pending_info['price'], pending_info['concept'], pending_info['related_model'], accounting) except: # Rollback the purchase if existing if purchase is not None: rollback(purchase) context = { 'title': 'Payment Canceled', 'message': 'Your payment has been canceled. An error occurs or the timeout has finished, if you want to acquire the offering purchase it again in WStore.' } return render(request, 'err_msg.html', context) # Check if is the first payment if len(purchase.contract.charges) == 1: if purchase.organization_owned: org = purchase.owner_organization org.offerings_purchased.append(purchase.offering.pk) org.save() else: # Add the offering to the user profile user_profile = UserProfile.objects.get(user=purchase.customer) user_profile.offerings_purchased.append(purchase.offering.pk) user_profile.save() notify_provider(purchase) # _lock is set to false db.wstore_purchase.find_and_modify( query={'_id': reference}, update={'$set': {'_lock': False}} ) # Return the confirmation web page context = { 'title': 'Payment Confirmed', 'message': 'Your payment has been received. To download the resources and the invoice go to the offering details page.' } return render(request, 'err_msg.html', context)
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')
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: 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, 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 = {} 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, 'renovation': self._set_renovation_states, 'use': self._set_renovation_states } states_processors[concept](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')
def read(self, request, reference): purchase = None try: token = request.GET.get('token') payer_id = request.GET.get('PayerID', '') db = get_database_connection() # Uses an atomic operation to get and set the _lock value in the purchase # document pre_value = db.wstore_purchase.find_and_modify( query={'_id': ObjectId(reference)}, update={'$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 '_lock' in pre_value and pre_value['_lock']: raise Exception('') purchase = Purchase.objects.get(ref=reference) # Check that the request user is authorized to end the payment if request.user.userprofile.current_organization != purchase.owner_organization: raise Exception() # If the purchase state value is different from pending means that # the timeout function has completely ended before acquire the resource # so _lock is set to false and the view ends if purchase.state != 'pending': db.wstore_purchase.find_and_modify( query={'_id': ObjectId(reference)}, update={'$set': { '_lock': False }}) raise Exception('') pending_info = purchase.contract.pending_payment # Get the payment client # Load payment client cln_str = settings.PAYMENT_CLIENT client_class = cln_str.split('.')[-1] client_package = cln_str.partition('.' + client_class)[0] payment_client = getattr( __import__(client_package, globals(), locals(), [client_class], -1), client_class) # build the payment client client = payment_client(purchase) client.end_redirection_payment(token, payer_id) charging_engine = ChargingEngine(purchase) accounting = None if 'accounting' in pending_info: accounting = pending_info['accounting'] charging_engine.end_charging(pending_info['price'], pending_info['concept'], pending_info['related_model'], accounting) except: # Rollback the purchase if existing if purchase is not None: rollback(purchase) context = { 'title': 'Payment Canceled', 'message': 'Your payment has been canceled. An error occurs or the timeout has finished, if you want to acquire the offering purchase it again in WStore.' } return render(request, 'err_msg.html', context) # Check if is the first payment if len(purchase.contract.charges) == 1: if purchase.organization_owned: org = purchase.owner_organization org.offerings_purchased.append(purchase.offering.pk) org.save() else: # Add the offering to the user profile user_profile = UserProfile.objects.get(user=purchase.customer) user_profile.offerings_purchased.append(purchase.offering.pk) user_profile.save() notify_provider(purchase) # _lock is set to false db.wstore_purchase.find_and_modify(query={'_id': reference}, update={'$set': { '_lock': False }}) # Return the confirmation web page context = { 'title': 'Payment Confirmed', 'message': 'Your payment has been received. To download the resources and the invoice go to the offering details page.' } return render(request, 'err_msg.html', context)