def update(self, request, reference): purchase = Purchase.objects.get(ref=reference) data = json.loads(request.raw_post_data) try: if data['method'] == 'paypal': charging_engine = ChargingEngine(purchase, payment_method='paypal') elif data['method'] == 'credit_card': # Get the payment info if 'credit_card' in data: credit_card = data['credit_card'] else: if purchase.organization_owned: credit_card = purchase.owner_organization.payment_info else: credit_card = purchase.customer.userprofile.payment_info charging_engine = ChargingEngine(purchase, payment_method='credit_card', credit_card=credit_card) charging_engine.resolve_charging() except: # Refresh the purchase info purchase = Purchase.objects.get(ref=reference) rollback(purchase) return build_response(request, 400, 'Invalid JSON content') return build_response(request, 200, 'OK')
def handle(self, *args, **options): """ This method is used to perform the charging process of the offerings that have pending SDR for more than a month """ now = time.mktime(datetime.now().timetuple()) if len(args) == 0: # Get contracts for contract in Contract.objects.all(): pending_sdrs = contract.pending_sdrs # If there are subscriptions the renovations are used as triggers if len(pending_sdrs) > 0 and (not 'subscription' in contract.pricing_model): time_stamp = time.mktime(pending_sdrs[0]['time_stamp'].timetuple()) if (time_stamp + 2592000) <= now: # A month # Get the related payment info purchase = contract.purchase if purchase.organization_owned: org = purchase.owner_organization payment_info = org.payment_info else: payment_info = purchase.customer.userprofile.payment_info charging = ChargingEngine(purchase, payment_method='credit_card', credit_card=payment_info) charging.resolve_charging(sdr=True) elif len(args) == 1: # Get the purchase try: purchase = Purchase.objects.get(ref=args[0]) except: raise Exception('The provided purchase does not exists') # Get the contract contract = purchase.contract # Check if there are pending SDRs if (len(contract.pending_sdrs) > 0): # Get payment info if purchase.organization_owned: org = purchase.owner_organization payment_info = org.payment_info else: payment_info = purchase.customer.userprofile.payment_info charging = ChargingEngine(purchase, payment_method='credit_card', credit_card=payment_info) charging.resolve_charging(sdr=True) else: raise Exception('No accounting info in the provided purchase') else: raise Exception('Invalid number of arguments')
def resolve_purchase_usage(self, purchase): # Get payment info if purchase.organization_owned: org = purchase.owner_organization payment_info = org.payment_info else: payment_info = purchase.customer.userprofile.payment_info charging = ChargingEngine(purchase, payment_method='credit_card', credit_card=payment_info) charging.resolve_charging(type_='use')
def _process_modify_items(self, items): if len(items) > 1: raise OrderingError( 'Only a modify item is supported per order item') item = items[0] if 'product' not in item: raise OrderingError( 'It is required to specify product information in modify order items' ) product = item['product'] if 'id' not in product: raise OrderingError( 'It is required to provide product id in modify order items') client = InventoryClient() order, contract = self._get_existing_contract(client, product['id']) # Build the new contract new_contract = self._build_contract(item) if new_contract.pricing_model != {}: contract.pricing_model = new_contract.pricing_model contract.revenue_class = new_contract.revenue_class order.save() # The modified item is treated as an initial payment charging_engine = ChargingEngine(order) return charging_engine.resolve_charging(type_='initial', related_contracts=[contract])
def _process_modify_items(self, items): if len(items) > 1: raise OrderingError('Only a modify item is supported per order item') item = items[0] if 'product' not in item: raise OrderingError('It is required to specify product information in modify order items') product = item['product'] if 'id' not in product: raise OrderingError('It is required to provide product id in modify order items') client = InventoryClient() order, contract = self._get_existing_contract(client, product['id']) # Build the new contract new_contract = self._build_contract(item) if new_contract.pricing_model != {}: contract.pricing_model = new_contract.pricing_model contract.revenue_class = new_contract.revenue_class order.save() # The modified item is treated as an initial payment charging_engine = ChargingEngine(order) return charging_engine.resolve_charging(type_='initial', related_contracts=[contract])
def _process_add_items(self, items, order_id, description, terms_accepted): new_contracts = [self._build_contract(item) for item in items] terms_found = False for c in new_contracts: off = Offering.objects.get(pk=ObjectId(c.offering)) if off.asset is not None and off.asset.has_terms: terms_found = True if terms_found and not terms_accepted: raise OrderingError('You must accept the terms and conditions of the offering to acquire it') current_org = self._customer.userprofile.current_organization order = Order.objects.create( order_id=order_id, customer=self._customer, owner_organization=current_org, date=datetime.utcnow(), state='pending', tax_address=self._get_billing_address(items), contracts=new_contracts, description=description ) self.rollback_logger['models'].append(order) charging_engine = ChargingEngine(order) return charging_engine.resolve_charging()
def create(self, request): try: task = json.loads(request.body) except: return build_response(request, 400, 'The provided data is not a valid JSON object') # Check the products to be renovated if 'name' not in task or 'id' not in task or 'priceType' not in task: return build_response(request, 400, 'Missing required field, must contain name, id and priceType fields') # Parse oid from product name parsed_name = task['name'].split('=') try: order = Order.objects.get(order_id=parsed_name[1]) except: return build_response(request, 404, 'The oid specified in the product name is not valid') # Get contract to renovate if isinstance(task['id'], int): task['id'] = unicode(task['id']) try: contract = order.get_product_contract(task['id']) except: return build_response(request, 404, 'The specified product id is not valid') # Refresh accounting information on_usage_refreshed(order, contract) # Build charging engine charging_engine = ChargingEngine(order) if task['priceType'].lower() not in ['recurring', 'usage']: return build_response(request, 400, 'Invalid priceType only recurring and usage types can be renovated') try: redirect_url = charging_engine.resolve_charging(type_=task['priceType'].lower(), related_contracts=[contract]) except ValueError as e: return build_response(request, 400, unicode(e)) except OrderingError as e: return build_response(request, 422, unicode(e)) except: return build_response(request, 500, 'An unexpected event prevented your payment to be created') response = build_response(request, 200, 'OK') # Include redirection header if needed if redirect_url is not None: response['X-Redirect-URL'] = redirect_url return response
def _process_add_items(self, items, order_id, description): new_contracts = [self._build_contract(item) for item in items] current_org = self._customer.userprofile.current_organization order = Order.objects.create( order_id=order_id, customer=self._customer, owner_organization=current_org, date=datetime.utcnow(), state='pending', tax_address=self._get_billing_address(items), contracts=new_contracts, description=description) self.rollback_logger['models'].append(order) charging_engine = ChargingEngine(order) return charging_engine.resolve_charging()
def _process_add_items(self, items, order_id, description): new_contracts = [self._build_contract(item) for item in items] current_org = self._customer.userprofile.current_organization order = Order.objects.create( order_id=order_id, customer=self._customer, owner_organization=current_org, date=datetime.utcnow(), state='pending', tax_address=self._get_billing_address(items), contracts=new_contracts, description=description ) self.rollback_logger['models'].append(order) charging_engine = ChargingEngine(order) return charging_engine.resolve_charging()
def process_product_payment(self, request, task, order, contract): # Refresh accounting information on_usage_refreshed(order, contract) # Build charging engine charging_engine = ChargingEngine(order) redirect_url = None try: redirect_url = charging_engine.resolve_charging( type_=task['priceType'].lower(), related_contracts=[contract]) except ValueError as e: return None, build_response(request, 400, str(e)) except OrderingError as e: # The error might be raised because renewing a suspended product not expired if str( e ) == 'OrderingError: There is not recurring payments to renovate' and contract.suspended: try: on_product_acquired(order, contract) # Change product state to active contract.suspended = False order.save() inventory_client = InventoryClient() inventory_client.activate_product(contract.product_id) except: return None, build_response( request, 400, 'The asset has failed to be activated') else: return None, build_response(request, 422, str(e)) except: return None, build_response( request, 500, 'An unexpected event prevented your payment to be created') return redirect_url, None
def handle(self, *args, **options): """ This method is used to perform the charging process of the offerings that have pending SDR for more than a month """ now = time.mktime(datetime.now().timetuple()) if len(args) == 0: # Get contracts for contract in Contract.objects.all(): pending_sdrs = contract.pending_sdrs # If there are subscriptions the renovations are used as triggers if len(pending_sdrs) > 0 and (not 'subscription' in contract.pricing_model): time_stamp = time.mktime( pending_sdrs[0]['time_stamp'].timetuple()) if (time_stamp + 2592000) <= now: # A month # Get the related payment info purchase = contract.purchase if purchase.organization_owned: org = purchase.owner_organization payment_info = org.payment_info else: payment_info = purchase.customer.userprofile.payment_info charging = ChargingEngine(purchase, payment_method='credit_card', credit_card=payment_info) charging.resolve_charging(sdr=True) elif len(args) == 1: # Get the purchase try: purchase = Purchase.objects.get(ref=args[0]) except: raise Exception('The provided purchase does not exists') # Get the contract contract = purchase.contract # Check if there are pending SDRs if (len(contract.pending_sdrs) > 0): # Get payment info if purchase.organization_owned: org = purchase.owner_organization payment_info = org.payment_info else: payment_info = purchase.customer.userprofile.payment_info charging = ChargingEngine(purchase, payment_method='credit_card', credit_card=payment_info) charging.resolve_charging(sdr=True) else: raise Exception('No accounting info in the provided purchase') else: raise Exception('Invalid number of arguments')
def create_purchase(user, offering, org_owned=False, payment_info=None): if offering.state != 'published': raise PermissionDenied("This offering can't be purchased") if offering.open: raise PermissionDenied('Open offerings cannot be purchased') if accepted_needed(offering) and not payment_info['accepted']: raise PermissionDenied('You must accept the terms and conditions of the offering to acquire it') profile = UserProfile.objects.get(user=user) # Check if the offering is already purchased if (org_owned and offering.pk in profile.current_organization.offerings_purchased) \ or (not org_owned and offering.pk in profile.offerings_purchased): raise PermissionDenied('The offering has been already purchased') organization = profile.current_organization plan = None # Check the selected plan if payment_info and 'plan' in payment_info: plan = payment_info['plan'] # Get the effective tax address if 'tax_address' not in payment_info: if org_owned: tax = organization.tax_address else: tax = profile.tax_address # Check that the customer has a tax address if 'street' not in tax: raise ValueError('The customer does not have a tax address') else: tax = payment_info['tax_address'] # Check tax_address fields if ('street' not in tax) or ('postal' not in tax)\ or ('city' not in tax) or ('country' not in tax): raise ValueError('The tax address is not valid') # Check the payment method before purchase creation in order to avoid # an inconsistent state in the database credit_card_info = None if payment_info['payment_method'] == 'credit_card': if 'credit_card' in payment_info: # Check credit card info if (not ('number' in payment_info['credit_card'])) or (not ('type' in payment_info['credit_card']))\ or (not ('expire_year' in payment_info['credit_card'])) or (not ('expire_month' in payment_info['credit_card']))\ or (not ('cvv2' in payment_info['credit_card'])): raise ValueError('Invalid credit card info') credit_card_info = payment_info['credit_card'] else: if org_owned: credit_card_info = organization.payment_info else: credit_card_info = profile.payment_info # Check the credit card info if 'number' not in credit_card_info: raise Exception('The customer does not have payment info') elif payment_info['payment_method'] != 'paypal': raise ValueError('Invalid payment method') # Check if a purchase object exists old_purchase = Purchase.objects.filter(owner_organization=organization, offering=offering) if len(old_purchase) > 0: for p in old_purchase: p.delete() # Create the purchase purchase = Purchase.objects.create( customer=user, date=datetime.now(), offering=offering, organization_owned=org_owned, state='pending', tax_address=tax, owner_organization=organization ) # Load ref purchase.ref = purchase.pk purchase.save() if credit_card_info is not None: charging_engine = ChargingEngine(purchase, payment_method='credit_card', credit_card=credit_card_info, plan=plan) else: charging_engine = ChargingEngine(purchase, payment_method='paypal', plan=plan) redirect_url = charging_engine.resolve_charging(new_purchase=True) if redirect_url is None: result = purchase # If no redirect URL is provided the purchase has ended so the user profile # info is updated if org_owned: organization.offerings_purchased.append(offering.pk) organization.save() else: profile.offerings_purchased.append(offering.pk) profile.save() notify_provider(purchase) else: result = redirect_url # Update offering indexes index_path = os.path.join(settings.BASEDIR, 'wstore') index_path = os.path.join(index_path, 'search') index_path = os.path.join(index_path, 'indexes') se = SearchEngine(index_path) se.update_index(offering) return result