Subversion Repositories SmartDukaan

Rev

Rev 24385 | Blame | Compare with Previous | Last modification | View Log | RSS feed

'''
Created on 10-May-2010

@author: ashish
'''
from elixir import *
from shop2020.clients.CatalogClient import CatalogClient
from shop2020.clients.InventoryClient import InventoryClient
from shop2020.clients.LogisticsClient import LogisticsClient
from shop2020.clients.PromotionClient import PromotionClient
from shop2020.clients.TransactionClient import TransactionClient
from shop2020.model.v1 import user
from shop2020.model.v1.user.impl.Converters import to_t_cart, to_t_line
from shop2020.model.v1.user.impl.Dataservice import Cart, Line, Address, User, \
    Discount, InsuranceDetails, PrivateDealUser
from shop2020.thriftpy.logistics.ttypes import LogisticsServiceException, \
    DeliveryType
from shop2020.thriftpy.model.v1.catalog.ttypes import Item, InsurerType
from shop2020.thriftpy.model.v1.order.ttypes import Transaction as TTransaction, \
    TransactionStatus as TTransactionStatus, Order as TOrder, LineItem as TLineItem, \
    OrderStatus, OrderSource
from shop2020.thriftpy.model.v1.user.ttypes import CartStatus, LineStatus, \
    ShoppingCartException, PromotionException, CartPlus
from shop2020.utils.Utils import to_py_date, to_java_date
import datetime
import json
import math
import traceback




def get_cart(userId):
    user = User.get_by(id=userId)
    return user.active_cart

def get_cart_by_id(id):
    cart = Cart.get_by(id=id)
    return cart

def create_cart():
    cart = Cart()
    cart.created_on = datetime.datetime.now()
    cart.updated_on = datetime.datetime.now()
    cart.cart_status = CartStatus.ACTIVE
    return cart

def get_carts_between(start_time, end_time, status):
    init_time = to_py_date(start_time)
    finish_time = to_py_date(end_time)
    
    query = Cart.query
    if status:
        query = query.filter(Cart.cart_status==status)
    if init_time:
        query = query.filter(Cart.created_on >= init_time)
    if finish_time:
        query = query.filter(Cart.created_on <= finish_time)
    
    carts = query.all()
    return carts

def get_line(item_id, cart_id, status, single):
    #get cart first 
    try:
        found_cart = Cart.get_by(id=cart_id)
    except:
        raise ShoppingCartException(101, "cart not found ")
    query = Line.query.filter_by(cart = found_cart, item_id = item_id)
    
    if status:
        query = query.filter_by(line_status = status)
    else:
        query = query.filter_by(line_status = LineStatus.LINE_ACTIVE)
    try:
        if single:
            return query.one()
        else:
            return query.all()
    except:
        return None

def add_item_to_cart(cart_id, item_id, quantity, sourceId):
    if not item_id:
        raise ShoppingCartException(101, "item_id cannot be null")
    
    if not quantity:
        raise ShoppingCartException(101, "quantity cannot be null")    

    cart = Cart.get_by(id = cart_id)    
    if not cart:
        raise ShoppingCartException(101, "no cart attached to this id" + str(cart_id))
    retval = ""
    catalog_client = CatalogClient().get_client()
    item = catalog_client.getItemForSource(item_id, sourceId)
    dataProtectionInsurer = catalog_client.getPrefferedInsurerForItem(item_id,InsurerType._NAMES_TO_VALUES.get("DATA"))
    item_shipping_info = catalog_client.isActive(item_id)
    if not item_shipping_info.isActive:
        return catalog_client.getItemStatusDescription(item_id)
    
    current_time = datetime.datetime.now()
    cart.updated_on = current_time
    line = get_line(item_id, cart_id, None,True)
    if line:
        #change the quantity only
        line.insuranceAmount = (line.insuranceAmount/line.quantity) * quantity
        line.quantity = quantity
        line.updated_on = current_time
        line.dataProtectionAmount = (line.dataProtectionAmount/line.quantity) * quantity
    else:
        line = Line()
        line.cart = cart
        line.item_id = item_id
        line.quantity = quantity
        line.created_on = current_time
        line.updated_on = current_time
        line.actual_price = item.sellingPrice
        line.line_status = LineStatus.LINE_ACTIVE
        line.insurer = 0
        line.insuranceAmount = 0
        #DATA INSURER IS SET UPON ADD TO CART
        line.dataProtectionInsurer = dataProtectionInsurer
    session.commit()
    return retval

def delete_item_from_cart(cart_id, item_id):
    if not item_id:
        raise ShoppingCartException(101, "item_id cannot be null")
    cart = Cart.get_by(id = cart_id)
    if not cart:
        raise ShoppingCartException(101, "no cart attached to this id")
    item = get_line(item_id, cart_id, None, True)
    count_deleted_discounts = delete_discounts_for_line(item)
    item.delete()
    current_time = datetime.datetime.now()
    cart.updated_on = current_time
    session.commit()

def delete_discounts_for_line(item_line):
    count_deleted = Discount.query.filter_by(line = item_line).delete()
    session.commit()
    return count_deleted

def delete_discounts_from_cart(cart_id, cart = None):
    if cart is None:
        if cart_id is None:
            raise ShoppingCartException(101, 'cart_id and cart, both cannot be null')
        else:
            cart = Cart.get_by(id = cart_id)
    
    if cart.lines:
        for line in cart.lines:
            delete_discounts_for_line(line)

def save_discounts(discounts):
    if not discounts:
        raise ShoppingCartException(101, 'discounts be null')
    
    if len(discounts) > 0:
        cart = Cart.get_by(id = discounts[0].cart_id)
        
        for t_discount in discounts:
            line = Line.query.filter_by(cart = cart, item_id = t_discount.item_id).first()
            if line is not None:
                discount = Discount()
                discount.line = line
                discount.discount = t_discount.discount
                discount.quantity = t_discount.quantity
                session.commit()
            
def add_address_to_cart(cart_id, address_id):
    if not cart_id:
        raise ShoppingCartException(101, "cart id cannot be made null")
    
    if not address_id:
        raise ShoppingCartException(101, "address id cannot be made null")
    
    cart = get_cart_by_id(cart_id)
    if not cart:
        raise ShoppingCartException(101, "no cart for this id")
    
    address = Address.get_by(id=address_id)
    if not address:
        raise ShoppingCartException(101, "No address for this id")
    
    cart.address_id = address_id
    current_time = datetime.datetime.now()
    #cart.updated_on = current_time
    session.commit()

