Esempio n. 1
0
    def update_tax(self):
        taxclass = self.product.taxClass
        processor = get_tax_processor(order=self.order)

        if self.product.taxable:
            self.unit_tax = processor.by_product_and_price(taxclass, self.unit_price, product=self.product)
            self.tax = processor.by_orderitem(self)
Esempio n. 2
0
def _get_taxprocessor(request=None):
    taxprocessor = get_thread_variable("taxer", None)
    if not taxprocessor:
        if request:
            user = request.user
            if user.is_authenticated():
                user = user
            else:
                user = None
        else:
            user = get_current_user()

        taxprocessor = get_tax_processor(user=user)
        set_thread_variable("taxer", taxprocessor)

    return taxprocessor
Esempio n. 3
0
def _get_taxprocessor(request=None):
    taxprocessor = get_thread_variable('taxer', None)
    if not taxprocessor:
        if request:
            user = request.user
            if user.is_authenticated():
                user = user
            else:
                user = None
        else:
            user = get_current_user()

        taxprocessor = get_tax_processor(user=user)
        set_thread_variable('taxer', taxprocessor)

    return taxprocessor
Esempio n. 4
0
def _get_taxprocessor(request=None):
    if request:
        user = request.user
        if user.is_authenticated:
            user_id = user.id
        else:
            user = None
            user_id = "None"
    else:
        user = get_current_user()
        user_id = user and user.id
    thread_key = "taxer-%s" % user_id
    taxprocessor = get_thread_variable(thread_key, None)
    if not taxprocessor:
        taxprocessor = get_tax_processor(user=user)
        set_thread_variable(thread_key, taxprocessor)
    return taxprocessor
Esempio n. 5
0
def _get_taxprocessor(request=None):
    if request:
        user = request.user
        if user.is_authenticated():
            user_id = user.id
        else:
            user = None
            user_id = "None"
    else:
        user = get_current_user()
        user_id = user and user.id
    thread_key = "taxer-%s" % user_id
    taxprocessor = get_thread_variable(thread_key, None)
    if not taxprocessor:
        taxprocessor = get_tax_processor(user=user)    
        set_thread_variable(thread_key, taxprocessor)
    return taxprocessor
