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(order_id=data['orderId']) # 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) for sale in order.sales_ids: client.refund(sale) # Only those orders with all its order items in ack state can be refunded # that means that all the contracts have been refunded for contract in order.contracts: if len(contract.charges) > 0: cdr_manager = CDRManager(order, contract) charge = contract.charges[-1] # Create a refund CDR for each contract cdr_manager.refund_cdrs(charge['cost'], charge['duty_free'], charge['date'].isoformat() + 'Z') order.delete() except: return build_response(request, 400, 'Sales cannot be refunded') return build_response(request, 200, 'Ok')
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(order_id=data['orderId']) # 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) for sale in order.sales_ids: client.refund(sale) # Only those orders with all its order items in ack state can be refunded # that means that all the contracts have been refunded for contract in order.contracts: cdr_manager = CDRManager(order, contract) charge = contract.charges[-1] cdr_manager.refund_cdrs(charge['cost'], charge['duty_free'], charge['date'].isoformat() + 'Z') # Create a refund CDR for each contract order.delete() except: return build_response(request, 400, 'Sales cannot be refunded') return build_response(request, 200, 'Ok')
def end_charging(self, transactions, free_contracts, concept): """ Process the second step of a payment once the customer has approved the charge :param transactions: List of transactions applied including the total price and the related model :param concept: Concept of the charge, it can be initial, renovation, or use """ # Update purchase state if self._order.state == 'pending': self._order.state = 'paid' self._order.save() time_stamp = datetime.utcnow() self._order.pending_payment = {} invoice_builder = InvoiceBuilder(self._order) billing_client = BillingClient() if concept != 'initial' else None for transaction in transactions: contract = self._order.get_item_contract(transaction['item']) contract.last_charge = time_stamp valid_from, valid_to = self.end_processors[concept](contract, transaction) # If the customer has been charged create the CDR cdr_manager = CDRManager(self._order, contract) cdr_manager.generate_cdr(transaction['related_model'], time_stamp.isoformat() + 'Z') # Generate the invoice invoice_path = '' try: invoice_path = invoice_builder.generate_invoice(contract, transaction, concept) except: pass # Update contracts charge = Charge( date=time_stamp, cost=transaction['price'], duty_free=transaction['duty_free'], currency=transaction['currency'], concept=concept, invoice=invoice_path ) contract.charges.append(charge) # Send the charge to the billing API to allow user accesses if concept != 'initial': # When the change concept is initial, the product has not been yet created in the inventory billing_client.create_charge(charge, contract.product_id, start_date=valid_from, end_date=valid_to) for free in free_contracts: self._order.owner_organization.acquired_offerings.append(free.offering.pk) self._order.owner_organization.save() self._order.save() self._send_notification(concept, transactions)
def end_charging(self, transactions, concept): """ Process the second step of a payment once the customer has approved the charge :param transactions: List of transactions applied including the total price and the related model :param concept: Concept of the charge, it can be initial, renovation, or use """ # Update purchase state if self._order.state == 'pending': self._order.state = 'paid' self._order.save() time_stamp = datetime.now() self._order.pending_payment = {} for transaction in transactions: contract = self._order.get_item_contract(transaction['item']) # Update contracts contract.charges.append({ 'date': time_stamp, 'cost': transaction['price'], 'currency': transaction['currency'], 'concept': concept }) contract.last_charge = time_stamp self.end_processors[concept](contract, transaction) # If the customer has been charged create the CDR cdr_manager = CDRManager(self._order, contract) cdr_manager.generate_cdr(transaction['related_model'], unicode(time_stamp)) self._order.save() # TODO: Improve the rollback in case of unexpected exception try: # Generate the invoice invoice_builder = InvoiceBuilder(self._order) invoice_builder.generate_invoice(transactions, concept) # Send notifications if required handler = NotificationsHandler() if concept == 'initial': # Send customer and provider notifications handler.send_acquired_notification(self._order) for cont in self._order.contracts: handler.send_provider_notification(self._order, cont) elif concept == 'renovation' or concept == 'use': handler.send_renovation_notification(self._order, transactions) except: pass
def end_charging(self, transactions, concept): """ Process the second step of a payment once the customer has approved the charge :param transactions: List of transactions applied including the total price and the related model :param concept: Concept of the charge, it can be initial, renovation, or use """ # Update purchase state if self._order.state == 'pending': self._order.state = 'paid' self._order.save() time_stamp = datetime.utcnow() self._order.pending_payment = {} invoice_builder = InvoiceBuilder(self._order) billing_client = BillingClient() if concept != 'initial' else None for transaction in transactions: contract = self._order.get_item_contract(transaction['item']) contract.last_charge = time_stamp valid_from, valid_to = self.end_processors[concept](contract, transaction) # If the customer has been charged create the CDR cdr_manager = CDRManager(self._order, contract) cdr_manager.generate_cdr(transaction['related_model'], time_stamp.isoformat() + 'Z') # Generate the invoice invoice_path = '' try: invoice_path = invoice_builder.generate_invoice(contract, transaction, concept) except: pass # Update contracts charge = Charge( date=time_stamp, cost=transaction['price'], duty_free=transaction['duty_free'], currency=transaction['currency'], concept=concept, invoice=invoice_path ) contract.charges.append(charge) # Send the charge to the billing API to allow user accesses if concept != 'initial': # When the change concept is initial, the product has not been yet created in the inventory billing_client.create_charge(charge, contract.product_id, start_date=valid_from, end_date=valid_to) self._order.save() # TODO: Improve the rollback in case of unexpected exception try: # Send notifications if required handler = NotificationsHandler() if concept == 'initial': # Send customer and provider notifications handler.send_acquired_notification(self._order) for cont in self._order.contracts: handler.send_provider_notification(self._order, cont) elif concept == 'recurring' or concept == 'usage': handler.send_renovation_notification(self._order, transactions) except: pass