def add_store_to_cart(cartId, storeId):
    if not cartId:
        raise ShoppingCartException(101, "cart id cannot be made null")
    
    cart = get_cart_by_id(cartId)
    if not cart:
        raise ShoppingCartException(101, "no cart for this id")
    
    if storeId:
        cart.pickupStoreId = storeId
    else:
        cart.pickupStoreId = None
        
    session.commit()
    
def apply_coupon_to_cart(t_cart, coupon_code):
    cart = get_cart_by_id(t_cart.id)
    if not cart:
        raise ShoppingCartException(101, "no cart attached to this id")
    pc = PromotionClient().get_client()
    for t_line in t_cart.lines:
        line = Line.query.filter_by(cart = cart).filter_by(item_id = t_line.itemId).one()
        line.discounted_price = None
        if not pc.isGiftVoucher(coupon_code):
            line.discounted_price = t_line.discountedPrice
        #line.dealText = t_line.dealText
        #line.freebieId = t_line.freebieId
    
    cart.total_price = t_cart.totalPrice
    cart.discounted_price = t_cart.discountedPrice
    cart.coupon_code = coupon_code
    session.commit()

def remove_coupon(cart_id):
    cart = get_cart_by_id(cart_id)
    if not cart:
        raise ShoppingCartException(101, "no cart attached to this id")
    
    #Resetting discounted price of each line in cart to Null
    for line in cart.lines:
        line.discounted_price = None
        line.dealText = None
        line.freebieId = None
    
    delete_discounts_from_cart(cart.id, cart=cart)
    cart.discounted_price = None
    cart.coupon_code = None
    session.commit()
    
def commit_cart(cart_id, sessionSource, sessionTime, firstSource, firstSourceTime, userId, schemeId, orderSource, selfPickup):   
    cart = get_cart_by_id(cart_id)   
    #now we have a cart. Need to create a transaction with it
    totalCartVal = 0
    totalshippingCost = 0
    for lineObj in cart.lines:
        totalCartVal += lineObj.actual_price * lineObj.quantity
    txn = TTransaction()
    txn.shoppingCartid = cart_id
    txn.customer_id = userId
    txn.createdOn = to_java_date(datetime.datetime.now())
    txn.transactionStatus = TTransactionStatus.INIT
    txn.statusDescription = "New Order"
    txn.coupon_code = cart.coupon_code
    txn.sessionSource = sessionSource
    txn.sessionStartTime = sessionTime
    txn.firstSource = firstSource
    txn.firstSourceTime = firstSourceTime
    txn.payment_option = schemeId

    txn.totalShippingCost = 0
        
    txnOrders = create_orders(cart, userId, orderSource, totalshippingCost, totalCartVal, selfPickup)
    shippingCostInOrders = 0
    for order in txnOrders:
        shippingCostInOrders = shippingCostInOrders + order.shippingCost
    
    diff = totalshippingCost - shippingCostInOrders
    txnOrders[0].shippingCost = txnOrders[0].shippingCost + diff
    
    
    txn.orders = txnOrders
    
    transaction_client = TransactionClient().get_client()
    txn_id = transaction_client.createTransaction(txn)
    
    session.commit()
    
    return txn_id

def create_orders(cart, userId, orderSource, totalshippingCost, totalCartVal, selfPickup):
    cart_lines = cart.lines
    orders = []
    isGv = False
    if cart.coupon_code:
        try:
            pc = PromotionClient().get_client()
            isGv = pc.isGiftVoucher(cart.coupon_code)
        except:
            isGv = False
        
    insuranceDetails = InsuranceDetails.get_by(addressId = cart.address_id)
    itemIds = []
    for line in cart_lines:
        itemIds.append(line.item_id) 
    inventory_client = CatalogClient().get_client()
    itemsMap = inventory_client.getItems(itemIds)
    print "cart_lines -", cart_lines
    for line in cart_lines:
        if line.line_status == LineStatus.LINE_ACTIVE:
            quantity_remaining_for_order = line.quantity
        
            for discount in line.discounts:
                #i = 0
                #while i < discount.quantity:
                t_line_item = create_line_item(line, line.actual_price if isGv else (line.actual_price - discount.discount), line.quantity, itemsMap.get(line.item_id))
                t_order = create_order(userId, cart.address_id, t_line_item, cart.pickupStoreId, discount.discount if isGv else 0, line.insurer, (line.insuranceAmount/line.quantity), insuranceDetails,line.dataProtectionInsurer,(line.dataProtectionAmount)/line.quantity, orderSource, line.freebieId, totalshippingCost, totalCartVal, selfPickup)
                orders.append(t_order)
                    #i += 1
                quantity_remaining_for_order -= discount.quantity
            print "quantity_remaining_for_order ", quantity_remaining_for_order 
            if quantity_remaining_for_order > 0:
                t_line_item = create_line_item(line, line.actual_price, quantity_remaining_for_order, itemsMap.get(line.item_id))
                t_order = create_order(userId, cart.address_id, t_line_item, cart.pickupStoreId, 0, line.insurer, (line.insuranceAmount/line.quantity), insuranceDetails, line.dataProtectionInsurer,(line.dataProtectionAmount)/line.quantity, orderSource, line.freebieId, totalshippingCost, totalCartVal, selfPickup)
                orders.append(t_order)

    
    wallet_amount = cart.wallet_amount
    if wallet_amount is None:
        wallet_amount = 0
    print "adjusting wallet_amount ***",wallet_amount
    for order in orders:
        if ((order.total_amount+ order.shippingCost - order.gvAmount) >= wallet_amount):
            order.wallet_amount = wallet_amount
        else:
            order.wallet_amount = order.total_amount+ order.shippingCost - order.gvAmount
        
        order.net_payable_amount = order.total_amount+ order.shippingCost - order.gvAmount - order.wallet_amount
        wallet_amount = wallet_amount - order.wallet_amount
    return orders

