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)
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
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
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
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
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()
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)
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
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
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()
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