def create(self, request): try: # Extract SDR document from the HTTP request data = json.loads(request.body) except: # The usage document is not valid, so the state cannot be changed return build_response(request, 400, 'The request does not contain a valid JSON object') # Validate usage information response = None try: sdr_manager = SDRManager() sdr_manager.validate_sdr(data) except PermissionDenied as e: response = build_response(request, 403, unicode(e)) except ValueError as e: response = build_response(request, 422, unicode(e)) except: response = build_response(request, 500, 'The SDR document could not be processed due to an unexpected error') usage_client = UsageClient() if response is not None: # The usage document is not valid, change its state to Rejected usage_client.update_usage_state('Rejected', data) else: # The usage document is valid, change its state to Guided usage_client.update_usage_state('Guided', data) response = build_response(request, 200, 'OK') # Update usage document state return response
def _process_use_charge(self, contracts): """ Resolves usage charges, which includes pay-per-use payments :return: The URL where redirecting the customer to approve the charge """ self._order.state = 'pending' transactions = [] usage_client = UsageClient() for contract in contracts: if 'pay_per_use' not in contract.pricing_model: continue related_model = { 'pay_per_use': contract.pricing_model['pay_per_use'] } accounting = self._parse_raw_accounting(usage_client.get_customer_usage( self._order.owner_organization.name, contract.product_id, state='Guided')) if 'alteration' in contract.pricing_model and \ contract.pricing_model['alteration'].get('period') == 'recurring': related_model['alteration'] = contract.pricing_model['alteration'] if len(accounting) > 0: self._append_transaction( transactions, contract, related_model, accounting=accounting ) return self._execute_renovation_transactions(transactions, 'There is not usage payments to renovate')
def remove_usage_specs(self): if 'usage' in self._model.options: try: usage_client = UsageClient() for unit, href in self._model.options['usage'].iteritems(): spec_id = href.split('/')[-1] usage_client.delete_usage_spec(spec_id) except HTTPError as e: if e.response.status_code != 404: raise e
def _end_use_charge(self, contract, transaction): # Change applied usage documents SDR Guided to Rated usage_client = UsageClient() for sdr_info in transaction['applied_accounting']: for sdr in sdr_info['accounting']: usage_client.rate_usage( sdr['usage_id'], unicode(contract.last_charge), sdr['duty_free'], sdr['price'], sdr_info['model']['tax_rate'], transaction['currency'], contract.product_id ) transaction['related_model']['accounting'] = transaction['applied_accounting']
def configure_usage_spec(self): # Build common usage spec specification_template = { 'usageSpecCharacteristic': [ self._get_usage_characteristic('orderId', 'Order identifier', 'string'), self._get_usage_characteristic('productId', 'Product identifier', 'string'), self._get_usage_characteristic( 'correlationNumber', 'Accounting correlation number', 'number'), self._get_usage_characteristic('unit', 'Accounting unit', 'string'), self._get_usage_characteristic('value', 'Accounting value', 'number') ] } usage_specs = self.get_usage_specs() usage_client = UsageClient() # Create usage specifications for supported units for spec in usage_specs: if 'name' not in spec or 'description' not in spec: raise PluginError( 'Invalid product specification configuration, must include name and description' ) # Check if the usage spec is already registered if 'usage' not in self._model.options or spec['name'].lower( ) not in self._model.options['usage']: usage_spec = deepcopy(specification_template) usage_spec['name'] = spec['name'] usage_spec['description'] = spec['description'] created_spec = usage_client.create_usage_spec(usage_spec) if 'usage' not in self._model.options: self._model.options['usage'] = {} # Save the spec href to be used in usage documents self._model.options['usage'][ spec['name'].lower()] = created_spec['href'] self._model.save()
def _end_use_charge(self, contract, transaction): # Change applied usage documents SDR Guided to Rated usage_client = UsageClient() for sdr_info in transaction['applied_accounting']: for sdr in sdr_info['accounting']: usage_client.rate_usage(sdr['usage_id'], unicode(contract.last_charge), sdr['duty_free'], sdr['price'], sdr_info['model']['tax_rate'], transaction['currency'], contract.product_id) transaction['related_model']['accounting'] = transaction[ 'applied_accounting'] return contract.charges[-1].date if len( contract.charges) > 0 else self._order.date, None
def create(self, request): try: # Extract SDR document from the HTTP request data = json.loads(request.body) except: # The usage document is not valid, so the state cannot be changed return build_response( request, 400, 'The request does not contain a valid JSON object') # Validate usage information response = None sdr_manager = SDRManager() try: sdr_manager.validate_sdr(data) except PermissionDenied as e: response = build_response(request, 403, str(e)) except ValueError as e: response = build_response(request, 422, str(e)) except: response = build_response( request, 500, 'The SDR document could not be processed due to an unexpected error' ) usage_client = UsageClient() if response is not None: # The usage document is not valid, change its state to Rejected usage_client.update_usage_state(data['id'], 'Rejected') else: # The usage document is valid, change its state to Guided usage_client.update_usage_state(data['id'], 'Guided') sdr_manager.update_usage() response = build_response(request, 200, 'OK') # Update usage document state return response
def on_usage_refresh(self, asset, contract, order): if not self._model.pull_accounting: return pending_accounting, last_usage = self.get_pending_accounting( asset, contract, order) usage_template = { 'type': 'event', 'status': 'Received', 'usageCharacteristic': [{ 'name': 'orderId', 'value': order.order_id }, { 'name': 'productId', 'value': contract.product_id }], 'relatedParty': [{ 'role': 'customer', 'id': order.owner_organization.name, 'href': order.owner_organization.get_party_url() }] } usage_client = UsageClient() for usage_record in pending_accounting: if 'date' not in usage_record or 'unit' not in usage_record or 'value' not in usage_record: raise PluginError( 'Invalid usage record, it must include date, unit and value' ) # Generate a TMForum usage document for each usage record usage = deepcopy(usage_template) usage['date'] = usage_record['date'] usage['usageSpecification'] = { 'href': self._model.options['usage'][usage_record['unit']], 'name': usage_record['unit'] } usage['usageCharacteristic'].append({ 'name': 'unit', 'value': usage_record['unit'] }) usage['usageCharacteristic'].append({ 'name': 'correlationNumber', 'value': contract.correlation_number }) usage['usageCharacteristic'].append({ 'name': 'value', 'value': usage_record['value'] }) usage_doc = usage_client.create_usage(usage) # All the information is known so the document is directly created in Guided state usage_client.update_usage_state(usage_doc['id'], 'Guided') contract.correlation_number += 1 order.save() if last_usage is not None: contract.last_usage = last_usage order.save()