Subversion Repositories SmartDukaan

Rev

Rev 1334 | Rev 1382 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

'''
Created on 29-Mar-2010

@author: ashish
'''
from string import Template
from email.mime.multipart import MIMEMultipart
from shop2020.thriftpy.utils.ttypes import HelperServiceException, Mail
from email.mime.base import MIMEBase
from email import encoders
from email.mime.text import MIMEText
import os
import smtplib
import time
from time import strftime

from shop2020.model.v1.order.impl.DataService import Transaction, LineItem,\
    Alerts, Order, BatchNoGenerator
from shop2020.thriftpy.model.v1.order.ttypes import Transaction as T_Transaction,\
    TransactionServiceException, TransactionStatus, OrderStatus
import datetime
from elixir import *
from shop2020.utils.Utils import to_py_date, to_java_date
from sqlalchemy.sql.expression import and_
from shop2020.model.v1 import order
from shop2020.clients.LogisticsClient import LogisticsClient
from shop2020.clients.InventoryClient import InventoryClient
from shop2020.clients.UserClient import UserClient

def get_new_transaction():
    transaction = Transaction()
    transaction.createdOn = datetime.datetime.now()
    transaction.status = TransactionStatus.INIT
    transaction.status_message = "New transaction"
    return transaction

def create_order(t_order):
    order = Order()
    if t_order.warehouse_id:
        order.warehouse_id = t_order.warehouse_id
    if t_order.logistics_provider_id:    
        order.logistics_provider_id = t_order.logistics_provider_id
        order.airwaybill_no = t_order.airwaybill_no
        order.tracking_id = t_order.tracking_id
    if t_order.expected_delivery_time:    
        order.expected_delivery_time = to_py_date(t_order.expected_delivery_time)
    if t_order.customer_id:    
        order.customer_id = t_order.customer_id
        order.customer_name = t_order.customer_name
        order.customer_city = t_order.customer_city
        order.customer_state = t_order.customer_state
        order.customer_mobilenumber = t_order.customer_mobilenumber
        order.customer_pincode = t_order.customer_pincode
        order.customer_address1 = t_order.customer_address1
        order.customer_address2 = t_order.customer_address2
        order.customer_email = t_order.customer_email
    #new status and status description to be added    
    order.status = t_order.status  
    order.statusDescription = t_order.statusDescription
    order.total_amount = t_order.total_amount
    order.total_weight = t_order.total_weight
    if t_order.created_timestamp:
        order.created_timestamp = to_py_date(t_order.created_timestamp)
    else:
        order.created_timestamp = datetime.datetime.now()
    return order
    
def create_transaction(t_transaction):
    t_orders = t_transaction.orders
    if not t_orders:
        raise TransactionServiceException(101, "Orders missing from the transaction")
    transaction = get_new_transaction()
    transaction.customer_id = t_transaction.customer_id 
    transaction.shopping_cart_id = t_transaction.shoppingCartid

    for t_order in t_orders:
        order = create_order(t_order)
        order.transaction = transaction 
        for line_item in t_order.lineitems:
            litem = LineItem()
            litem.item_id = line_item.item_id
            litem.productGroup = line_item.productGroup
            litem.brand = line_item.brand
            if line_item.model_number:
                litem.model_number = line_item.model_number
            if line_item.model_name:    
                litem.model_name = line_item.model_name
            if line_item.color:
                litem.color = line_item.color
            if line_item.extra_info:
                litem.extra_info = line_item.extra_info
            litem.quantity = line_item.quantity
            litem.unit_price = line_item.unit_price
            litem.unit_weight = line_item.unit_weight
            litem.total_price = line_item.total_price
            litem.total_weight = line_item.total_weight
            litem.transfer_price = line_item.transfer_price
            """
            if line_item.addedOn:
                litem.added_on = to_py_date(line_item.addedOn)
            else:
                litem.added_on = datetime.datetime.now()
            """
            litem.order = order
    session.commit()
    return transaction.id

def get_transaction(transaction_id):
    transaction = Transaction.get_by(id=transaction_id)
    if not transaction:
        raise TransactionServiceException(108, "no such transaction")
    
    return transaction

