Exemple #1
0
    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
Exemple #2
0
    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
Exemple #3
0
    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
Exemple #4
0
    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
Exemple #5
0
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
Exemple #6
0
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()
Exemple #7
0
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
Exemple #8
0
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()