Esempio n. 6
0
    def force_recalculate_total(self, save=True):
        """Calculates sub_total, taxes and total."""
        zero = Decimal("0.0000000000")
        total_discount = Decimal("0.0000000000")

        discount = Discount.objects.by_code(self.discount_code)
        discount.calc(self)

        discounts = discount.item_discounts
        itemprices = []
        fullprices = []
        for lineitem in self.orderitem_set.all():
            lid = lineitem.id
            if lid in discounts:
                lineitem.discount = discounts[lid]
            else:
                lineitem.discount = zero
            # now double check against other discounts, such as tiered discounts
            adjustment = get_product_quantity_adjustments(lineitem.product, qty=lineitem.quantity)
            if adjustment and adjustment.price:
                baseprice = adjustment.price.price
                finalprice = adjustment.final_price()
                #We need to add in any OrderItemDetail price adjustments before we do anything else 
                baseprice += lineitem.get_detail_price() 
                finalprice += lineitem.get_detail_price() 
                if baseprice > finalprice or baseprice != lineitem.unit_price:
                    unitdiscount = (lineitem.discount/lineitem.quantity) + baseprice-finalprice
                    unitdiscount = trunc_decimal(unitdiscount, 2)
                    linediscount = unitdiscount * lineitem.quantity
                    total_discount += linediscount
                    fullydiscounted = (baseprice - unitdiscount) * lineitem.quantity
                    lineitem.unit_price = baseprice
                    lineitem.discount = linediscount
                    lineitem.line_item_price = baseprice * lineitem.quantity
                    log.debug('Adjusting lineitem unit price for %s. Full price=%s, discount=%s.  Final price for qty %d is %s', 
                        lineitem.product.slug, baseprice, unitdiscount, lineitem.quantity, fullydiscounted)
            if save:
                lineitem.save()

            itemprices.append(lineitem.sub_total)
            fullprices.append(lineitem.line_item_price)

        shipprice = Price()
        shipprice.price = self.shipping_cost
        shipadjust = PriceAdjustmentCalc(shipprice)
        if 'Shipping' in discounts:
            shipadjust += PriceAdjustment('discount', _('Discount'), discounts['Shipping'])

        signals.satchmo_shipping_price_query.send(self, adjustment=shipadjust)    
        shipdiscount = shipadjust.total_adjustment()
        self.shipping_discount = shipdiscount
        total_discount += shipdiscount

        self.discount = total_discount

        if itemprices:
            item_sub_total = reduce(operator.add, itemprices)
        else:
            item_sub_total = zero

        if fullprices:
            full_sub_total = reduce(operator.add, fullprices)
        else:
            full_sub_total = zero

        self.sub_total = full_sub_total

        taxProcessor = get_tax_processor(self)
        totaltax, taxrates = taxProcessor.process()
        self.tax = totaltax

        # clear old taxes
        for taxdetl in self.taxes.all():
            taxdetl.delete()

        for taxdesc, taxamt in taxrates.items():
            taxdetl = OrderTaxDetail(order=self, tax=taxamt, description=taxdesc, method=taxProcessor.method)
            taxdetl.save()

        log.debug("Order #%i, recalc: sub_total=%s, shipping=%s, discount=%s, tax=%s",
            self.id,
            moneyfmt(item_sub_total), 
            moneyfmt(self.shipping_sub_total),
            moneyfmt(self.discount), 
            moneyfmt(self.tax))

        self.total = Decimal(item_sub_total + self.shipping_sub_total + self.tax)

        if save:
            self.save()
Esempio n. 7
0
 def update_tax(self):
     taxclass = self.product.taxClass
     processor = get_tax_processor(order=self.order)
     self.unit_tax = processor.by_price(taxclass, self.unit_price)
     self.tax = processor.by_orderitem(self)
Esempio n. 8
0
def productvariation_details(product, include_tax, user, create=False):
    """Build the product variation details, for conversion to javascript.

    Returns variation detail dictionary built like so:
    details = {
        "OPTION_KEY" : {
            "SLUG": "Variation Slug",
            "PRICE" : {"qty" : "$price", [...]},
            "SALE" : {"qty" : "$price", [...]},
            "TAXED" : "$taxed price",   # omitted if no taxed price requested
            "QTY" : 1
        },
        [...]
    }
    """

    ignore_stock = config_value('PRODUCT','NO_STOCK_CHECKOUT')
    discount = find_best_auto_discount(product)
    use_discount = discount and discount.percentage > 0

    if include_tax:
        from tax.utils import get_tax_processor
        taxer = get_tax_processor(user=user)
        tax_class = product.taxClass

    details = {'SALE' : use_discount}

    variations = ProductPriceLookup.objects.filter(parentid=product.id).order_by("-price")
    if variations.count() == 0:
        if create:
            log.debug('Creating price lookup for %s', product)
            ProductPriceLookup.objects.smart_create_for_product(product)
            variations = ProductPriceLookup.objects.filter(parentid=product.id).order_by("-price")
        else:
            log.warning('You must run satchmo_rebuild_pricing and add it to a cron-job to run every day, or else the product details will not work for product detail pages.')
    for detl in variations:
        key = detl.key
        if details.has_key(key):
            detail = details[key]
            qty = detl.quantity
        else:
            detail = {}
            detail['SLUG'] = detl.productslug

            if not detl.active:
                qty = round_decimal('-1.0')
            elif ignore_stock:
                qty = round_decimal('10000.0')
            else:
                qty = round_decimal(detl.items_in_stock)

            detail['QTY'] = round_decimal(qty)

            detail['PRICE'] = {}

            if use_discount:
                detail['SALE'] = {}

            if include_tax:
                detail['TAXED'] = {}
                if use_discount:
                    detail['TAXED_SALE'] = {}

	    if detl.productimage_set:
	            detail['ADDITIONAL_IMAGES'] = [u"%s" % prodimg.picture for prodimg in detl.productimage_set.all()]

            details[key] = detail

        qtykey = "%d" % detl.quantity

        price = detl.dynamic_price

        detail['PRICE'][qtykey] = moneyfmt(price)
        if use_discount:
            detail['SALE'][qtykey] = moneyfmt(calc_discounted_by_percentage(price, discount.percentage))

        if include_tax:
            tax_price = taxer.by_price(tax_class, price) + price
            detail['TAXED'][qtykey] = moneyfmt(tax_price)
            if use_discount:
                detail['TAXED_SALE'][qtykey] = moneyfmt(calc_discounted_by_percentage(tax_price, discount.percentage))

    return details