def get_transactions_for_customer(customer_id, from_date, to_date, status):
    if not customer_id:
        raise TransactionServiceException(101, "bad customer id")
    query = Transaction.query.filter(Transaction.customer_id == customer_id)
    if status:
        query = query.filter(Transaction.status == status)
    if from_date:
        query = query.filter(Transaction.createdOn >from_date)
    if to_date:
        query = query.filter(Transaction.createdOn < to_date)
    return query.all()

def get_transactions_for_shopping_cart_id(shopping_cart_id):
    transactions = Transaction.query.filter_by(shopping_cart_id=shopping_cart_id).all()
    if not transactions:
        raise TransactionServiceException(108, "transactions for this shopping cart")
    return transactions

def get_transaction_status(transaction_id):
    if not transaction_id:
        raise TransactionServiceException(101, "bad transaction id")
    
    transaction = get_transaction(transaction_id)
    
    return transaction.status

def change_transaction_status(transaction_id, new_status, description):
    transaction = get_transaction(transaction_id)
    transaction.status = new_status
    transaction.status_message = description
    if new_status == TransactionStatus.FAILED:
        for order in transaction.orders:
            order.status = OrderStatus.PAYMENT_FAILED
    elif new_status == TransactionStatus.IN_PROCESS:
        for order in transaction.orders:
            order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
            order.statusDescription = "Submitted to warehouse"
            #After we got payment success, we will set logistics info also 
            logistics_client = LogisticsClient().get_client()
            #FIXME line item is only one now. If multiple will come, need to fix.
            item_id = order.lineitems[0].item_id
            logistics_info = logistics_client.getLogisticsInfo(order.customer_pincode, item_id)
            
            order.warehouse_id = logistics_info.warehouseId
            order.logistics_provider_id = logistics_info.providerId
            order.airwaybill_no = logistics_info.airway_billno
            order.tracking_id = order.airwaybill_no
            order.expected_delivery_time = datetime.datetime.now() + datetime.timedelta(days=logistics_info.deliveryTime)
            
            catalog_client = InventoryClient().get_client()
            catalog_client.reserveItemInWarehouse(item_id, logistics_info.warehouseId, order.lineitems[0].quantity)
            item_pricing = catalog_client.getItemPricing(item_id, order.warehouse_id)
            order.lineitems[0].transfer_price = item_pricing.transferPrice
        
        try:
            #Email the information of order placed to customer
            email_transaction_info_to_user(transaction_id)
        except Exception as ex:
            #Nothing much to do. Customer will not know that there was a transaction.
            print ex
    session.commit()
    return True

def email_transaction_info_to_user(transaction_id):
    transaction = get_transaction(transaction_id)
    
    html_header = """
<html>
<body>
<div>
    <p>
        Hello,<br /><br />
        Thanks for your placing your order with us. Following are the details of your order:
    </p>
    <div>
        Order Date: $order_date
    </div><hr />
    <div>
        <b>Order Details</b>
        <hr />
        <table>
        <tr>
            <th>Order No.</th>
            <th>Product</th>
            <th>Quantity</th>
            <th>Unit Price</th>
            <th>Amount</th>
        </tr>
    """
    total_amount = 0.0
    html_table = ""
    
    for order in transaction.orders:
        order_date = order.created_timestamp
        html_tr = "<tr><td>" + str(order.id) + "</td>"
        
        for lineitem in order.lineitems:
            html_tr += "<td>" + str(lineitem) + "</td>"
            html_tr += "<td>" + str(lineitem.quantity) + "</td>"
            html_tr += "<td>" + str(lineitem.unit_price) + "</td>"
            html_tr += "<td>" + str(lineitem.total_price) + "</td></tr>"
            total_amount += lineitem.total_price
            html_table += html_tr
    html_footer = """
        <tr><td colspan=5>&nbsp;</td></tr>
        <tr>
            <td colspan=4>Total Amount</td>
            <td>$total_amount</td>
        </tr>
        </table>
    </div><hr />
    <p>
        Best Wishes,<br />
        Saholic Team
    </p>
</div>
</body>
</html>
    """
#    formated_order_date = strftime("%B %d, %Y %H:%M %p", time.strptime(order_date, "%Y-%m-%d %H:%M:%S"))
    formated_order_date = order_date
    email_header = Template(html_header).substitute(dict(order_date = formated_order_date))
    email_footer = Template(html_footer).substitute(dict(total_amount = total_amount))
    
    user_client = UserClient().get_client()
    user = user_client.getUserById(transaction.customer_id)
    sendMail(Email(email_header + html_table + email_footer, "Saholic - Order Details", user.email))
    return True