def create_order(userId, address_id, t_line_item, pickupStoreId, gvAmount, insurer, insuranceAmount, insuranceDetails, dataProtectionInsurer, dataProtectionAmount, orderSource, freebieId, totalshippingCost, totalCartVal, selfPickup):
    user = User.get_by(id=userId)
    address = Address.get_by(id=address_id)
    t_order = TOrder()
    
    t_order.customer_id = user.id
    t_order.customer_email = user.email
    
    t_order.customer_name = address.name
    t_order.customer_pincode = address.pin
    t_order.customer_address1 = address.line_1
    t_order.customer_address2 = address.line_2
    t_order.customer_city = address.city
    t_order.customer_state = address.state
    t_order.customer_mobilenumber = address.phone
    
    t_order.total_amount = t_line_item.total_price + insuranceAmount + dataProtectionAmount
    t_order.gvAmount = gvAmount
    
    t_order.total_weight = t_line_item.total_weight
    t_order.lineitems = [t_line_item]
    
    t_order.status = OrderStatus.PAYMENT_PENDING
    t_order.statusDescription = "Payment Pending"
    t_order.created_timestamp = to_java_date(datetime.datetime.now())
    
    t_order.pickupStoreId = pickupStoreId 
    t_order.insuranceAmount = insuranceAmount 
    t_order.insurer = insurer
    if insuranceDetails:
        t_order.dob = insuranceDetails.dob
        t_order.guardianName = insuranceDetails.guardianName
    
    catalog_client = CatalogClient().get_client()
    
    if freebieId is None:
        freebie_item_id = catalog_client.getFreebieForItem(t_line_item.item_id)
        if freebie_item_id:
            t_order.freebieItemId = freebie_item_id
    else:
        freebie_item_id = None if freebieId == 0 else freebieId  
    t_order.source = orderSource
    t_order.dataProtectionInsurer = dataProtectionInsurer
    t_order.dataProtectionAmount = dataProtectionAmount
    #if item.category in [10006, 10010]:
    if selfPickup:
        t_order.logistics_provider_id = 4
        t_order.shippingCost = 0
    else:
        t_order.shippingCost = round((t_line_item.total_price*totalshippingCost)/totalCartVal, 0)
        #t_order.shippingCost = perUnitShippingCost*t_line_item.quantity
    #else:
    #    t_order.shippingCost = 0
    return t_order
        
def create_line_item(line, final_price, quantity=1, item=None):
    if item is None:
        inventory_client = CatalogClient().get_client()
        item = inventory_client.getItem(line.item_id)
    t_line_item = TLineItem()
    t_line_item.productGroup = item.productGroup
    t_line_item.brand = item.brand
    t_line_item.model_number = item.modelNumber
    if item.color is None or item.color == "NA":
        t_line_item.color = ""
    else:
        t_line_item.color = item.color
    t_line_item.model_name = item.modelName
    t_line_item.mrp = item.mrp
    t_line_item.extra_info = item.featureDescription
    t_line_item.item_id = item.id
    t_line_item.quantity = quantity
    
    t_line_item.unit_price = final_price
    t_line_item.total_price = final_price * quantity
    t_line_item.hsnCode = item.hsnCode
    
    t_line_item.unit_weight = item.weight
    t_line_item.total_weight = item.weight if item.weight is None else item.weight * quantity
    if line.dealText is None:
        t_line_item.dealText = item.bestDealText
    elif line.dealText == '':
        t_line_item.dealText = None
    else:
        t_line_item.dealText = line.dealText
        
    if item.warrantyPeriod:
        #Computing Manufacturer Warranty expiry date
        today = datetime.date.today()
        expiry_year = today.year + int((today.month + item.warrantyPeriod) / 12)
        expiry_month = (today.month + item.warrantyPeriod) % 12
        
        try:
            expiry_date = datetime.datetime(expiry_year, expiry_month, today.day, 23, 59, 59, 999999)
        except ValueError:
            try:
                expiry_date = datetime.date(expiry_year, expiry_month, (today.day - 1), 23, 59, 59, 999999)
            except ValueError:
                try:
                    expiry_date = datetime.date(expiry_year, expiry_month, (today.day - 2), 23, 59, 59, 999999)
                except ValueError:
                    expiry_date = datetime.date(expiry_year, expiry_month, (today.day - 3), 23, 59, 59, 999999)
        
        t_line_item.warrantry_expiry_timestamp = to_java_date(expiry_date)
        
    return t_line_item
    