Esempio n. 9
0
    def get_recurring_charge_data(self, testing=False):
        """Build the list of dictionaries needed to process a recurring charge.
        
        Because Authorize can only take one subscription at a time, we build a list
        of the transaction dictionaries, for later sequential posting.
        """
        if not self.arb_enabled:
            return []
        
        # get all subscriptions from the order
        subscriptions = self.get_recurring_orderitems()
        
        if len(subscriptions) == 0:
            self.log_extra('No subscription items')
            return []

        settings = self.settings            
        # set up the base dictionary
        trans = {}

        if self.is_live():
            conn = settings.ARB_CONNECTION.value
            self.log_extra('Using live recurring charge connection.')
        else:
            conn = settings.ARB_CONNECTION_TEST.value
            self.log_extra('Using test recurring charge connection.')
        
        shop_config = Config.objects.get_current()
        
        trans['connection'] = conn
        trans['config'] = {
            'merchantID' : settings.LOGIN.value,
            'transactionKey' : settings.TRANKEY.value,
            'shop_name' : shop_config.store_name,
        }
        trans['order'] = self.order
        trans['card'] = self.order.credit_card
        trans['card_expiration'] =  "%4i-%02i" % (self.order.credit_card.expire_year, self.order.credit_card.expire_month)
        
        translist = []
        taxer = get_tax_processor(user = self.order.contact.user)
        
        for subscription in subscriptions:
            product = subscription.product
            subtrans = trans.copy()
            subtrans['subscription'] = subscription
            subtrans['product'] = product
            
            sub = product.subscriptionproduct
            
            trial = sub.get_trial_terms(0)
            if trial:
                price = trunc_decimal(trial.price, 2)
                trial_amount = price
                if price and subscription.product.taxable:
                    trial_amount = taxer.by_price(subscription.product.taxClass, price)
                    #todo, maybe add shipping for trial?
                amount = sub.recurring_price()
                trial_occurrences = trial.occurrences
                if not trial_occurrences:
                    self.log.warn("Trial expiration period is less than one recurring billing cycle. " +
                        "Authorize does not allow this, so the trial period has been adjusted to be equal to one recurring cycle.")
                    trial_occurrences = 1
            else:
                trial_occurrences = 0
                trial_amount = Decimal('0.00')
                amount = subscription.total_with_tax

            occurrences = sub.recurring_times + trial_occurrences
            if occurrences > 9999:
                occurrences = 9999

            subtrans['occurrences'] = occurrences
            subtrans['trial_occurrences'] = trial_occurrences
            subtrans['trial'] = trial
            subtrans['trial_amount'] = trunc_decimal(trial_amount, 2)
            subtrans['amount'] = trunc_decimal(amount, 2)
            if trial:
                charged_today = trial_amount
            else:
                charged_today = amount
            
            charged_today = trunc_decimal(charged_today, 2)
                
            subtrans['charged_today'] = charged_today
            translist.append(subtrans)
            
        return translist
