def authorize_payment(self, amount=NOTSET): """Make an authorization, using the existing pending payment if found""" self.amount = amount log.debug("Recording %s authorization of %s for %s", self.key, self.amount, self.order) self._get_pending() if self.pending: self.orderpayment = OrderAuthorization() self.orderpayment.capture = self.pending.capture if amount == NOTSET: self.set_amount_from_pending() else: log.debug("No pending %s authorizations for %s", self.key, self.order) self.orderpayment = OrderAuthorization( order=self.order, payment=self.key) self.cleanup() return self.orderpayment
def capture_payment(self, amount=None): """Make a direct payment without a prior authorization, using the existing pending payment if found.""" self.amount = amount self._get_pending() if self.pending: self.orderpayment = self.pending.capture log.debug("Using linked payment: %s", self.orderpayment) if amount is None: self.set_amount_from_pending() else: log.debug("No pending %s payments for %s", self.key, self.order) self.orderpayment = OrderPayment(order=self.order, payment=self.key) log.debug("Recorded %s payment of %s for %s", self.key, self.amount, self.order) self.cleanup() return self.orderpayment
def authorize_payment(self, amount=None): """Make an authorization, using the existing pending payment if found""" self.amount = amount log.debug("Recording %s authorization of %s for %s", self.key, self.amount, self.order) self._get_pending() if self.pending: self.orderpayment = OrderAuthorization() self.orderpayment.capture = self.pending.capture if amount is None: self.set_amount_from_pending() else: log.debug("No pending %s authorizations for %s", self.key, self.order) self.orderpayment = OrderAuthorization(order=self.order, payment=self.key) self.cleanup() return self.orderpayment
def capture_payment(self, amount=NOTSET): """Make a direct payment without a prior authorization, using the existing pending payment if found.""" self.amount = amount log.debug("Recording %s payment of %s for %s", self.key, amount, self.order) self._get_pending() if self.pending: self.orderpayment = self.pending.capture log.debug("Using linked payment: %s", self.orderpayment) if amount == NOTSET: self.set_amount_from_pending() else: log.debug("No pending %s payments for %s", self.key, self.order) self.orderpayment = OrderPayment( order=self.order, payment=self.key) self.cleanup() return self.orderpayment
class PaymentRecorder(object): """Manages proper recording of pending payments, payments, and authorizations.""" def __init__(self, order, config): self.order = order self.key = unicode(config.KEY.value) self.config = config self._amount = NOTSET self.transaction_id = "" self.reason_code = "" self.orderpayment = None self.pending = None def _set_amount(self, amount): if amount != NOTSET: self._amount = amount def _get_amount(self): if self._amount == NOTSET: return self.order.balance else: return self._amount amount = property(fset=_set_amount, fget=_get_amount) def _get_pending(self): self.pendingpayments = self.order.pendingpayments.filter(payment__exact=self.key) if self.pendingpayments.count() > 0: self.pending = self.pendingpayments[0] log.debug("Found pending payment: %s", self.pending) def authorize_payment(self, amount=NOTSET): """Make an authorization, using the existing pending payment if found""" self.amount = amount log.debug("Recording %s authorization of %s for %s", self.key, self.amount, self.order) self._get_pending() if self.pending: self.orderpayment = OrderAuthorization() self.orderpayment.capture = self.pending.capture if amount == NOTSET: self.set_amount_from_pending() else: log.debug("No pending %s authorizations for %s", self.key, self.order) self.orderpayment = OrderAuthorization( order=self.order, payment=self.key) self.cleanup() return self.orderpayment def capture_authorized_payment(self, authorization, amount=NOTSET): """Convert an authorization into a payment.""" self.amount = amount log.debug("Recording %s capture of authorization #%i for %s", self.key, authorization.id, self.order) self.orderpayment = authorization.capture self.cleanup() return self.orderpayment def capture_payment(self, amount=NOTSET): """Make a direct payment without a prior authorization, using the existing pending payment if found.""" self.amount = amount log.debug("Recording %s payment of %s for %s", self.key, amount, self.order) self._get_pending() if self.pending: self.orderpayment = self.pending.capture log.debug("Using linked payment: %s", self.orderpayment) if amount == NOTSET: self.set_amount_from_pending() else: log.debug("No pending %s payments for %s", self.key, self.order) self.orderpayment = OrderPayment( order=self.order, payment=self.key) self.cleanup() return self.orderpayment def cleanup(self): if self.pending: pending = self.pending self.orderpayment.capture = pending.capture self.orderpayment.order = pending.order self.orderpayment.payment = pending.payment self.orderpayment.details = pending.details # delete any extra pending orderpayments for p in self.pendingpayments: if p != pending and p.capture.transaction_id=='LINKED': p.capture.delete() p.delete() self.orderpayment.reason_code=self.reason_code self.orderpayment.transaction_id=self.transaction_id self.orderpayment.amount=self.amount self.orderpayment.time_stamp = datetime.now() self.orderpayment.save() order = self.orderpayment.order if order.paid_in_full: def _latest_status(order): try: curr_status = order.orderstatus_set.latest() return curr_status.status except OrderStatus.DoesNotExist: return '' if _latest_status(order) in ('', 'New'): order.order_success() # order_success listeners or product methods could have modified the status. reload it. if _latest_status(order) == '': order.add_status('New') def create_pending(self, amount=NOTSET): """Create a placeholder payment entry for the order. This is done by step 2 of the payment process.""" if amount == NOTSET: amount = Decimal("0.00") self.amount = amount self._get_pending() ct = self.pendingpayments.count() if ct > 0: log.debug("Deleting %i expired pending payment entries for order #%i", ct, self.order.id) for pending in self.pendingpayments: if pending.capture.transaction_id=='LINKED': pending.capture.delete() pending.delete() log.debug("Creating pending %s payment of %s for %s", self.key, amount, self.order) self.pending = OrderPendingPayment.objects.create(order=self.order, amount=amount, payment=self.key) return self.pending def set_amount_from_pending(self): """Try to figure out how much to charge. If it is set on the "pending" charge use that otherwise use the order balance.""" amount = self.pending.amount # otherwise use the order balance. if amount == Decimal('0.00'): amount = self.order.balance self.amount = amount
def cron_rebill(request=None): """Rebill customers with expiring recurring subscription products This can either be run via a url with GET key authentication or directly from a shell script. """ #TODO: support re-try billing for failed transactions if request is not None: if not config_value('PAYMENT', 'ALLOW_URL_REBILL'): return bad_or_missing(request, _("Feature is not enabled.")) if 'key' not in request.GET or request.GET['key'] != config_value('PAYMENT','CRON_KEY'): return HttpResponse("Authentication Key Required") expiring_subscriptions = OrderItem.objects.filter(expire_date__gte=timezone.now()).order_by('order', 'id', 'expire_date') for item in expiring_subscriptions: if item.product.is_subscription:#TODO - need to add support for products with trial but non-recurring if item.product.subscriptionproduct.recurring_times and item.product.subscriptionproduct.recurring_times + item.product.subscriptionproduct.get_trial_terms().count() == OrderItem.objects.filter(order=item.order, product=item.product).count(): continue if item.expire_date == datetime.date(timezone.now()) and item.completed: if item.id == OrderItem.objects.filter(product=item.product, order=item.order).order_by('-id')[0].id: #bill => add orderitem, recalculate total, porocess card new_order_item = OrderItem(order=item.order, product=item.product, quantity=item.quantity, unit_price=item.unit_price, line_item_price=item.line_item_price) #if product is recurring, set subscription end if item.product.subscriptionproduct.recurring: new_order_item.expire_date = item.product.subscriptionproduct.calc_expire_date() #check if product has 2 or more trial periods and if the last one paid was a trial or a regular payment. ordercount = item.order.orderitem_set.all().count() if item.product.subscriptionproduct.get_trial_terms().count() > 1 and item.unit_price == item.product.subscriptionproduct.get_trial_terms(ordercount - 1).price: new_order_item.unit_price = item.product.subscriptionproduct.get_trial.terms(ordercount).price new_order_item.line_item_price = new_order_item.quantity * new_order_item.unit_price new_order_item.expire_date = item.product.subscriptionproduct.get_trial_terms(ordercount).calc_expire_date() new_order_item.save() item.order.recalculate_total() # if new_order_item.product.subscriptionproduct.is_shippable == 3: # item.order.total = item.order.total - item.order.shipping_cost # item.order.save() payments = item.order.payments.all()[0] #list of ipn based payment modules. Include processors that use 3rd party recurring billing. ipn_based = ['PAYPAL'] if not payments.payment in ipn_based and item.order.balance > 0: #run card #Do the credit card processing here & if successful, execute the success_handler from livesettings import config_get_group payment_module = config_get_group('PAYMENT_%s' % payments.payment) credit_processor = payment_module.MODULE.load_module('processor') processor = credit_processor.PaymentProcessor(payment_module) processor.prepare_data(item.order) result = processor.process() if result.payment: reason_code = result.payment.reason_code else: reason_code = "unknown" log.info("""Processing %s recurring transaction with %s Order #%i Results=%s Response=%s Reason=%s""", payment_module.LABEL.value, payment_module.KEY.value, item.order.id, result.success, reason_code, result.message) if result.success: #success handler item.order.add_status(status='New', notes = ugettext("Subscription Renewal Order successfully submitted")) new_order_item.completed = True new_order_item.save() orderpayment = OrderPayment(order=item.order, amount=item.order.balance, payment=unicode(payment_module.KEY.value)) orderpayment.save() return HttpResponse()
class PaymentRecorder(object): """Manages proper recording of pending payments, payments, and authorizations.""" def __init__(self, order, config): self.order = order self.key = six.text_type(config.KEY.value) self.config = config self._amount = None self.transaction_id = "" self.reason_code = "" self.orderpayment = None self.pending = None def _set_amount(self, amount): if not amount is None: self._amount = amount def _get_amount(self): if self._amount is None: balance = self.order.balance return balance if balance > 0 else Decimal("0") else: return self._amount amount = property(fset=_set_amount, fget=_get_amount) def _get_pending(self): self.pendingpayments = self.order.pendingpayments.filter( payment__exact=self.key) if self.pendingpayments.count() > 0: self.pending = self.pendingpayments[0] log.debug("Found pending payment: %s", self.pending) def authorize_payment(self, amount=None): """Make an authorization, using the existing pending payment if found""" self.amount = amount log.debug("Recording %s authorization of %s for %s", self.key, self.amount, self.order) self._get_pending() if self.pending: self.orderpayment = OrderAuthorization() self.orderpayment.capture = self.pending.capture if amount is None: self.set_amount_from_pending() else: log.debug("No pending %s authorizations for %s", self.key, self.order) self.orderpayment = OrderAuthorization(order=self.order, payment=self.key) self.cleanup() return self.orderpayment def capture_authorized_payment(self, authorization, amount=None): """Convert an authorization into a payment.""" self.amount = amount log.debug("Recording %s capture of authorization #%i for %s", self.key, authorization.id, self.order) self.orderpayment = authorization.capture self.cleanup() return self.orderpayment def capture_payment(self, amount=None): """Make a direct payment without a prior authorization, using the existing pending payment if found.""" self.amount = amount self._get_pending() if self.pending: self.orderpayment = self.pending.capture log.debug("Using linked payment: %s", self.orderpayment) if amount is None: self.set_amount_from_pending() else: log.debug("No pending %s payments for %s", self.key, self.order) self.orderpayment = OrderPayment(order=self.order, payment=self.key) log.debug("Recorded %s payment of %s for %s", self.key, self.amount, self.order) self.cleanup() return self.orderpayment def record_failure(self, amount=None, details="", authorization=None): log.info('Recording a payment failure: order #%i, code %s\nmessage=%s', self.order.id, self.reason_code, details) self.amount = amount failure = OrderPaymentFailure.objects.create( order=self.order, details=details, transaction_id=self.transaction_id, amount=self.amount, payment=self.key, reason_code=self.reason_code) return failure def cleanup(self): if self.pending: pending = self.pending self.orderpayment.capture = pending.capture self.orderpayment.order = pending.order self.orderpayment.payment = pending.payment self.orderpayment.details = pending.details # delete any extra pending orderpayments for p in self.pendingpayments: if p != pending and p.capture.transaction_id == 'LINKED': p.capture.delete() p.delete() self.orderpayment.reason_code = self.reason_code self.orderpayment.transaction_id = self.transaction_id self.orderpayment.amount = self.amount self.orderpayment.time_stamp = timezone.now() self.orderpayment.save() order = self.orderpayment.order if order.paid_in_full: def _latest_status(order): try: curr_status = order.orderstatus_set.latest() return curr_status.status except OrderStatus.DoesNotExist: return '' if _latest_status(order) in ('', 'New'): order.order_success() # order_success listeners or product methods could have modified the status. reload it. if _latest_status(order) == '': order.add_status('New') def create_pending(self, amount=None): """Create a placeholder payment entry for the order. This is done by step 2 of the payment process.""" if amount is None: amount = Decimal("0.00") self.amount = amount self._get_pending() ct = self.pendingpayments.count() if ct > 0: log.debug( "Deleting %i expired pending payment entries for order #%i", ct, self.order.id) for pending in self.pendingpayments: if pending.capture.transaction_id == 'LINKED': pending.capture.delete() pending.delete() log.debug("Creating pending %s payment of %s for %s", self.key, amount, self.order) self.pending = OrderPendingPayment.objects.create(order=self.order, amount=amount, payment=self.key) return self.pending def set_amount_from_pending(self): """Try to figure out how much to charge. If it is set on the "pending" charge use that otherwise use the order balance.""" amount = self.pending.amount # otherwise use the order balance. if amount == Decimal('0.00'): amount = self.order.balance self.amount = amount
def cron_rebill(request=None): """Rebill customers with expiring recurring subscription products This can either be run via a url with GET key authentication or directly from a shell script. """ #TODO: support re-try billing for failed transactions if request is not None: if not config_value('PAYMENT', 'ALLOW_URL_REBILL'): return bad_or_missing(request, _("Feature is not enabled.")) if 'key' not in request.GET or request.GET['key'] != config_value( 'PAYMENT', 'CRON_KEY'): return HttpResponse("Authentication Key Required") expiring_subscriptions = OrderItem.objects.filter( expire_date__gte=timezone.now()).order_by('order', 'id', 'expire_date') for item in expiring_subscriptions: if item.product.is_subscription: #TODO - need to add support for products with trial but non-recurring if item.product.subscriptionproduct.recurring_times and item.product.subscriptionproduct.recurring_times + item.product.subscriptionproduct.get_trial_terms( ).count() == OrderItem.objects.filter( order=item.order, product=item.product).count(): continue if item.expire_date == datetime.date( timezone.now()) and item.completed: if item.id == OrderItem.objects.filter( product=item.product, order=item.order).order_by('-id')[0].id: #bill => add orderitem, recalculate total, porocess card new_order_item = OrderItem( order=item.order, product=item.product, quantity=item.quantity, unit_price=item.unit_price, line_item_price=item.line_item_price) #if product is recurring, set subscription end if item.product.subscriptionproduct.recurring: new_order_item.expire_date = item.product.subscriptionproduct.calc_expire_date( ) #check if product has 2 or more trial periods and if the last one paid was a trial or a regular payment. ordercount = item.order.orderitem_set.all().count() if item.product.subscriptionproduct.get_trial_terms( ).count( ) > 1 and item.unit_price == item.product.subscriptionproduct.get_trial_terms( ordercount - 1).price: new_order_item.unit_price = item.product.subscriptionproduct.get_trial.terms( ordercount).price new_order_item.line_item_price = new_order_item.quantity * new_order_item.unit_price new_order_item.expire_date = item.product.subscriptionproduct.get_trial_terms( ordercount).calc_expire_date() new_order_item.save() item.order.recalculate_total() # if new_order_item.product.subscriptionproduct.is_shippable == 3: # item.order.total = item.order.total - item.order.shipping_cost # item.order.save() payments = item.order.payments.all()[0] #list of ipn based payment modules. Include processors that use 3rd party recurring billing. ipn_based = ['PAYPAL'] if not payments.payment in ipn_based and item.order.balance > 0: #run card #Do the credit card processing here & if successful, execute the success_handler payment_module = config_get_group('PAYMENT_%s' % payments.payment) credit_processor = payment_module.MODULE.load_module( 'processor') processor = credit_processor.PaymentProcessor( payment_module) processor.prepare_data(item.order) result = processor.process() if result.payment: reason_code = result.payment.reason_code else: reason_code = "unknown" log.info( """Processing %s recurring transaction with %s Order #%i Results=%s Response=%s Reason=%s""", payment_module.LABEL.value, payment_module.KEY.value, item.order.id, result.success, reason_code, result.message) if result.success: #success handler item.order.add_status( status='New', notes=ugettext( "Subscription Renewal Order successfully submitted" )) new_order_item.completed = True new_order_item.save() orderpayment = OrderPayment( order=item.order, amount=item.order.balance, payment=six.text_type( payment_module.KEY.value)) orderpayment.save() return HttpResponse()