def validate_cart(cartId, sourceId, couponCode):
    inventory_client = CatalogClient().get_client()
    logistics_client = LogisticsClient().get_client()
    promotion_client = PromotionClient().get_client()
    retval = ""
    emival = ""
    # No need to validate duplicate items since there are only two ways
    # to add items to a cart and both of them check whether the item being
    # added is a duplicate of an already existing item.
    cart = Cart.get_by(id=cartId)
    cart_lines = cart.lines
    customer_pincode = None
    current_time = datetime.datetime.now()
    if cart.pickupStoreId :
        store = logistics_client.getPickupStore(cart.pickupStoreId)
        customer_pincode = store.pin
    if cart.address_id != None and customer_pincode == None:
        address = Address.get_by(id=cart.address_id)
        customer_pincode = address.pin

    user = User.get_by(active_cart_id = cartId)
    
    dealItems = []
    bulkPricingMap ={}
    bulkPricingItems =[]
    privateDealUser = PrivateDealUser.get_by(id=user.id)    
    if privateDealUser is not None and privateDealUser.isActive:
        itemIds = [cartLine.item_id for cartLine in cart.lines]
        deals = inventory_client.getAllActivePrivateDeals(itemIds, 0)
        dealItems = deals.keys()
        bulkPricingMap = inventory_client.getBulkPricingForItems(itemIds)
        bulkPricingItems = bulkPricingMap.keys() 

    if not customer_pincode:
        default_address_id = user.default_address_id
        if default_address_id:
            address = Address.get_by(id = default_address_id)
            customer_pincode = address.pin
    if not customer_pincode:
        #FIXME should not be hard coded. May be we can pick from config server.
        customer_pincode = "110001"
    cart.total_price = 0
    for line in cart_lines:
        old_estimate = line.estimate
        item_id = line.item_id
        item = inventory_client.getItemForSource(item_id, sourceId)
        
        item_shipping_info = inventory_client.isActive(item_id) 
        if item_shipping_info.isActive:
            if item_shipping_info.isRisky and item_shipping_info.quantity < line.quantity:
                line.quantity = 1
                retval = "Try adding a smaller quantity of " + item.brand + " " + item.modelNumber + " (" + item.color + ")"
            bulkPrice = None
            if item_id in bulkPricingItems:
                #Check quantity qualifies or not
                bulkPricingList = bulkPricingMap.get(item_id)
                bulkPricingList = sorted(bulkPricingList, key=lambda x: x.quantity, reverse=False)
                for pricingItems in bulkPricingList:
                    if pricingItems.quantity <= line.quantity:
                        bulkPrice = pricingItems
                    else:
                        break
                
                 
            if item_id in dealItems:
                if bulkPrice is None:
                    line.actual_price = deals[item_id].dealPrice
                else:
                    line.actual_price = bulkPrice.price
                if deals[item_id].dealTextOption==0:
                    line.dealText = ''
                if deals[item_id].dealTextOption==2:
                    line.dealText =  deals[item_id].dealText
                    
                if deals[item_id].dealFreebieOption==0:
                    line.freebieId = 0
                if deals[item_id].dealFreebieOption==2:
                    line.freebieId =  deals[item_id].dealFreebieItemId

            else:
                if bulkPrice is None:
                    line.actual_price = item.sellingPrice
                else:
                    line.actual_price = bulkPrice.price 
                line.dealText = None
                line.freebieId = None
            cart.total_price = cart.total_price + (line.actual_price * line.quantity)
            try:
                item_delivery_estimate = logistics_client.getLogisticsEstimation(item_id, customer_pincode, DeliveryType.PREPAID).deliveryTime
            except LogisticsServiceException:
                item_delivery_estimate = -1
                #TODO Use the exception clause to set the retval appropriately
            except :
                item_delivery_estimate = -1
                
            if item_delivery_estimate !=-1:
                inv_client = InventoryClient().get_client()
                itemAvailability = None
                try:
                    itemAvailability = inv_client.getItemAvailabilityAtLocation(item_id, 1)
                except:
                    pass
                
                print 'itemAvailability billling Warehouse ', itemAvailability[2]
                if itemAvailability is not None:
                    billingWarehouse = None
                    try:
                        billingWarehouse = inv_client.getWarehouse(itemAvailability[2])
                    except:
                        pass
                    
                    print 'billingWarehouse Id Location ', billingWarehouse.stateId
                    if billingWarehouse is not None:
                        estimateVal = None
                        if not logistics_client.isAlive() :
                            logistics_client = LogisticsClient().get_client()
                        try:
                            estimateVal = logistics_client.getFirstDeliveryEstimateForWhLocation(customer_pincode, billingWarehouse.stateId)
                            if estimateVal ==-1:
                                item_delivery_estimate =-1
                        except:
                            pass
                        print 'estimateVal Value ', estimateVal
            if old_estimate != item_delivery_estimate:
                line.estimate = item_delivery_estimate
                cart.updated_on = current_time
        else:
            Discount.query.filter(Discount.line==line).delete()
            line.delete()
    if cart.checked_out_on is not None:
        if cart.updated_on > cart.checked_out_on:
            cart.checked_out_on = None
    session.commit()
    
    if cart.coupon_code is not None:
        try:
            updated_cart = promotion_client.applyCoupon(cart.coupon_code, cart.id)
            if updated_cart.message is not None:
                emival = updated_cart.message
        except PromotionException as ex:
            remove_coupon(cart.id)
            #retval = ex.message
    session.commit()
    
    cart = Cart.get_by(id=cartId)
    cart_lines = cart.lines
    map_lines = {}
    
    insurerFlag = False
    for line in cart_lines:
        if line.insurer > 0 or line.dataProtectionInsurer > 0:
            line_map = {}
            line_map['insurer'] = line.insurer
            line_map['dpinsurer'] = line.dataProtectionInsurer
            line_map['amount'] = line.discounted_price if line.discounted_price else line.actual_price
            line_map['quantity'] = line.quantity
            insurerFlag = True
            map_lines[line.item_id] = line_map
        
    if insurerFlag:
        map_lines = inventory_client.checkServices(map_lines)
        for line in cart_lines :
            if map_lines.has_key(line.item_id):
                line_map = map_lines[line.item_id]
                if line_map['insurer'] > 0:
                    if cart.discounted_price:
                        cart.discounted_price = cart.discounted_price + line_map['insureramount']
                    line.insurer = line_map['insurer']
                    line.insuranceAmount = line_map['insureramount']
                    cart.total_price = cart.total_price + line_map['insureramount']
                if line_map['dpinsurer'] > 0:
                    if cart.discounted_price:
                        cart.discounted_price = cart.discounted_price + line_map['dpinsureramount']
                    line.dataProtectionInsurer = line_map['dpinsurer']
                    line.dataProtectionAmount = line_map['dpinsureramount']
                    cart.total_price = cart.total_price + line_map['dpinsureramount']
                line.updated_on = datetime.datetime.now()
        cart.updated_on = datetime.datetime.now()
        session.commit()
    session.close()
    return [retval, emival]

def merge_cart(fromCartId, toCartId):
    fromCart = Cart.get_by(id=fromCartId)
    toCart = Cart.get_by(id=toCartId)
    
    old_lines = fromCart.lines
    new_lines = toCart.lines
    
    for line in old_lines:
        for discount in line.discounts:
            discount.delete()
    session.commit()
    
    for line in old_lines:
        flag = True
        for new_line in new_lines:
            if line.item_id == new_line.item_id:
                flag = False
        
        if flag:
            line.cart_id = toCartId
        else:
            line.delete()
            
    if toCart.coupon_code is None:
        toCart.coupon_code = fromCart.coupon_code
    
    toCart.updated_on = datetime.datetime.now()
    fromCart.expired_on = datetime.datetime.now()
    fromCart.cart_status = CartStatus.INACTIVE
    session.commit()

def check_out(cartId):
    if cartId is None:
        raise ShoppingCartException(101, "Cart id not specified")
    cart = Cart.get_by(id = cartId)
    if cart is None:
        raise ShoppingCartException(102, "The specified cart couldn't be found")
    cart.checked_out_on = datetime.datetime.now()
    session.commit()
    return True

def reset_cart(cartId, items):
    if cartId is None:
        raise ShoppingCartException(101, "Cart id not specified")
    for item_id, quantity in items.iteritems():
        line = Line.query.filter_by(cart_id=cartId, item_id=item_id).one()
        if line is not None:
            delete_discounts_for_line(line)
            line.discounted_price = None
            line.quantity = line.quantity - quantity
            if line.quantity == 0:
                line.delete()
    cart = Cart.get_by(id=cartId)
    cart.updated_on = datetime.datetime.now()
    cart.checked_out_on = None
    
    # Removing Coupon
    cart.total_price = None
    cart.discounted_price = None
    cart.coupon_code = None
    cart.wallet_amount = 0.0
    
    session.commit()
    return True