Esempio n. 10
0
    def force_recalculate_total(self, save=True):
        """Calculates sub_total, taxes and total."""
        zero = Decimal("0.0000000000")
        discount = Discount.objects.by_code(self.discount_code)
        discount.calc(self)
        self.discount = discount.total
        discounts = discount.item_discounts
        itemprices = []
        fullprices = []
        for lineitem in self.orderitem_set.all():
            lid = lineitem.id
            if lid in discounts:
                lineitem.discount = discounts[lid]
            else:
                lineitem.discount = zero
            if save:
                lineitem.save()

            itemprices.append(lineitem.sub_total)
            fullprices.append(lineitem.line_item_price)

        shipprice = Price()
        shipprice.price = self.shipping_cost
        shipadjust = PriceAdjustmentCalc(shipprice)
        if 'Shipping' in discounts:
            shipadjust += PriceAdjustment('discount', _('Discount'), discounts['Shipping'])

        signals.satchmo_shipping_price_query.send(self, adjustment=shipadjust)    
        self.shipping_discount = shipadjust.total_adjustment()

        if itemprices:
            item_sub_total = reduce(operator.add, itemprices)
        else:
            item_sub_total = zero

        if fullprices:
            full_sub_total = reduce(operator.add, fullprices)
        else:
            full_sub_total = zero

        self.sub_total = full_sub_total

        taxProcessor = get_tax_processor(self)
        totaltax, taxrates = taxProcessor.process()
        self.tax = totaltax

        # clear old taxes
        for taxdetl in self.taxes.all():
            taxdetl.delete()

        for taxdesc, taxamt in taxrates.items():
            taxdetl = OrderTaxDetail(order=self, tax=taxamt, description=taxdesc, method=taxProcessor.method)
            taxdetl.save()

        log.debug("Order #%i, recalc: sub_total=%s, shipping=%s, discount=%s, tax=%s",
            self.id,
            moneyfmt(item_sub_total), 
            moneyfmt(self.shipping_sub_total),
            moneyfmt(self.discount), 
            moneyfmt(self.tax))

        self.total = Decimal(item_sub_total + self.shipping_sub_total + self.tax)

        if save:
            self.save()
Esempio n. 11
0
    def get_recurring_charge_data(self, testing=False):
        """Build the list of dictionaries needed to process a recurring charge.

        Because Authorize can only take one subscription at a time, we build a list
        of the transaction dictionaries, for later sequential posting.
        """
        if not self.arb_enabled:
            return []

        # get all subscriptions from the order
        subscriptions = self.get_recurring_orderitems()

        if len(subscriptions) == 0:
            self.log_extra('No subscription items')
            return []

        settings = self.settings
        # set up the base dictionary
        trans = {}

        if self.is_live():
            conn = settings.ARB_CONNECTION.value
            self.log_extra('Using live recurring charge connection.')
        else:
            conn = settings.ARB_CONNECTION_TEST.value
            self.log_extra('Using test recurring charge connection.')

        shop_config = Config.objects.get_current()

        trans['connection'] = conn
        trans['config'] = {
            'merchantID' : settings.LOGIN.value,
            'transactionKey' : settings.TRANKEY.value,
            'shop_name' : shop_config.store_name,
        }
        trans['order'] = self.order
        trans['card'] = self.order.credit_card
        trans['card_expiration'] =  "%4i-%02i" % (self.order.credit_card.expire_year, self.order.credit_card.expire_month)

        translist = []
        taxer = get_tax_processor(user = self.order.contact.user)

        for subscription in subscriptions:
            product = subscription.product
            subtrans = trans.copy()
            subtrans['subscription'] = subscription
            subtrans['product'] = product

            sub = product.subscriptionproduct

            trial = sub.get_trial_terms(0)
            if trial:
                price = trunc_decimal(trial.price, 2)
                trial_amount = price
                if price and subscription.product.taxable:
                    trial_amount = taxer.by_price(subscription.product.taxClass, price)
                    #todo, maybe add shipping for trial?
                amount = sub.recurring_price()
                trial_occurrences = trial.occurrences
                if not trial_occurrences:
                    self.log.warn("Trial expiration period is less than one recurring billing cycle. " +
                        "Authorize does not allow this, so the trial period has been adjusted to be equal to one recurring cycle.")
                    trial_occurrences = 1
            else:
                trial_occurrences = 0
                trial_amount = Decimal('0.00')
                amount = subscription.total_with_tax

            occurrences = sub.recurring_times + trial_occurrences
            if occurrences > 9999:
                occurrences = 9999

            subtrans['occurrences'] = occurrences
            subtrans['trial_occurrences'] = trial_occurrences
            subtrans['trial'] = trial
            subtrans['trial_amount'] = trunc_decimal(trial_amount, 2)
            subtrans['amount'] = trunc_decimal(amount, 2)
            if trial:
                charged_today = trial_amount
            else:
                charged_today = amount

            charged_today = trunc_decimal(charged_today, 2)

            subtrans['charged_today'] = charged_today
            translist.append(subtrans)

        return translist