class Email:
    def __init__(self, message, subject, to):
        self.data = message
        self.sender = ''
        self.subject = subject
        self.to = [to]

def sendMail(mail):
    if not mail:
        raise Exception(101, "mail not present")
    #msg = MIMEMultipart()
    #mail = Mail()
    if mail.sender:
        mail.data = "This mail is sent by " + mail.sender + "\n" + mail.data
        
    msg = MIMEText(mail.data, 'html')
    msg['To'] = ', '.join( mail.to )
    if mail.sender:
        msg['From'] = mail.sender
    else:    
        msg['From'] = "help@saholic.com"
    msg['Subject'] = mail.subject
    #msg.attach(mail.data)
    
    for to in mail.to:
        mail.sender = "help@shop2020.in"
        mail.password = "5h0p2o2o"
        mailServer = smtplib.SMTP("smtp.gmail.com", 587)
        mailServer.ehlo()
        mailServer.starttls()
        mailServer.ehlo()
        mailServer.login(mail.sender, mail.password)
        mailServer.sendmail(mail.password, to, msg.as_string())
        # Should be mailServer.quit(), but that crashes...
        mailServer.close()

def get_order(order_id):
    order = Order.get_by(id=order_id)
    if not order:
        raise TransactionServiceException(108, "no such order")
    
    return order

def get_orders_for_customer(customer_id, from_date, to_date, status):
    if not customer_id:
        raise TransactionServiceException(101, "bad customer id")
    query = Order.query.filter(Order.customer_id == customer_id)
    if status:
        query = query.filter(Order.status == status)
    if from_date:
        query = query.filter(Order.created_timestamp >from_date)
    if to_date:
        query = query.filter(Order.created_timestamp < to_date)
    return query.all()

def get_all_orders(status, from_date, to_date, warehouse_id):
    if not warehouse_id:
        raise TransactionServiceException(101, "bad warehouse id")
    query = Order.query.filter(Order.warehouse_id == warehouse_id)
    if status:
        query = query.filter(Order.status == status)
    if from_date:
        query = query.filter(Order.created_timestamp >from_date)
    if to_date:
        query = query.filter(Order.created_timestamp < to_date)
    return query.all()

def get_orders_by_billing_date(status, start_billing_date, end_billing_date, warehouse_id):
    if not warehouse_id:
        raise TransactionServiceException(101, "bad warehouse id")

    query = Order.query.filter(Order.warehouse_id == warehouse_id)
    
    if status:
        query = query.filter(Order.status == status)
    
    if start_billing_date:
        query = query.filter(Order.billing_timestamp >= start_billing_date)
    
    if end_billing_date:
        query = query.filter(Order.billing_timestamp <= end_billing_date)
    
    return query.all()

def get_orders_for_transaction(transaction_id):
    orders = Order.query.filter_by(transaction_id=transaction_id).all()
    if not orders:
        raise TransactionServiceException(101, "No order for the transaction")
    return orders

def get_line_items_for_order(order_id):
    query = LineItem.query.filter(LineItem.order_id == order_id)
    return query.all()

def change_order_status(self, orderId, status, description):
    order = get_order(orderId)
    order.status = status
    order.statusDescription = description
    session.commit()
    return True
    
def accept_order(self, orderId):
    order = get_order(orderId)
    order.status = OrderStatus.ACCEPTED
    order.statusDescription = "Order Accepted"
    order.accepted_timestamp = datetime.datetime.now()
    session.commit()
    return True

def bill_order(self, orderId):
    order = get_order(orderId)
    order.status = OrderStatus.BILLED
    order.statusDescription = "Order Billed"
    order.billing_timestamp = datetime.datetime.now()
    session.commit()
    return True

def add_billing_details(orderId, invoice_number, billed_by):
    order = Order.get_by(id=orderId)
    if not order:
        raise TransactionServiceException(101, "No order found for the givem orderid")
    order.invoice_number = invoice_number
    order.billed_by = billed_by
    session.commit()
    return True