def get_carts_with_coupon_count(coupon_code):
    return Cart.query.filter_by(coupon_code = coupon_code).count()

def show_cod_option(cartId, sourceId, pincode):
    cart = Cart.get_by(id = cartId)
    cod_option = True
    logistics_client = LogisticsClient().get_client()
    if cart:
        itemIds = []
        for line in cart.lines:
            itemIds.append(line.item_id)
#        catalog_client = CatalogClient().get_client()
#        items = catalog_client.getItems(itemIds).values()
#        for item in items:
#            if item.category not in [10006, 10010]:
#                return False
    
        if cart.coupon_code:
            promotion_client = PromotionClient().get_client()
            cod_option = promotion_client.isCodApplicable(to_t_cart(cart))
        
        if cod_option and cart.lines:
            for line in cart.lines:
                try:
                    logistics_info = logistics_client.getLogisticsEstimation(line.item_id, pincode, DeliveryType.PREPAID)
                    if not logistics_info.codAllowed:
                        cod_option = False
                        break
                except:
                    pass    
            if cart.total_price > 150000:
                cod_option = False
    return cod_option

def get_products_added_to_cart(startDate, endDate):
    lines = session.query(Line.item_id).filter(Line.created_on > to_py_date(startDate)).filter(Line.created_on < to_py_date(endDate)).all()
    datas = []
    for line in lines:
        datas.append(line[0])
    return datas

def insure_item(itemId, cartId, toInsure, insurerType):
    cart = Cart.get_by(id = cartId)
    line = None
    for cartLine in cart.lines:
        if(cartLine.item_id == itemId):
            line = cartLine
            break
        
    if not line:
        print("Error : No line found for cartId : " + cartId + " and itemId : " + itemId)
        return False
    
    try:
        if toInsure:
            csc = CatalogClient().get_client()
            item = csc.getItem(itemId)
            insurerId = csc.getPrefferedInsurerForItem(itemId,insurerType)
            insuranceAmount = csc.getInsuranceAmount(itemId, line.discounted_price if line.discounted_price else line.actual_price, insurerId, line.quantity)
            if InsurerType._VALUES_TO_NAMES.get(insurerType)=='DEVICE':
                if cart.discounted_price:
                    cart.discounted_price = cart.discounted_price - line.insuranceAmount + insuranceAmount
                line.insurer = insurerId
                line.insuranceAmount = insuranceAmount
            if InsurerType._VALUES_TO_NAMES.get(insurerType)=='DATA':
                if cart.discounted_price:
                    cart.discounted_price = cart.discounted_price - line.dataProtectionAmount + insuranceAmount
                line.dataProtectionInsurer = insurerId
                line.dataProtectionAmount = insuranceAmount
            cart.total_price = cart.total_price + insuranceAmount
        else:
            if InsurerType._VALUES_TO_NAMES.get(insurerType)=='DEVICE':
                cart.total_price = cart.total_price - line.insuranceAmount
                if cart.discounted_price:
                    cart.discounted_price = cart.discounted_price - line.insuranceAmount
                line.insurer = 0
                line.insuranceAmount = 0
            if InsurerType._VALUES_TO_NAMES.get(insurerType)=='DATA':
                cart.total_price = cart.total_price - line.dataProtectionAmount
                if cart.discounted_price:
                    cart.discounted_price = cart.discounted_price - line.dataProtectionAmount
                line.dataProtectionInsurer = 0
                line.dataProtectionAmount = 0
        line.updated_on = datetime.datetime.now()
        cart.updated_on = datetime.datetime.now()
        session.commit()
    except:
        print("Error : Unable to insure")
        print("insurerId : " + str(insurerId) + " ItemId : " + str(itemId) + " CartId : " + str(cartId))
        return False
    
    return True

def cancel_insurance(cartId):
    try:
        cart = Cart.get_by(id = cartId)
        for cartLine in cart.lines:
            cart.total_price = cart.total_price - cartLine.insuranceAmount
            if cart.discounted_price:
                cart.discounted_price = cart.discounted_price - cartLine.insuranceAmount
            cartLine.insurer = 0
            cartLine.insuranceAmount = 0
            cartLine.updated_on = datetime.datetime.now()
        cart.updated_on = datetime.datetime.now()
        session.commit()
    except:
        print("Error : Unable to cancel insurance for cartId :" + str(cartId))
        return False
    
    return True

def store_insurance_specific_details(addressId, dob, guardianName):
    try:
        insuranceDetails = InsuranceDetails.get_by(addressId = addressId);
        if insuranceDetails is None :
            insuranceDetails = InsuranceDetails()
        insuranceDetails.addressId = addressId
        insuranceDetails.dob = dob
        insuranceDetails.guardianName = guardianName
        session.commit()
    except:
        print("Error : Unable to store insurance details for addressId : " + str(addressId))
        return False
    return True

def is_insurance_detail_present(addressId):
    try:
        insuranceDetails = InsuranceDetails.get_by(addressId = addressId);
        if insuranceDetails is None :
            return False
    except:
        print("Error : Unable to get insurance details for addressId : " + str(addressId))
        return False
    return True


def add_items_to_cart(cartId, itemQty, couponCode=None):
    try: 
        found_cart = Cart.get_by(id=cartId)
        itemQtyMap = {}
        current_time = datetime.datetime.now()
        for itemqty in itemQty:
            itemQtyMap[itemqty.itemId] = itemqty.qty 
            
        if found_cart.lines:
            for line in found_cart.lines:
                    Discount.query.filter(Discount.line==line).delete()
                    line.delete()
        for itemId,qty in itemQtyMap.iteritems():
            #This condition will ensure that cart is only persisted with non-zero quantities.
            if qty==0:
                continue
            line = Line()
            line.cart = found_cart
            line.item_id = itemId
            line.quantity = qty
            line.created_on = current_time
            line.updated_on = current_time
            line.line_status = LineStatus.LINE_ACTIVE
            line.insurer = 0
            line.insuranceAmount = 0
        if couponCode:
            found_cart.coupon_code = couponCode
        else:
            found_cart.coupon_code = None
        session.commit()
        return True
    except:
        traceback.print_exc()
        return False
             
    
    