Esempio n. 12
0
def productvariation_details(product, include_tax, user, create=False):
    """Build the product variation details, for conversion to javascript.

    Returns variation detail dictionary built like so:
    details = {
        "OPTION_KEY" : {
            "SLUG": "Variation Slug",
            "PRICE" : {"qty" : "$price", [...]},
            "SALE" : {"qty" : "$price", [...]},
            "TAXED" : "$taxed price",   # omitted if no taxed price requested
            "QTY" : 1
        },
        [...]
    }
    """

    ignore_stock = config_value('PRODUCT', 'NO_STOCK_CHECKOUT')
    discount = find_best_auto_discount(product)
    use_discount = discount and discount.percentage > 0

    if include_tax:
        from tax.utils import get_tax_processor
        taxer = get_tax_processor(user=user)
        tax_class = product.taxClass

    details = {'SALE': use_discount}

    variations = ProductPriceLookup.objects.filter(
        parentid=product.id).order_by("-price")
    if variations.count() == 0:
        if create:
            log.debug('Creating price lookup for %s', product)
            ProductPriceLookup.objects.smart_create_for_product(product)
            variations = ProductPriceLookup.objects.filter(
                parentid=product.id).order_by("-price")
        else:
            log.warning(
                'You must run satchmo_rebuild_pricing and add it to a cron-job to run every day, or else the product details will not work for product detail pages.'
            )
    for detl in variations:
        key = detl.key
        if details.has_key(key):
            detail = details[key]
            qty = detl.quantity
        else:
            detail = {}
            detail['SLUG'] = detl.productslug

            if not detl.active:
                qty = round_decimal('-1.0')
            elif ignore_stock:
                qty = round_decimal('10000.0')
            else:
                qty = round_decimal(detl.items_in_stock)

            detail['QTY'] = round_decimal(qty)

            detail['PRICE'] = {}

            if use_discount:
                detail['SALE'] = {}

            if include_tax:
                detail['TAXED'] = {}
                if use_discount:
                    detail['TAXED_SALE'] = {}

            if detl.productimage_set:
                detail['ADDITIONAL_IMAGES'] = [
                    u"%s" % prodimg.picture
                    for prodimg in detl.productimage_set.all()
                ]

            details[key] = detail

        qtykey = "%d" % detl.quantity

        price = detl.dynamic_price

        detail['PRICE'][qtykey] = moneyfmt(price)
        if use_discount:
            detail['SALE'][qtykey] = moneyfmt(
                calc_discounted_by_percentage(price, discount.percentage))

        if include_tax:
            tax_price = taxer.by_price(tax_class, price) + price
            detail['TAXED'][qtykey] = moneyfmt(tax_price)
            if use_discount:
                detail['TAXED_SALE'][qtykey] = moneyfmt(
                    calc_discounted_by_percentage(tax_price,
                                                  discount.percentage))

    return details