def add_jacket_number(orderId, jacket_number):
    order = Order.get_by(id=orderId)
    if not order:
        raise TransactionServiceException(101, "No order found for the givem orderid")
    order.jacket_number = jacket_number 
    session.commit()
    return True

def batch_orders(warehouseId):
    if not warehouseId:
        raise TransactionServiceException(101, "bad warehouse id")
    
    batchno_generator = BatchNoGenerator()
    session.commit()
    query = Order.query.filter_by(warehouse_id=warehouseId)
    query = query.filter_by(status=OrderStatus.SUBMITTED_FOR_PROCESSING)
    query = query.order_by(Order.created_timestamp)
    pending_orders = query.all()
    
    serial_no = 1
    for order in pending_orders:
        order.batchNo = batchno_generator.id
        order.serialNo = serial_no
        serial_no += 1
    session.commit() 
    pending_orders = query.all()
    return pending_orders

def order_outofstock(orderId):
    order = get_order(orderId)
    order.status = OrderStatus.INVENTORY_LOW
    order.statusDescription = "Low Inventory"
    order.outofstock_timestamp = datetime.datetime.now()
    session.commit()
    return True

def mark_orders_as_manifested(warehouse_id, provider_id):
    try:
        current_timestamp = datetime.datetime.now()
        orders = Order.query.filter_by(warehouse_id = warehouse_id, logistics_provider_id = provider_id, status = OrderStatus.BILLED).all()
        for order in orders:
            order.status = OrderStatus.SHIPPED_FROM_WH
            order.statusDescription = "Order shipped from warehouse"
            order.shipping_timestamp = current_timestamp
        session.commit()
        return True
    except:
        return False

def mark_orders_as_picked_up(provider_id, pickup_details):
    for awb, pickup_timestamp in pickup_details.iteritems():
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
        if order == None:
            raise TransactionServiceException(102, "No order found for the awb: " + awb)
        order.status = OrderStatus.SHIPPED_TO_LOGST
        order.statusDescription = "Order picked up by Courier Company"
        order.pickup_timestamp = pickup_timestamp
    session.commit()

    current_time = datetime.datetime.now()
    to_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
    from_datetime = to_datetime - datetime.timedelta(2)
    orders_not_picked_up = Order.query.filter_by(logistics_provider_id = provider_id).filter_by(status=OrderStatus.SHIPPED_FROM_WH).filter(Order.shipping_timestamp >= from_datetime).filter(Order.shipping_timestamp <= to_datetime).all()
    return orders_not_picked_up

def mark_orders_as_delivered(provider_id, delivered_orders):
    for awb, detail in delivered_orders.iteritems():
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
        if order == None:
            raise TransactionServiceException(103, "No order found for the awb:" + awb)
        order.status = OrderStatus.DELIVERY_SUCCESS
        order.statusDescription = "Order delivered"
        order.delivery_timestamp, order.receiver = detail.split('|')
    session.commit()

def mark_orders_as_failed(provider_id, returned_orders):
    for awb, detail in returned_orders.iteritems():
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
        if order == None:
            raise TransactionServiceException(103, "No order found for the awb:" + awb)
        order.status = OrderStatus.FAILED
        order.delivery_timestamp, reason = detail.split('|')
        order.statusDescription = "Order Returned to Origin:" + reason
    session.commit()    

def update_non_delivery_reason(provider_id, undelivered_orders):
    for awb, reason in undelivered_orders.iteritems():
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
        if order == None:
            raise TransactionServiceException(103, "No order found for the awb:" + awb)
        order.statusDescription = reason
    session.commit()

def get_alerts(order_id, all):
    query = Alerts.query.filter_by(order_id=order_id)
    if not all:
        query = query.filter_by(valid=True)
    return query.all()

def set_alert(order_id, unset, type, comment):
    #get existing alert
    if unset:
        query = Alerts.query.filter_by(order_id=order_id)
        query = query.filter_by(type=type)
        alerts = query.all()
        for alert in alerts:
            if alert.valid:
                alert.valid = False
                alert.comment = comment
                alert.time_unset = datetime.datetime.now()
    else:
        alert = Alerts()
        alert.order_id = order_id
        alert.valid = True
        alert.type = type
        alert.comment = comment
        alert.time_set = datetime.datetime.now()
    session.commit()    

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