def validate_fofo_cart(cart, user, privateDealUser, customer_pincode):
    current_time = datetime.datetime.now()
    totalQty = 0
    totalAmount = 0
    cartMessages = []
    cartItems = []
    responseMap = {}
    cartMessageChanged = 0
    cartMessageOOS = 0
    codAllowed = False
    cartMessageUndeliverable = 0
    
    itemIds = [cartLine.item_id for cartLine in cart.lines]
    
    catalog_client = CatalogClient().get_client()
    #logistics_client = LogisticsClient().get_client()
    #promotion_client = PromotionClient().get_client()
    inv_client = InventoryClient().get_client()
    
    fofoDealsMap = catalog_client.getAllFofoDeals(itemIds, [4, 7])    
    fofoDealsAvailability = inv_client.getFofoAvailability(fofoDealsMap.keys())
    
    

    itemsMap = catalog_client.getItems(itemIds)
    cart_lines = cart.lines
    cart.total_price = 0
    nonAccessoryQuantity = 0
    for line in cart_lines:
        itemQuantityChanged=False
        cartItem={}
        tempBulkItemList = []
        
        old_estimate = line.estimate
        item_id = line.item_id
        item = itemsMap.get(item_id)
        #in case item is missing remove that line
        #lets silently remvoe fofoDealsMap as fofo customer is not allowed to orders with fofo
        if item is None or item.itemStatus==0 or not fofoDealsMap.has_key(item.id):
            Discount.query.filter(Discount.line==line).delete()
            line.delete()
            continue
        cartItem['itemId']=line.item_id
        cartItem['quantity']=0
        cartItem['cartItemMessages']=[]
        cartItemMessages = cartItem['cartItemMessages']
        cartItem['color'] = item.color
        cartItem['catalogItemId'] = item.catalogItemId
        cartItem['packQuantity'] = item.packQuantity
        cartItem['minBuyQuantity'] = item.minimumBuyQuantity
        cartItem['quantityStep'] = item.quantityStep
        cartItem['bulkPricing'] = tempBulkItemList
        cartItem['maxQuantity'] =0
        #This should be removed
        fofoDealsAvailability[item_id] = 30
        if not fofoDealsAvailability.has_key(item_id):
            continue
        else:
            availability = fofoDealsAvailability.get(item_id)
            if availability < line.quantity:
                line.quantity = availability
                itemQuantityChanged=True
            cartItem['maxQuantity'] = min(availability,100)
            if item.maximumBuyQuantity is not None and item.maximumBuyQuantity >0:
                cartItem['maxQuantity'] = min(availability, item.maximumBuyQuantity)
            if availability < cartItem['minBuyQuantity']:
                cartItem['minBuyQuantity'] = availability 
        
            if line.quantity < cartItem['minBuyQuantity']:
                itemQuantityChanged=True
                line.quantity = cartItem['minBuyQuantity']
            
            if line.quantity > cartItem['maxQuantity']:
                itemQuantityChanged=True
                line.quantity = cartItem['maxQuantity']
            
            cartItem['quantity'] = line.quantity
            line.actual_price = fofoDealsMap.get(item_id)
            if item.category in [10006, 10010]:
                nonAccessoryQuantity += cartItem['quantity'] 
                cartItem['categoryName'] = "mobile" 
        
        cartItem['sellingPrice'] = line.actual_price
        cartItem['bulkPricing'] = []

        if availability:
            cart.total_price = cart.total_price + (line.actual_price * line.quantity)
            ##Lets assign hardcoded deliveryestimate for fofo
            item_delivery_estimate = 2
            codAllowed = False
            cartItem['estimate'] = item_delivery_estimate
            if itemQuantityChanged:
                cartMessageChanged += 1
                cartItemMessages.append({"type":"danger", "messageText":"Only " + str(item.maximumBuyQuantity) + " available"})
            if old_estimate != item_delivery_estimate:
                line.estimate = item_delivery_estimate
                cart.updated_on = current_time
            totalAmount += line.actual_price * cartItem['quantity']
        else:
            cartItem['quantity'] = 0
            cartMessageOOS += 1
            cartItemMessages.append({"type":"danger", "messageText":"Out of Stock"})
            Discount.query.filter(Discount.line==line).delete()
            line.delete()
        totalQty += cartItem['quantity']

        if cartItemMessages:
            cartItems.insert(0, cartItem)
        else:
            cartItems.append(cartItem)
    if cart.checked_out_on is not None:
        if cart.updated_on > cart.checked_out_on:
            cart.checked_out_on = None
    session.commit()
    
    responseMap['totalQty']= totalQty
    responseMap['totalAmount']= totalAmount
    responseMap['nonAccessoryQuantity']= nonAccessoryQuantity
    responseMap['cartMessages']= cartMessages
    responseMap['cartItems']= cartItems
    responseMap['pincode']= customer_pincode
    responseMap['shippingCharge'] = 0
    responseMap['cartMessageChanged'] = cartMessageChanged
    responseMap['cartMessageOOS'] = cartMessageOOS
    responseMap['cartMessageUndeliverable'] = cartMessageUndeliverable
    responseMap['codAllowed'] = codAllowed
    return json.dumps(responseMap)         
    
    
    
