def self_save_billing(self): cust = self.request.ctx.customer self.forbid_if(cust.campaign.company.enterprise_id != self.enterprise_id) bill = cust.billing if not bill: bill = Billing.create(cust, True) bill.set_cc_info(self.request.POST.get('bill_cc_num'), self.request.POST.get('bill_cc_cvv')) bill.cc_exp = self.request.POST.get('bill_cc_exp') bill.cc_token = self.request.POST.get('bill_cc_token') if 'bill_exp_month' in self.request.POST and 'bill_exp_year' in self.request.POST: bill.cc_exp = self.request.POST.get('bill_exp_month') + '/' + self.request.POST.get('bill_exp_year') bill.bind(self.request.POST, False, 'bill') bill.save() cust.save() self.db_flush() api = BaseBillingApi.create_api(cust.campaign.company.enterprise) if api.update_billing(cust, bill): Status.add(cust, cust, Status.find_event(self.enterprise_id, cust, 'NOTE'), 'Billing Updated at gateway') self.flash('Successfully saved billing information.') cust.invalidate_caches() return self.find_redirect() else: (_, last_note) = api.get_last_status() self.flash('Unable to save credit card information: %s' % last_note) log.error('CC CHANGE DECLINED %s %s %s' % (cust.customer_id, cust.email, last_note)) self.raise_redirect(self.request.referrer)
def delete(self): customer_id = self.request.matchdict.get('customer_id') customer = Customer.load(customer_id) self.forbid_if(not customer or customer.campaign.company.enterprise_id != self.enterprise_id) customer.mod_dt = util.now() customer.delete_dt = util.now() Status.add(customer, customer, StatusEvent.find(self.enterprise_id, 'Customer', 'DELETED'), 'Customer Deleted') return 'True'
def remove(self): lis = Listing.load(self.request.matchdict.get('listing_id')) cust = self.request.ctx.customer self.forbid_if(not lis or not cust or lis.customer.customer_id != cust.customer_id or cust.campaign.company.enterprise_id != self.enterprise_id) lis.soft_delete() Status.add(cust, lis, Status.find_event(self.enterprise_id, lis, 'CLOSED'), 'Listing Deleted: %s' % self.request.POST.get('title')) return 'True'
def send_to_customer(self, sender, customer, order=None, extra_message=None, subject=None): #pylint: disable-msg=R0913 output = self.render(customer, order, extra_message) subject = subject if subject else self.tokenize(self.subject, customer, order) mail = UserMail(sender) mail.send(customer.email, subject, output) Status.add(customer, self, Status.find_event(customer.campaign.company.enterprise_id, self, 'SENT'), 'Sent %s (%s)' % (self.name, subject)) return True
def save_status(self): product_id = self.request.POST['product_id'] product = Product.load(product_id) self.forbid_if(not product or product.company.enterprise_id != self.enterprise_id) event = StatusEvent.load(self.request.POST['event_id']) self.forbid_if(not event or (not event.is_system and event.enterprise_id != self.enterprise_id)) note = self.request.POST.get('note') Status.add(None, product, event, note, self.request.ctx.user) return HTTPFound('/crm/product/show_history/%s' % product_id)
def delete(self): product_id = self.request.matchdict.get('product_id') product = Product.load(product_id) self.forbid_if(not product or str(product.company.enterprise_id) != str(self.enterprise_id)) product.mod_dt = util.now() product.delete_dt = util.now() Status.add(None, product, StatusEvent.find(self.enterprise_id, 'Product', 'DELETED'), 'Product Deleted') product.invalidate_caches() return 'True'
def upload_asset(self): """ KB: [2011-03-23]: Take this file and hash its name up to put it in a sensible directory. """ listing_id = self.request.matchdict.get('listing_id') listing_hash = self.request.matchdict.get('hash') lis = Listing.load(listing_id) self.forbid_if(not lis or lis.hash != listing_hash) ass = Asset.create_new(lis, self.enterprise_id, self.request) Status.add(lis.customer, lis, Status.find_event(self.enterprise_id, lis, 'ASSET_UPLOAD'), ass.name) return str(ass.id)
def _cancel_order_impl(self, order_id, reason, by_customer=False): codr = CustomerOrder.load(order_id) self.forbid_if(not codr) cust = codr.customer api = BaseBillingApi.create_api(cust.campaign.company.enterprise) if api.cancel_order(codr, cust.billing): Status.add(cust, cust, Status.find_event(self.enterprise_id, cust, 'NOTE'), 'Billing Cancelled at gateway') codr.cancel(reason, by_customer) cust.invalidate_caches()
def save_status(self): purchase_order_id = self.request.matchdict.get('purchase_order_id') purchase = PurchaseOrder.load(purchase_order_id) self.forbid_if(not purchase or purchase.company.enterprise_id != self.enterprise_id) event = StatusEvent.load(self.request.POST.get('event_id')) self.forbid_if(not event or not self.request.POST.get('event_id') or (not event.is_system and event.enterprise_id != self.enterprise_id)) note = self.request.POST.get('note') Status.add(None, purchase, event, note, self.request.ctx.user) self.flash("Saved status") return HTTPFound('/crm/purchase/edit/%s' % purchase_order_id)
def delete_purchase_order_item(self): purchase_order_id = self.request.matchdict.get('purchase_order_id') order_item_id = self.request.matchdict.get('order_item_id') porder = PurchaseOrder.load(purchase_order_id) self.forbid_if(not porder) poi = PurchaseOrderItem.load(order_item_id) self.forbid_if(not poi or poi.purchase_order != porder) prod = poi.product poi.delete() Status.add(None, porder, Status.find_event(self.enterprise_id, porder, 'MODIFIED'), 'Purchase Order %s. "%s" removed.' % ('MODIFIED', prod.name), self.request.ctx.user) poi.flush() return 'True'
def complete(self): purchase_order_id = self.request.matchdict.get('purchase_order_id') porder = PurchaseOrder.load(purchase_order_id) self.forbid_if(not porder or porder.company.enterprise_id != self.enterprise_id) porder.complete_dt = util.today() porder.save() for oitem in porder.order_items: if not oitem.complete_dt: oitem.complete_dt = util.today() oitem.save() InventoryJournal.create_new(oitem.product, 'Item Receipt', oitem.quantity) Status.add(None, porder, Status.find_event(self.enterprise_id, porder, 'COMPLETED'), 'Purchase Order Completed', self.request.ctx.user) return 'True'
def save(self): porder = PurchaseOrder.load(self.request.POST.get('purchase_order_id')) new = False if not porder: new = True porder = PurchaseOrder() porder.bind(self.request.POST) porder.save() porder.flush() Status.add(None, porder, Status.find_event(self.enterprise_id, porder, 'CREATED' if new else 'MODIFIED'), 'Purchase Order %s' % ('CREATED' if new else 'MODIFIED'), self.request.ctx.user) self.db_flush() self.flash('Successfully saved PO %s.' % porder.purchase_order_id) return HTTPFound('/crm/purchase/edit/%s' % porder.purchase_order_id)
def complete_item(self): purchase_order_id = self.request.matchdict.get('purchase_order_id') order_item_id = self.request.matchdict.get('order_item_id') porder = PurchaseOrder.load(purchase_order_id) self.forbid_if(not porder) poi = PurchaseOrderItem.load(order_item_id) self.forbid_if(not poi or poi.purchase_order != porder or poi.complete_dt) poi.complete_dt = util.today() poi.save() poi.flush() InventoryJournal.create_new(poi.product, 'Item Receipt', poi.quantity) Status.add(None, porder, Status.find_event(self.enterprise_id, porder, 'COMPLETED'), 'Purchase Order Item "%s" Completed' % poi.product.name, self.request.ctx.user) return 'True'
def show_history(self): product_id = self.request.matchdict['product_id'] product = Product.load(product_id) self.forbid_if(not product or product.company.enterprise_id != self.enterprise_id) return {'product' : product, 'events' : util.select_list(StatusEvent.find_all_applicable(self.enterprise_id, product), 'event_id', 'display_name'), 'history' : Status.find(product) }
def save_purchase_order_item(self): purchase_order_id = self.request.matchdict.get('purchase_order_id') self.forbid_if(not 'product_id' in self.request.GET or not self.request.GET.get('product_id')) poi = PurchaseOrderItem.load(self.request.POST.get('order_item_id')) if not poi: poi = PurchaseOrderItem() poi.purchase_order_id = purchase_order_id poi.bind(self.request.POST) poi.product_id = self.request.GET.get('product_id') poi.note = self.request.POST.get('order_note') poi.save() poi.flush() porder = poi.purchase_order Status.add(None, porder, Status.find_event(self.enterprise_id, porder, 'MODIFIED'), 'Purchase Order %s. "%s" added.' % ('MODIFIED', poi.product.name), self.request.ctx.user) self.db_flush() return '{"id": "%s"}' % poi.order_item_id
def show_history(self): customer_id = self.request.matchdict.get('customer_id') customer = Customer.load(customer_id) self.forbid_if(not customer or customer.campaign.company.enterprise_id != self.enterprise_id) return { 'customer' : customer, 'history' : Status.find_by_customer(customer, self.offset), 'offset' : self.offset }
def show_history(self): purchase_order_id = self.request.matchdict.get('purchase_order_id') purchase = PurchaseOrder.load(purchase_order_id) self.forbid_if(not purchase or purchase.company.enterprise_id != self.enterprise_id) return { 'history' : Status.find(purchase), 'purchase' : purchase, 'offset' : self.offset }
def show_status_dialog(self): customer_id = self.request.matchdict.get('customer_id') status_id = self.request.matchdict.get('status_id') customer = Customer.load(customer_id) self.forbid_if(not customer or customer.campaign.company.enterprise_id != self.enterprise_id) status = Status.load(status_id) self.forbid_if(not status or str(customer.customer_id) != str(customer_id)) return { 'customer' : customer, 'status' : status }
def cancel(self, reason, by_customer=False): self.cancel_dt = datetime.datetime.date(datetime.datetime.now()) for oitem in self.active_items: prod = oitem.product InventoryJournal.create_new(prod, "Cancelled Order", oitem.quantity, oitem) oitem.delete_dt = util.today() oitem.save() journals = Journal.find_all_by_order(self) for j in journals: j.delete_dt = util.today() j.save() msg = "Order Canceled" if not by_customer else "Order Cancelled by Customer" Status.add( self.customer, self, Status.find_event(self.customer.campaign.company.enterprise_id, self, "CREATED"), "%s : %s" % (msg, reason), ) self.save()
def augment_order(self, customer, product, campaign, user_created, quantity=0, incl_tax=True): enterprise_id = product.company.enterprise_id item = OrderItem() item.order = self item.product = product item.creator = user_created discount = product.get_discount_price(campaign) retail = product.get_price(campaign) item.unit_price = discount if discount else retail item.unit_cost = product.unit_cost item.unit_discount_price = discount if discount else 0.0 item.unit_retail_price = retail item.quantity = quantity if campaign.tax_rate and incl_tax: item.tax = (item.unit_price * item.quantity) * campaign.tax_rate if quantity > 0: if product.track_inventory: InventoryJournal.create_new(product, "Sale", item.quantity, item) item.save() if product.can_have_children(): item.flush() # we need this to get the parent ID. children = product.get_children() if children and len(children) > 0: for kid in children: child_item = OrderItem() child_item.order = self child_item.parent_id = item.order_item_id child_item.product = kid.child child_item.creator = user_created child_item.unit_price = 0.0 child_item.unit_discount_price = 0.0 child_item.unit_cost = product.unit_cost child_item.quantity = kid.child_quantity if kid.child.track_inventory: InventoryJournal.create_new(kid.child, "Sale", child_item.quantity, child_item) Status.add(customer, self, Status.find_event(enterprise_id, self, "MODIFIED"), "Order Modified ") self.save() self.flush() return item
def save(self): self.forbid_if('redir' not in self.request.POST) redir = self.request.POST.get('redir') cust = self.request.ctx.customer lis = Listing.load(self.request.POST.get('listing_id')) if not lis: lis = Listing() lis.customer = cust lis.company = self.request.ctx.campaign.company lis.site = self.request.ctx.site # l.ip = util.self.request_ip() # g = Geo() # gip = g.by_ip(l.ip) # if gip and gip['latitude'] and gip['longitude']: # l.latitude = gip['latitude'] if 'latitude' in gip else None # l.longitude = gip['longitude'] if 'longitude' in gip else None # l.city = gip['city'] if 'city' in gip else None # l.state = gip['region_name'] if 'region_name' in gip else None # l.zip = gip['postal_code'] if 'postal_code' in gip else None # l.country = gip['country_code'] if 'country_code' in gip else None # l.dma = gip['dma_code'] if 'dma_code' in gip else None # this overrides the original lat/lng settings if they are coming from # the POST instead of the geo ip. lis.bind(self.request.POST, True) lis.save() self.db_flush() # for key in self.request.POST.keys(): # if key.startswith('asset_'): # ass = Asset.load(key[6:]) # ass.fk_type = 'Listing' # ass.fk_id = lis.listing_id # ass.save() Status.add(cust, lis, Status.find_event(self.enterprise_id, lis, 'OPEN'), 'Listing Created: %s' % self.request.POST.get('title')) self.flash('Listing: "%s" saved' % lis.title) return HTTPFound('%s?listing_id=%s&post=1' % (redir, lis.listing_id))
def contact(self): camp = self.request.ctx.campaign message = self.request.POST.get('message') email = self.request.POST.get('email') msg = "%s %s<br>(%s)<br><br>%s<br><br>%s" % (self.request.POST.get('fname'), self.request.POST.get('lname'), email, self.request.POST.get('phone'), message) if util.nvl(self.request.POST.get('save')): cust = Customer.find(email, camp) if not cust: cust = Customer() cust.campaign = camp cust.bind(self.request.POST) cust.phone = cust.phone[:20] if cust.phone else None # prevents people from putting in "904-716-7487 (mobile)" and it barfs cust.save() Status.add(cust, cust, Status.find_event(self.enterprise_id, cust, 'NOTE'), 'NOTE FROM CUSTOMER\n%s' % message) email_info = camp.get_email_info() mail = UserMail(camp) mail.send(email_info.email, 'SITE CONTACT FORM %s' % self.request.host, msg) return self.find_redirect()
def return_item(self): customer_id = self.request.matchdict.get('customer_id') order_id = self.request.matchdict.get('order_id') order_item_id = self.request.matchdict.get('order_item_id') customer = Customer.load(customer_id) self.forbid_if(not customer or customer.campaign.company.enterprise_id != self.enterprise_id) order = customer.get_order(order_id) self.forbid_if(not order) order_item = OrderItem.load(order_item_id) self.forbid_if(not order_item or str(order_item.order.order_id) != str(order.order_id)) user = self.request.ctx.user return_type = self.request.POST.get('rt_refund_type') quantity_returned = float(self.request.POST.get('quantity_returned')) credit_amount = float(self.request.POST.get('credit_amount')) jrnl = Journal.create_new(credit_amount, customer, order, user, return_type) ret = ProductReturn.create_new(order_item.product, order_item.order, quantity_returned, credit_amount, jrnl, user) status_note = "'%s' returned. $%.2f refunded by %s" % (order_item.product.name, credit_amount, return_type) Status.add(customer, order_item, Status.find_event(self.enterprise_id, order_item, 'RETURN'), status_note) order_item.quantity -= quantity_returned if order_item.quantity == 0: order_item.delete_dt = util.today() order_item.save() if order_item.product.track_inventory: InventoryJournal.create_new(order_item.product, 'Return', quantity_returned, order_item, None, None, ret) for attr_kid in order_item.children: Status.add(customer, attr_kid, Status.find_event(self.enterprise_id, attr_kid, 'RETURN'), status_note) attr_kid_prod = attr_kid.product if attr_kid_prod.track_inventory: InventoryJournal.create_new(attr_kid_prod, 'Return', quantity_returned, attr_kid) self.flash(status_note) if len(order.active_items) == 0: # KB: [2012-09-06]: Deleted the one thing out of this # order. Kill the order status_note = 'Only item in order returned. Order cancelled.' self._cancel_order_impl(order_id, status_note, False) self.flash(status_note) ret = HTTPFound('/crm/customer/show_orders/%s' % customer_id) else: ret = HTTPFound('/crm/customer/edit_order_dialog/%s/%s' % (customer_id, order_id)) customer.invalidate_caches() return ret
def _apply_payment(self, customer_id, order_id, pmt_amount=None, pmt_method=None, pmt_note=None): #pylint: disable-msg=R0913 """ KB: [2011-03-09]: Check that everything is kosher Create a journal entry for the order for the amount and type specified in the UI Create a status noting the type and amount of the payment applied. """ customer = Customer.load(customer_id) self.forbid_if(not customer or customer.campaign.company.enterprise_id != self.enterprise_id) order = customer.get_order(order_id) self.forbid_if(not order) user = self.request.ctx.user current_customer_balance = customer.get_current_balance() #prior_payments_applied = order.total_payments_applied() prior_total_due = order.total_payments_due() balance_amount_to_apply = float(self.request.POST.get('pmt_balance_amount_to_apply', 0.0)) amt = float(util.nvl(pmt_amount, self.request.POST.get('pmt_amount'))) method = util.nvl(pmt_method, self.request.POST.get('pmt_method')) note = util.nvl(pmt_note, self.request.POST.get('pmt_note')) self.forbid_if(round(amt + balance_amount_to_apply, 2) > round(prior_total_due, 2), "amt + balance_amount_to_apply > prior_total_due") self.forbid_if(current_customer_balance > 0 and round(balance_amount_to_apply, 2) > round(current_customer_balance, 2), "balance_amount_to_apply > current_customer_balance") pmt_type = 'PartialPayment' if amt == prior_total_due: pmt_type = 'FullPayment' Journal.create_new(amt, customer, order, user, pmt_type, method, note) status_note = '%s applied: $%s' % (pmt_type, util.money(amt)) Status.add(customer, order, Status.find_event(self.enterprise_id, order, 'PAYMENT_APPLIED'), status_note) self.flash(status_note) if balance_amount_to_apply > 0: Journal.create_new(balance_amount_to_apply, customer, order, user, 'CreditDecrease') status_note = '%s applied: $%s' % ('CreditDecrease', util.money(balance_amount_to_apply)) Status.add(customer, order, Status.find_event(self.enterprise_id, order, 'PAYMENT_APPLIED'), status_note) self.flash(status_note) customer.invalidate_caches() customer.flush() return 'True'
def save_status(self): customer_id = self.request.matchdict.get('customer_id') customer = Customer.load(customer_id) self.forbid_if(not customer or customer.campaign.company.enterprise_id != self.enterprise_id) event = StatusEvent.load(self.request.POST.get('event_id')) self.forbid_if(not event or not self.request.POST.get('event_id') or (not event.is_system and event.enterprise_id is not None and event.enterprise_id != self.enterprise_id)) order = None note = self.request.POST.get('note') if self.request.POST.get('order_id'): order = CustomerOrder.load(self.request.POST.get('order_id')) self.forbid_if(not order or order.campaign.company.enterprise_id != self.enterprise_id) Status.add(customer, order, event, note, self.request.ctx.user) self.flash('Statused Order to %s' % event.display_name) elif self.request.POST.get('order_item_id'): order_item = OrderItem.load(self.request.POST.get('order_item_id')) self.forbid_if(not order_item or order_item.order.campaign.company.enterprise_id != self.enterprise_id) Status.add(customer, order_item, event, note, self.request.ctx.user) self.flash('Statused Item to %s' % event.display_name) else: Status.add(customer, customer, event, note, self.request.ctx.user) self.flash('Statused Customer to %s' % event.display_name) customer.invalidate_caches() return self.find_redirect()
def edit_order(self): #pylint: disable-msg=R0915,R0912 customer_id = self.request.matchdict.get('customer_id') order_id = self.request.matchdict.get('order_id') oids_to_delete = self.request.POST.getall('order_items_to_delete[]') customer = Customer.load(customer_id) self.forbid_if(not customer or customer.campaign.company.enterprise_id != self.enterprise_id) order = customer.get_order(order_id) self.forbid_if(not order) order.shipping_total = self.request.POST.get('shipping_total') if self.request.POST.get('shipping_total') else 0.0 order.create_dt = self.request.POST.get('create_dt') if self.request.POST.get('create_dt') else order.create_dt order.save() total_payments_applied = order.total_payments_applied() for oid in oids_to_delete: oitem = OrderItem.load(oid) Status.add(customer, oitem, Status.find_event(self.enterprise_id, oitem, 'DELETED'), 'OrderItem deleted ') prod = oitem.product if prod.track_inventory: InventoryJournal.create_new(prod, 'Cancelled Item', oitem.quantity, oitem) for attr_kid in oitem.children: Status.add(customer, attr_kid, Status.find_event(self.enterprise_id, attr_kid, 'DELETED'), 'OrderItem deleted ') attr_kid_prod = attr_kid.product if attr_kid_prod.track_inventory: InventoryJournal.create_new(attr_kid_prod, 'Cancelled Item', oitem.quantity, attr_kid) attr_kid.soft_delete() oitem.soft_delete() # extract order_items[27][quantity] to set those properties. order_items = {} for key in self.request.POST.keys(): if key.startswith('order_items'): match = re.search(r'^.*\[(.*)\]\[(.*)\]', key) if match: order_item_id = match.group(1) attr = match.group(2) new_val = float(self.request.POST.get(key)) if attr != 'product_id' else self.request.POST.get(key) # KB: [2011-03-07]: If the ID ends in '_', its not really an ID but a new item. # product_id will only show up as non-null in the hash of a new product if order_item_id[-1] == '_': order_item_product = Product.load(self.request.POST.get('order_items[%s][product_id]' % order_item_id)) if not order_items.has_key(order_item_id): order_items[order_item_id] = order.augment_order(customer, order_item_product, customer.campaign, self.request.ctx.user) oitem = order_items[order_item_id] assert oitem.product is not None if 'quantity' == attr: new_val = float(new_val) if order_item_product.track_inventory: InventoryJournal.create_new(order_item_product, 'Sale', new_val, oitem) setattr(oitem, attr, new_val) oitem.save() else: if not order_items.has_key(order_item_id): order_items[order_item_id] = OrderItem.load(order_item_id) oitem = order_items[order_item_id] order_item_product = oitem.product if util.money(getattr(oitem, attr)) != util.money(new_val): Status.add(customer, oitem, Status.find_event(self.enterprise_id, oitem, 'MODIFIED'), 'Order Item modified: (id=%s). %s : %s -> %s' % (oitem.order_item_id, attr, util.money(getattr(oitem, attr)), util.money(new_val))) if 'quantity' == attr: new_val = float(new_val) if not total_payments_applied: if order_item_product.track_inventory: InventoryJournal.cleanup(oitem, 'Sale') InventoryJournal.create_new(order_item_product, 'Sale', new_val, oitem) setattr(oitem, attr, new_val) oitem.save() Status.add(customer, order, Status.find_event(self.enterprise_id, order, 'MODIFIED'), 'Order modified') customer.invalidate_caches() self.flash("Saved Order") return 'True'
def create_new(cart, customer, enterprise_id, campaign, user_created, order_note=None, incl_tax=True): """ KB: [2010-09-09]: Given a cart full of products, create a new order and return it. if a given product is a parent, then create an kid order_item of zero cost and attach it to the parent. """ cord = CustomerOrder() cord.creator = user_created cord.customer = customer cord.campaign = campaign cord.shipping_total = util.nvl(cart.shipping_total, 0.0) cord.shipping_note = cart.shipping_selection_name cord.handling_total = util.nvl(cart.handling_total, 0.0) cord.shipping_addr1 = cart.shipping_addr1 cord.shipping_addr2 = cart.shipping_addr2 cord.shipping_city = cart.shipping_city cord.shipping_state = cart.shipping_state cord.shipping_zip = cart.shipping_zip cord.shipping_country = cart.shipping_country cord.shipping_phone = cart.shipping_phone cart.calculate_cart_discount_for_order(cord) cord.note = order_note cord.save() cord.flush() for cart_item in cart.items: prd = Product.load(cart_item["product"].product_id) item = OrderItem() item.order = cord item.product = prd item.creator = user_created item.start_dt = cart_item["start_dt"] item.note = cart_item["note"] item.save() item.flush() attribute_order_items = [] for attribute_product_id in cart_item["attributes"].keys(): attribute_order_item = OrderItem() attribute_order_item.parent_id = item.order_item_id attribute_order_item.order = cord ao_prd = Product.load(attribute_product_id) attribute_order_item.product = ao_prd attribute_order_item.creator = user_created attribute_order_item.unit_cost = ao_prd.unit_cost attribute_order_item.unit_discount_price = ao_prd.get_discount_price(campaign) attribute_order_item.unit_retail_price = ao_prd.get_retail_price(campaign) attribute_order_item.quantity = cart_item["attributes"][attribute_product_id]["quantity"] attribute_order_item.save() attribute_order_items.append(attribute_order_item) # KB: [2013-02-24]: Discount is calculated by using the highest price of the discounts for the product and all of its selected attributes discount = max( [util.nvl(aois.unit_discount_price) for aois in attribute_order_items] + [prd.get_discount_price(campaign)] ) # KB: [2013-02-24]: Retail is calculated by using the highest price of the retail prices for the product and all its selected attributes. retail = max( [util.nvl(aois.unit_retail_price, 0.0) for aois in attribute_order_items] + [cart_item["base_price"] if "base_price" in cart_item else prd.get_retail_price(campaign)] ) item.quantity = float(cart_item["quantity"]) item.unit_price = discount if discount else retail if campaign.tax_rate and incl_tax: item.tax = (item.unit_price * item.quantity) * campaign.tax_rate item.unit_cost = prd.unit_cost item.unit_discount_price = discount if discount else None item.unit_retail_price = retail item.save() if prd.track_inventory: InventoryJournal.create_new(prd, "Sale", int(item.quantity), item) if item.unit_discount_price is not None: discount = DiscountProduct.find_by_product(prd) Journal.create_new( (item.unit_retail_price - item.unit_discount_price) * int(item.quantity), customer, cord, None, typ="AutomaticDiscount", attachment=discount, ) Status.add( customer, item, Status.find_event(enterprise_id, item, "CREATED"), "Item added to order %s @ $%s" % (prd.name, util.money(item.unit_price)), ) if prd.can_have_children(): item.flush() # we need this to get the parent ID. children = prd.get_children() if children and len(children) > 0: for kid in children: child_item = OrderItem() child_item.order = cord child_item.parent_id = item.order_item_id child_item.product = kid.child child_item.creator = user_created child_item.start_dt = cart_item["start_dt"] child_item.unit_price = 0.0 child_item.unit_discount_price = None child_item.unit_retail_price = 0.0 child_item.unit_cost = prd.unit_cost child_item.quantity = kid.child_quantity if kid.child.track_inventory: InventoryJournal.create_new(kid.child, "Sale", child_item.quantity, child_item) Status.add(customer, cord, Status.find_event(enterprise_id, cord, "CREATED"), "Order created ") if cord.discount: discount_amount = None if cord.discount.percent_off: item_price = cord.total_item_price() discount_amount = item_price - (item_price * cord.discount.percent_off) elif cord.discount.shipping_percent_off: # (9.0 / (1.0-0.1)) = 10.00 discount_amount = cart.shipping_discount_total if discount_amount and int(discount_amount) > 0: Journal.create_new( discount_amount, customer, cord, None, typ="AutomaticDiscount", attachment=cord.discount ) cord.save() cord.flush() return cord