<commit_before>from django.contrib.sites.models import Site
from livesettings import config_value
from l10n.utils import moneyfmt
from product.models import ProductVariation, Option, split_option_unique_id, \
                                   ProductPriceLookup, OptionGroup, Discount, \
                                   NullDiscount, Product
from satchmo_utils.numbers import RoundedDecimalError, round_decimal
import datetime
import logging
import types
from decimal import Decimal

try:
    from decimal import Decimal
except:
    from django.utils._decimal import Decimal

log = logging.getLogger('product.utils')

def calc_discounted_by_percentage(price, percentage):
    if not percentage:
        return price
    if percentage > 1:
        log.warn("Correcting discount percentage, should be less than 1, is %s", percentage)
        percentage = percentage/100

    work = price * (1-percentage)
    cents = Decimal("0.01")
    return work.quantize(cents)

def find_auto_discounts(product):
    if not type(product) in (types.ListType, types.TupleType):
        product = (product,)
    today = datetime.date.today()
    discs = Discount.objects.filter(automatic=True, active=True, startDate__lte=today, endDate__gt=today)
    return discs.filter(validProducts__in=product).order_by('-percentage')

def find_best_auto_discount(product):
    discs = find_auto_discounts(product)
    if len(discs) > 0:
        return discs[0]
    else:
        return None

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)
        tax_class = product.taxClass

    details = {'SALE' : use_discount}
    
    curr = config_value('LANGUAGE','CURRENCY')
    curr = curr.replace("_", " ")

    variations = ProductPriceLookup.objects.filter(parentid=product.id)
    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)
        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'] = {}
                
            details[key] = detail

        qtykey = "%d" % detl.quantity
        
        price = detl.dynamic_price
        
        detail['PRICE'][qtykey] = moneyfmt(price, curr=curr)
        if use_discount:
            detail['SALE'][qtykey] = moneyfmt(calc_discounted_by_percentage(price, discount.percentage), curr=curr)
        
        if include_tax:
            tax_price = taxer.by_price(tax_class, price) + price
            detail['TAXED'][qtykey] = moneyfmt(tax_price, curr=curr)
            detail['TAXED_SALE'][qtykey] = moneyfmt(calc_discounted_by_percentage(tax_price, discount.percentage), curr=curr)
                
    return details
    
def rebuild_pricing():
    site = Site.objects.get_current()
    for lookup in ProductPriceLookup.objects.filter(siteid=site.id):
        lookup.delete()
    
    products = Product.objects.active_by_site(site=site, variations=False)
    
    productct = products.count()<commit_msg>Fix another tax discount issue. Closes #818<commit_after>from django.contrib.sites.models import Site
from livesettings import config_value
from l10n.utils import moneyfmt
from product.models import ProductVariation, Option, split_option_unique_id, \
                                   ProductPriceLookup, OptionGroup, Discount, \
                                   NullDiscount, Product
from satchmo_utils.numbers import RoundedDecimalError, round_decimal
import datetime
import logging
import types
from decimal import Decimal

try:
    from decimal import Decimal
except:
    from django.utils._decimal import Decimal

log = logging.getLogger('product.utils')

def calc_discounted_by_percentage(price, percentage):
    if not percentage:
        return price
    if percentage > 1:
        log.warn("Correcting discount percentage, should be less than 1, is %s", percentage)
        percentage = percentage/100

    work = price * (1-percentage)
    cents = Decimal("0.01")
    return work.quantize(cents)

def find_auto_discounts(product):
    if not type(product) in (types.ListType, types.TupleType):
        product = (product,)
    today = datetime.date.today()
    discs = Discount.objects.filter(automatic=True, active=True, startDate__lte=today, endDate__gt=today)
    return discs.filter(validProducts__in=product).order_by('-percentage')

def find_best_auto_discount(product):
    discs = find_auto_discounts(product)
    if len(discs) > 0:
        return discs[0]
    else:
        return None

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}
    
    curr = config_value('LANGUAGE','CURRENCY')
    curr = curr.replace("_", " ")

    variations = ProductPriceLookup.objects.filter(parentid=product.id)
    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)
        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'] = {}
                
            details[key] = detail

        qtykey = "%d" % detl.quantity
        
        price = detl.dynamic_price
        
        detail['PRICE'][qtykey] = moneyfmt(price, curr=curr)
        if use_discount:
            detail['SALE'][qtykey] = moneyfmt(calc_discounted_by_percentage(price, discount.percentage), curr=curr)
        
        if include_tax:
            tax_price = taxer.by_price(tax_class, price) + price
            detail['TAXED'][qtykey] = moneyfmt(tax_price, curr=curr)
            if use_discount:
                detail['TAXED_SALE'][qtykey] = moneyfmt(calc_discounted_by_percentage(tax_price, discount.percentage), curr=curr)
                
    return details
    
def rebuild_pricing():
    site = Site.objects.get_current()
    for lookup in ProductPriceLookup.objects.filter(siteid=site.id):
        lookup.delete()
    
    products = Product.objects.active_by_site(site=site, variations=False)
    
    productct = products.count()
{'fraction_non_alphanumeric': 0.09909148531586731, 'fraction_numerical': 0.005387703359391507, 'mean_word_length': 2.3618607954545454, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '335782', 'n_tokens_mistral': 2807, 'n_tokens_neox': 2727, 'n_words': 625}