def validate_cart_new(cartId, customer_pincode, sourceId):
    
    # No need to validate duplicate items since there are only two ways
    # to add items to a cart and both of them check whether the item being
    # added is a duplicate of an already existing item.
    cart = Cart.get_by(id=cartId)
    cart_lines = cart.lines
    current_time = datetime.datetime.now()

    #if customer_pincode is 000000 pincode should be considered from address or
    #is address is not present treat is as customer input
    user = User.get_by(active_cart_id = cartId)
    privateDealUser = PrivateDealUser.get_by(id=user.id)
    if customer_pincode == "000000":
        address = Address.get_by(id=cart.address_id)
        if address:
            customer_pincode = address.pin
    catalog_client = CatalogClient().get_client()
    itemIds = [cartLine.item_id for cartLine in cart.lines]
    print " My email is ", user.email, user.id
    if privateDealUser is not None and privateDealUser.isActive and privateDealUser.isFofo:
        print " I am a privatedeal user", user.email
        fofoDealsMap = catalog_client.getAllFofoDeals(itemIds, [4, 7])
        print " I have recieved the fofo Deals Map", user.email
        if fofoDealsMap:
            return validate_fofo_cart(cart, user, privateDealUser, customer_pincode)

    
    logistics_client = LogisticsClient().get_client()

    responseMap = {}
    totalQty = 0
    nonAccessoryQuantity = 0
    totalAmount = 0 
    shippingCharges=0
    cartMessages=[]
    cartItems = []
    dealItems = []
    deals = {}
    bulkPricingMap ={}
    bulkPricingItems =[]
    
    
    if privateDealUser is not None and privateDealUser.isActive:
        deals = catalog_client.getAllActivePrivateDeals(itemIds, 0)
        bulkPricingMap = catalog_client.getBulkPricingForItems(itemIds)
        dealItems = deals.keys()
        bulkPricingItems = bulkPricingMap.keys()

    cart.total_price = 0
    itemsMap = catalog_client.getItems(itemIds)
    
    cartMessageChanged = 0
    cartMessageOOS = 0
    cartMessageUndeliverable = 0
    codAllowed = True
    
    
    
    for line in cart_lines:
        itemQuantityChanged=False
        cartItem={}
        tempBulkItemList = []
        
        old_estimate = line.estimate
        item_id = line.item_id
        item = itemsMap.get(item_id)
        #in case item is missing remove that line
        if item is None or item.itemStatus==0:
            Discount.query.filter(Discount.line==line).delete()
            line.delete()
            continue
        cartItem['itemId']=line.item_id
        cartItem['quantity']=0
        cartItem['cartItemMessages']=[]
        cartItemMessages = cartItem['cartItemMessages']
        cartItem['color'] = item.color
        cartItem['catalogItemId'] = item.catalogItemId
        cartItem['packQuantity'] = item.packQuantity
        cartItem['minBuyQuantity'] = item.minimumBuyQuantity
        cartItem['quantityStep'] = item.quantityStep
        cartItem['bulkPricing'] = tempBulkItemList
        
        item_shipping_info = catalog_client.isActive(item_id) 
        if item_shipping_info.isActive:
            if item_shipping_info.isRisky and item_shipping_info.quantity < line.quantity:
                line.quantity = item_shipping_info.quantity
                itemQuantityChanged=True
            cartItem['maxQuantity'] = min(item_shipping_info.quantity,100)
            if item.maximumBuyQuantity is not None and item.maximumBuyQuantity >0:
                cartItem['maxQuantity'] = min(item_shipping_info.quantity, item.maximumBuyQuantity)
        else:
            cartItem['maxQuantity'] =0
            
        
        if item_shipping_info.quantity < cartItem['minBuyQuantity']:
            cartItem['minBuyQuantity'] = item_shipping_info.quantity 
        
        if line.quantity < cartItem['minBuyQuantity']:
            itemQuantityChanged=True
            line.quantity = cartItem['minBuyQuantity']
        
        if line.quantity > cartItem['maxQuantity']:
            itemQuantityChanged=True
            line.quantity = cartItem['maxQuantity']
        
        cartItem['quantity'] = line.quantity
        
        bulkPrice = None
        singleUnitPricing = False
        if item_id in bulkPricingItems:
            #Check quantity qualifies or not
            bulkPricingList = bulkPricingMap.get(item_id)
            bulkPricingList = sorted(bulkPricingList, key=lambda x: x.quantity, reverse=False)
            for pricingItems in bulkPricingList:
                if pricingItems.quantity ==1:
                    singleUnitPricing = True
                if pricingItems.quantity <= line.quantity:
                    bulkPrice = pricingItems
                tempBulkItemList.append({'quantity':pricingItems.quantity,'price':pricingItems.price})
            
        if item_id in dealItems:
            if not singleUnitPricing and item_id in bulkPricingItems:
                tempBulkItemList.append({'quantity':1,'price':deals[item_id].dealPrice})
            if bulkPrice is None:
                line.actual_price = deals[item_id].dealPrice
            else:
                line.actual_price = bulkPrice.price
            if deals[item_id].dealTextOption==0:
                line.dealText = ''
            if deals[item_id].dealTextOption==2:
                line.dealText = deals[item_id].dealText
                
            if deals[item_id].dealFreebieOption==0:
                line.freebieId = 0
            if deals[item_id].dealFreebieOption==2:
                line.freebieId =  deals[item_id].dealFreebieItemId
            cartItem['dealText'] = line.dealText
        else:
            if not singleUnitPricing and item_id in bulkPricingItems:
                tempBulkItemList.append({'quantity':1,'price':item.sellingPrice})
            if bulkPrice is None:
                line.actual_price = item.sellingPrice
            else:
                line.actual_price = bulkPrice.price
            if item.bestDealText:
                cartItem['dealText'] = item.bestDealText
            line.dealText = None
            line.freebieId = None
        
        cartItem['sellingPrice'] = line.actual_price
        
        toRemove = []
        for dictbulkPricing in cartItem['bulkPricing']:
            if dictbulkPricing['quantity'] < cartItem['minBuyQuantity'] or dictbulkPricing['quantity'] > cartItem['maxQuantity']:
                toRemove.append(dictbulkPricing)
        for removePricing in toRemove:
            cartItem['bulkPricing'].remove(removePricing)
        cartItem['bulkPricing'] = sorted(cartItem['bulkPricing'], key=lambda k: k['quantity'],reverse=False)

        print "item_shipping_info", item_shipping_info        
        if item_shipping_info.isActive:
            cart.total_price = cart.total_price + (line.actual_price * line.quantity)
            try:
                item_delivery_estimate_tuple = logistics_client.getLogisticsEstimation(item_id, customer_pincode, DeliveryType.PREPAID)
                item_delivery_estimate = item_delivery_estimate_tuple.deliveryTime
                print "item_delivery_estimate", item_delivery_estimate 
                if item_delivery_estimate:
                    codAllowed = codAllowed and item_delivery_estimate_tuple.codAllowed 
            except LogisticsServiceException:
                traceback.print_exc()
                item_delivery_estimate = -1
                #TODO Use the exception clause to set the retval appropriately
            except :
                traceback.print_exc()
                item_delivery_estimate = -1
                
            if item_delivery_estimate !=-1:
                inv_client = InventoryClient().get_client()
                itemAvailability = None
                try:
                    itemAvailability = inv_client.getItemAvailabilityAtLocation(item_id, 1, -1)
                except:
                    pass
                
                print 'itemAvailability billling Warehouse ', itemAvailability[2]
                if itemAvailability is not None:
                    billingWarehouse = None
                    try:
                        billingWarehouse = inv_client.getWarehouse(itemAvailability[2])
                    except:
                        traceback.print_exc()
                        pass
                    
                    print 'billingWarehouse Id Location ', billingWarehouse.stateId
                    if billingWarehouse is not None:
                        estimateVal = None
                        if not logistics_client.isAlive() :
                            logistics_client = LogisticsClient().get_client()
                        try:
                            estimateVal = logistics_client.getFirstDeliveryEstimateForWhLocation(customer_pincode, billingWarehouse.logisticsLocation)
                            if estimateVal ==-1:
                                item_delivery_estimate =-1
                        except:
                            traceback.print_exc()
                            pass
                        print 'estimateVal Value ', estimateVal
            cartItem['estimate'] = item_delivery_estimate
            if item_delivery_estimate == -1:
                Discount.query.filter(Discount.line==line).delete()
                line.delete()
                cartItem['quantity'] = 0
                cartMessageUndeliverable += 1
                cartItemMessages.append({"type":"danger", "messageText":"Undeliverable"})
            elif itemQuantityChanged:
                cartMessageChanged += 1
                cartItemMessages.append({"type":"danger", "messageText":"Only " + str(item_shipping_info.quantity) + " available"})
            if old_estimate != item_delivery_estimate:
                line.estimate = item_delivery_estimate
                cart.updated_on = current_time
            totalAmount += line.actual_price * cartItem['quantity']
        else:
            cartItem['quantity'] = 0
            cartMessageOOS += 1
            cartItemMessages.append({"type":"danger", "messageText":"Out of Stock"})
            Discount.query.filter(Discount.line==line).delete()
            line.delete()
        totalQty += cartItem['quantity']
        if item.category in [10006, 10010]:
            nonAccessoryQuantity += cartItem['quantity']
        if cartItemMessages:
            cartItems.insert(0, cartItem)
        else:
            cartItems.append(cartItem)
    if cart.checked_out_on is not None:
        if cart.updated_on > cart.checked_out_on:
            cart.checked_out_on = None
    session.commit()
    
    if cart.coupon_code is not None:
        try:
            promotion_client = PromotionClient().get_client()
            updated_cart = promotion_client.applyCoupon(cart.coupon_code, cart.id)
            if updated_cart.message is not None:
                emival = updated_cart.message
        except PromotionException as ex:
            remove_coupon(cart.id)
            #retval = ex.message
    session.commit()
    
    cart = Cart.get_by(id=cartId)
    cart_lines = cart.lines
    insurerFlag = False
    for line in cart_lines:
        if line.insurer > 0 or line.dataProtectionInsurer > 0:
            line.insurer = 0
            line.insuranceAmount = 0 
            line.dataProtectionInsurer = 0
            line.dataProtectionAmount = 0
            insurerFlag = True
        
    if insurerFlag:
        cart.updated_on = datetime.datetime.now()
        session.commit()
    session.close()
    responseMap['totalQty']= totalQty
    responseMap['totalAmount']= totalAmount
    if totalAmount < 1000:
        shippingCharges = 100
    responseMap['cartMessages']= cartMessages
    responseMap['cartItems']= cartItems
    responseMap['pincode']= customer_pincode
    responseMap['shippingCharge']=shippingCharges
    responseMap['cartMessageChanged'] = cartMessageChanged
    responseMap['cartMessageOOS'] = cartMessageOOS
    responseMap['cartMessageUndeliverable'] = cartMessageUndeliverable
    ##As of now no Cod is allowed
    responseMap['codAllowed'] = False
    print "responseMap", responseMap
    return json.dumps(responseMap)
    
    
def validate_cart_plus(cart_id, source_id, couponCode):
    try:
        cart_messages = validate_cart(cart_id, source_id, couponCode)
        found_cart = Cart.get_by(id=cart_id)
        pincode = "110001"
        default_address_id = User.get_by(active_cart_id = cart_id).default_address_id
        
        default_address = None
        if found_cart.address_id is not None and found_cart.address_id > 0:
            pincode = Address.get_by(id=found_cart.address_id).pin
        elif default_address_id is not None:
            default_address = Address.get_by(id = default_address_id) 
            pincode = default_address.pin
        
        needInsuranceInfo = False
        if default_address_id is not None:
            for line in found_cart.lines:
                if line.insurer > 0:
                    needInsuranceInfo = not is_insurance_detail_present(default_address_id)
                    break
        cartPlus = CartPlus()
        cartPlus.cart = to_t_cart(found_cart)
        cartPlus.pinCode = pincode
        cartPlus.validateCartMessages = cart_messages
        cartPlus.needInsuranceInfo = needInsuranceInfo
        return cartPlus
    finally:
        close_session()

def close_session():
    if session.is_active:
        print "session is active. closing it."
        session.close()
        

def set_wallet_amount_in_cart(cartId, wallet_amount):
    cart = Cart.get_by(id = cartId)
    if cart is None:
        raise ShoppingCartException(102, "The specified cart couldn't be found")
    if wallet_amount < 0:
        raise ShoppingCartException(103, "Wallet amount is negative")
    cart.wallet_amount = wallet_amount
    session.commit()
    return True


def add_item_pricing_to_cart(cartId, itemQtyPriceList):
    try: 
        found_cart = Cart.get_by(id=cartId)

        #Get prices to validate should not be less than mop
        current_time = datetime.datetime.now()
            
        if found_cart.lines:
            for line in found_cart.lines:
                Discount.query.filter(Discount.line==line).delete()
                line.delete()
        for itemQtyPrice in itemQtyPriceList:
            #This condition will ensure that cart is only persisted with non-zero quantities.
            if itemQtyPrice.qty==0:
                continue
            line = Line()
            line.cart = found_cart
            print "itemQtyPrice.itemId-------", itemQtyPrice.itemId
            line.item_id = itemQtyPrice.itemId
            line.quantity = itemQtyPrice.qty
            line.created_on = current_time
            line.updated_on = current_time
            line.line_status = LineStatus.LINE_ACTIVE
            line.insurer = 0
            line.insuranceAmount = 0
            line.actual_price = itemQtyPrice.price
        found_cart.coupon_code = None
        session.commit()
        return True
    
    except:
        traceback.print_exc()
        return False