Subversion Repositories SmartDukaan

Rev

Rev 4421 | Rev 4435 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
104 ashish 1
'''
2
Created on 29-Mar-2010
3
 
2536 chandransh 4
@author: Chandranshu
104 ashish 5
'''
2536 chandransh 6
 
4369 rajveer 7
from datetime import date, timedelta
2536 chandransh 8
from elixir import *
3499 mandeep.dh 9
from reportlab.lib.units import inch
2536 chandransh 10
from reportlab.pdfgen.canvas import Canvas
11
from reportlab.rl_config import defaultPageSize
3499 mandeep.dh 12
from shop2020.clients.CatalogClient import CatalogClient
13
from shop2020.clients.HelperClient import HelperClient
14
from shop2020.clients.LogisticsClient import LogisticsClient
2747 chandransh 15
from shop2020.clients.PaymentClient import PaymentClient
3499 mandeep.dh 16
from shop2020.clients.UserClient import UserClient
17
from shop2020.clients.WarehouseClient import WarehouseClient
4421 mandeep.dh 18
from shop2020.config.client.ConfigClient import ConfigClient
3499 mandeep.dh 19
from shop2020.model.v1 import order
20
from shop2020.model.v1.order.impl.DataService import Transaction, LineItem, \
4394 rajveer 21
    Order, BatchNoGenerator, InvoiceIDGenerator, \
22
    TransactionRequiringExtraProcessing, OrderInventory, Alert
2687 chandransh 23
from shop2020.model.v1.order.impl.model.ReturnOrder import ReturnOrder
3499 mandeep.dh 24
from shop2020.thriftpy.logistics.ttypes import DeliveryType
25
from shop2020.thriftpy.model.v1.catalog.ttypes import BillingType
4394 rajveer 26
from shop2020.thriftpy.model.v1.order.ttypes import \
4008 mandeep.dh 27
    TransactionServiceException, TransactionStatus, OrderStatus, DelayReason, \
4369 rajveer 28
    ExtraTransactionProcessingType, HotspotAction, TimeoutSummary
4421 mandeep.dh 29
from shop2020.thriftpy.payments.ttypes import PaymentException
3499 mandeep.dh 30
from shop2020.thriftpy.warehouse.ttypes import PurchaseOrder, \
4365 mandeep.dh 31
    LineItem as POLineItem, ScanType
3499 mandeep.dh 32
from shop2020.utils.EmailAttachmentSender import mail, get_attachment_part
855 rajveer 33
from shop2020.utils.Utils import to_py_date, to_java_date
4008 mandeep.dh 34
from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
3499 mandeep.dh 35
from sqlalchemy.sql import func
36
from sqlalchemy.sql.expression import and_, or_, desc, not_, distinct
37
from string import Template
38
from textwrap import dedent
39
import datetime
40
import logging
41
import os
4421 mandeep.dh 42
import sys
43
import traceback
3499 mandeep.dh 44
import time
45
logging.basicConfig(level=logging.DEBUG)
104 ashish 46
 
3499 mandeep.dh 47
 
4019 chandransh 48
try:
49
    config_client = ConfigClient()
50
    PREPAID_SHIPPING_CUTOFF_TIME = int(config_client.get_property('delivery_cutoff_time'))
51
except Exception as ex:
52
    print "[ERROR] Unexpected config error:", sys.exc_info()[0]
53
    PREPAID_SHIPPING_CUTOFF_TIME = 15
3499 mandeep.dh 54
 
4019 chandransh 55
COD_SHIPPING_CUTOFF_TIME = 12
3499 mandeep.dh 56
 
2819 chandransh 57
PAGE_HEIGHT=defaultPageSize[1]
58
PAGE_WIDTH=defaultPageSize[0]
59
 
3499 mandeep.dh 60
ORDER_STATUS_TO_USER_TRUST_LEVEL_DELTA_DICT = {
61
        OrderStatus.SALES_RET_RESHIPPED     :  3,
62
        OrderStatus.SALES_RETURN_IN_TRANSIT : -5,
63
        OrderStatus.DELIVERY_SUCCESS        :  1,
3578 mandeep.dh 64
        OrderStatus.DOA_CERT_INVALID        : -5
3499 mandeep.dh 65
}
66
 
104 ashish 67
def get_new_transaction():
68
    transaction = Transaction()
69
    transaction.createdOn = datetime.datetime.now()
738 chandransh 70
    transaction.status = TransactionStatus.INIT
104 ashish 71
    transaction.status_message = "New transaction"
483 rajveer 72
    return transaction
73
 
74
def create_order(t_order):
75
    order = Order()
76
    if t_order.warehouse_id:
77
        order.warehouse_id = t_order.warehouse_id
509 rajveer 78
    if t_order.logistics_provider_id:    
483 rajveer 79
        order.logistics_provider_id = t_order.logistics_provider_id
80
        order.airwaybill_no = t_order.airwaybill_no
81
        order.tracking_id = t_order.tracking_id
4009 chandransh 82
    if t_order.expected_shipping_time:
4019 chandransh 83
        order.expected_shipping_time = to_py_date(t_order.expected_shipping_time).replace(hour=PREPAID_SHIPPING_CUTOFF_TIME, minute=0, second=0)
4102 chandransh 84
        order.promised_shipping_time = order.expected_shipping_time
4009 chandransh 85
    if t_order.expected_delivery_time:
483 rajveer 86
        order.expected_delivery_time = to_py_date(t_order.expected_delivery_time)
4102 chandransh 87
        order.promised_delivery_time = order.expected_delivery_time
483 rajveer 88
    if t_order.customer_id:    
89
        order.customer_id = t_order.customer_id
90
        order.customer_name = t_order.customer_name
860 rajveer 91
        order.customer_city = t_order.customer_city
92
        order.customer_state = t_order.customer_state
483 rajveer 93
        order.customer_mobilenumber = t_order.customer_mobilenumber
94
        order.customer_pincode = t_order.customer_pincode
738 chandransh 95
        order.customer_address1 = t_order.customer_address1
96
        order.customer_address2 = t_order.customer_address2
483 rajveer 97
        order.customer_email = t_order.customer_email
98
    #new status and status description to be added    
716 rajveer 99
    order.status = t_order.status  
483 rajveer 100
    order.statusDescription = t_order.statusDescription
101
    order.total_amount = t_order.total_amount
102
    order.total_weight = t_order.total_weight
103
    if t_order.created_timestamp:
104
        order.created_timestamp = to_py_date(t_order.created_timestamp)
105
    else:
685 chandransh 106
        order.created_timestamp = datetime.datetime.now()
483 rajveer 107
    return order
108
 
109
def create_transaction(t_transaction):
110
    t_orders = t_transaction.orders
111
    if not t_orders:
112
        raise TransactionServiceException(101, "Orders missing from the transaction")
113
    transaction = get_new_transaction()
114
    transaction.customer_id = t_transaction.customer_id 
115
    transaction.shopping_cart_id = t_transaction.shoppingCartid
2219 varun.gupt 116
    transaction.coupon_code = t_transaction.coupon_code
2815 vikas 117
    transaction.session_source = t_transaction.sessionSource
118
    transaction.session_start_time = to_py_date(t_transaction.sessionStartTime)
3858 vikas 119
    transaction.first_source = t_transaction.firstSource
120
    transaction.first_source_start_time = to_py_date(t_transaction.firstSourceTime)
483 rajveer 121
 
122
    for t_order in t_orders:
123
        order = create_order(t_order)
124
        order.transaction = transaction 
125
        for line_item in t_order.lineitems:
126
            litem = LineItem()
716 rajveer 127
            litem.item_id = line_item.item_id
963 chandransh 128
            litem.productGroup = line_item.productGroup
483 rajveer 129
            litem.brand = line_item.brand
130
            if line_item.model_number:
131
                litem.model_number = line_item.model_number
132
            if line_item.model_name:    
133
                litem.model_name = line_item.model_name
908 chandransh 134
            if line_item.color:
135
                litem.color = line_item.color
483 rajveer 136
            if line_item.extra_info:
137
                litem.extra_info = line_item.extra_info
138
            litem.quantity = line_item.quantity
139
            litem.unit_price = line_item.unit_price
140
            litem.unit_weight = line_item.unit_weight
141
            litem.total_price = line_item.total_price
142
            litem.total_weight = line_item.total_weight
4283 anupam.sin 143
            '''litem.transfer_price = line_item.transfer_price'''
4172 rajveer 144
            litem.dealText = line_item.dealText
4295 varun.gupt 145
            litem.warranty_expiry_timestamp = to_py_date(line_item.warrantry_expiry_timestamp)
1976 varun.gupt 146
 
483 rajveer 147
            """
148
            if line_item.addedOn:
149
                litem.added_on = to_py_date(line_item.addedOn)
150
            else:
151
                litem.added_on = datetime.datetime.now()
152
            """
153
            litem.order = order
154
    session.commit()
155
    return transaction.id
156
 
157
def get_transaction(transaction_id):
158
    transaction = Transaction.get_by(id=transaction_id)
159
    if not transaction:
160
        raise TransactionServiceException(108, "no such transaction")
161
 
162
    return transaction
163
 
164
def get_transactions_for_customer(customer_id, from_date, to_date, status):
165
    if not customer_id:
166
        raise TransactionServiceException(101, "bad customer id")
167
    query = Transaction.query.filter(Transaction.customer_id == customer_id)
1493 vikas 168
    if status is not None:
483 rajveer 169
        query = query.filter(Transaction.status == status)
170
    if from_date:
171
        query = query.filter(Transaction.createdOn >from_date)
172
    if to_date:
173
        query = query.filter(Transaction.createdOn < to_date)
174
    return query.all()
175
 
176
def get_transactions_for_shopping_cart_id(shopping_cart_id):
177
    transactions = Transaction.query.filter_by(shopping_cart_id=shopping_cart_id).all()
178
    return transactions
179
 
180
def get_transaction_status(transaction_id):
181
    if not transaction_id:
182
        raise TransactionServiceException(101, "bad transaction id")
183
 
184
    transaction = get_transaction(transaction_id)
185
 
186
    return transaction.status
187
 
188
def change_transaction_status(transaction_id, new_status, description):
189
    transaction = get_transaction(transaction_id)
190
    transaction.status = new_status
191
    transaction.status_message = description
690 chandransh 192
    if new_status == TransactionStatus.FAILED:
193
        for order in transaction.orders:
194
            order.status = OrderStatus.PAYMENT_FAILED
2339 chandransh 195
            order.statusDescription = "Payment Failed"
4247 rajveer 196
    elif new_status == TransactionStatus.AUTHORIZED or new_status == TransactionStatus.FLAGGED:
690 chandransh 197
        for order in transaction.orders:
4247 rajveer 198
            if new_status == TransactionStatus.AUTHORIZED:
199
                order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
200
                order.statusDescription = "Submitted to warehouse"
201
            elif new_status == TransactionStatus.FLAGGED:
202
                order.status = OrderStatus.PAYMENT_FLAGGED
203
                order.statusDescription = "Payment flagged by gateway"
3092 chandransh 204
            order.cod = False
743 rajveer 205
            #After we got payment success, we will set logistics info also 
206
            logistics_client = LogisticsClient().get_client()
207
            #FIXME line item is only one now. If multiple will come, need to fix.
871 chandransh 208
            item_id = order.lineitems[0].item_id
3044 chandransh 209
            logistics_info = logistics_client.getLogisticsInfo(order.customer_pincode, item_id, DeliveryType.PREPAID)
743 rajveer 210
 
1730 ankur.sing 211
            current_time = datetime.datetime.now()
212
            logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
4009 chandransh 213
            logistics_info.shippingTime = adjust_delivery_time(current_time, logistics_info.shippingTime)
1730 ankur.sing 214
 
743 rajveer 215
            order.warehouse_id = logistics_info.warehouseId
216
            order.logistics_provider_id = logistics_info.providerId
217
            order.airwaybill_no = logistics_info.airway_billno
218
            order.tracking_id = order.airwaybill_no
4019 chandransh 219
            order.expected_shipping_time = (current_time + datetime.timedelta(days=logistics_info.shippingTime)).replace(hour=PREPAID_SHIPPING_CUTOFF_TIME, minute=0, second=0)
4102 chandransh 220
            order.promised_shipping_time = order.expected_shipping_time
1730 ankur.sing 221
            order.expected_delivery_time = current_time + datetime.timedelta(days=logistics_info.deliveryTime)
3986 chandransh 222
            order.promised_delivery_time = order.expected_delivery_time 
871 chandransh 223
 
3133 rajveer 224
            catalog_client = CatalogClient().get_client()
871 chandransh 225
            catalog_client.reserveItemInWarehouse(item_id, logistics_info.warehouseId, order.lineitems[0].quantity)
1351 varun.gupt 226
 
4316 anupam.sin 227
            try:
228
                item_pricing = catalog_client.getItemPricing(item_id, -1)
229
                order.lineitems[0].transfer_price = item_pricing.transferPrice
230
            except:
231
                print "Not able to get transfer price. Skipping"
3064 chandransh 232
    elif new_status == TransactionStatus.COD_IN_PROCESS:
233
        for order in transaction.orders:
234
            order.status = OrderStatus.INIT
235
            order.statusDescription = "Verification Pending"
236
            order.cod = True
237
            #After we got payment success, we will set logistics info also 
238
            logistics_client = LogisticsClient().get_client()
239
            #FIXME line item is only one now. If multiple will come, need to fix.
240
            item_id = order.lineitems[0].item_id
241
            logistics_info = logistics_client.getLogisticsInfo(order.customer_pincode, item_id, DeliveryType.COD)
242
 
243
            current_time = datetime.datetime.now()
244
            logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
4009 chandransh 245
            logistics_info.shippingTime = adjust_delivery_time(current_time, logistics_info.shippingTime)
3064 chandransh 246
 
247
            order.warehouse_id = logistics_info.warehouseId
248
            order.logistics_provider_id = logistics_info.providerId
249
            order.airwaybill_no = logistics_info.airway_billno
250
            order.tracking_id = order.airwaybill_no
4019 chandransh 251
            order.expected_shipping_time = (current_time + datetime.timedelta(days=logistics_info.shippingTime)).replace(hour=COD_SHIPPING_CUTOFF_TIME, minute=0, second=0)
4102 chandransh 252
            order.promised_shipping_time = order.expected_shipping_time
3064 chandransh 253
            order.expected_delivery_time = current_time + datetime.timedelta(days=logistics_info.deliveryTime)
3986 chandransh 254
            order.promised_delivery_time = order.expected_delivery_time
3064 chandransh 255
 
3133 rajveer 256
            catalog_client = CatalogClient().get_client()
3064 chandransh 257
            catalog_client.reserveItemInWarehouse(item_id, logistics_info.warehouseId, order.lineitems[0].quantity)
258
 
4316 anupam.sin 259
            try:
260
                item_pricing = catalog_client.getItemPricing(item_id, -1)
261
                order.lineitems[0].transfer_price = item_pricing.transferPrice        
262
            except:
263
                print "Not able to get transfer price. Skipping"
483 rajveer 264
    session.commit()
3499 mandeep.dh 265
 
3530 mandeep.dh 266
    try:
267
        if new_status == TransactionStatus.COD_IN_PROCESS:
4008 mandeep.dh 268
            transaction_requiring_extra_processing = TransactionRequiringExtraProcessing()
269
            transaction_requiring_extra_processing.category = 'COD_VERIFICATION'
270
            transaction_requiring_extra_processing.transaction_id = transaction_id
271
            session.commit()
4247 rajveer 272
        elif new_status == TransactionStatus.FLAGGED:
273
            transaction_requiring_extra_processing = TransactionRequiringExtraProcessing()
274
            transaction_requiring_extra_processing.category = 'PAYMENT_FLAGGED'
275
            transaction_requiring_extra_processing.transaction_id = transaction_id
276
            session.commit()
3530 mandeep.dh 277
    except Exception as e:
4065 mandeep.dh 278
        print "Error inserting transaction Id: " + str(transaction_id) + " due to " + str(e)
3499 mandeep.dh 279
 
483 rajveer 280
    return True
281
 
3994 chandransh 282
def __get_holidays(start_time=0L, to_time=-1L):
283
    '''
284
    Get the list of all public holidays since start time including the
285
    day of start time if it's a holiday
286
    '''
287
    midnightTime = start_time.replace(hour=0, minute=0, second=0, microsecond=0)
1730 ankur.sing 288
    fromDate = to_java_date(midnightTime)
289
    logistics_client = LogisticsClient().get_client()
3994 chandransh 290
    #TODO: This list should be cached after the first call.
291
    #Calling logistics server is also unnecessary.
292
    holidays = logistics_client.getHolidays(fromDate, to_time)
293
    holidays = [to_py_date(holiday).date() for holiday in holidays]
294
    return holidays
295
 
296
 
297
def adjust_delivery_time(start_time, delivery_days):
298
    '''
299
    Returns the actual no. of days which will pass while 'delivery_days'
300
    no. of business days will pass since 'order_time'. 
301
    '''
302
    start_date = start_time.date()
303
    end_date = start_date + datetime.timedelta(days = delivery_days)
304
    holidays = __get_holidays(start_time)
1730 ankur.sing 305
 
3994 chandransh 306
    while start_date <= end_date:
307
        if start_date.weekday() == 6 or start_date in holidays:
1730 ankur.sing 308
            delivery_days = delivery_days + 1
3994 chandransh 309
            end_date = end_date + datetime.timedelta(days = 1)
4088 chandransh 310
        start_date = start_date + datetime.timedelta(days = 1)
3994 chandransh 311
 
1730 ankur.sing 312
    return delivery_days
313
 
1398 varun.gupt 314
def enqueue_transaction_info_email(transaction_id):
1262 varun.gupt 315
    transaction = get_transaction(transaction_id)
316
 
317
    html_header = """
318
<html>
319
<body>
320
<div>
321
    <p>
322
        Hello,<br /><br />
1742 rajveer 323
        Thanks for placing order with us. Following are the details of your order:
1262 varun.gupt 324
    </p>
325
    <div>
326
        Order Date: $order_date
1569 varun.gupt 327
    </div>
1262 varun.gupt 328
    <div>
329
        <table>
1569 varun.gupt 330
        <tr><td colspan="5"><hr /></td></tr>
331
        <tr><td colspan="5" align="left"><b>Order Details</b></td></tr>
332
        <tr><td colspan="5"><hr /></td></tr>
1262 varun.gupt 333
        <tr>
2050 varun.gupt 334
            <th width="100">Order No.</th>
335
            <th>Product</th>
336
            <th width="100">Quantity</th>
337
            <th width="100">Unit Price</th>
338
            <th width="100">Amount</th>
1262 varun.gupt 339
        </tr>
340
    """
1398 varun.gupt 341
    user_email = ""
1262 varun.gupt 342
    total_amount = 0.0
343
    html_table = ""
1569 varun.gupt 344
    order_date = datetime.datetime.now()
1262 varun.gupt 345
 
346
    for order in transaction.orders:
347
        order_date = order.created_timestamp
1398 varun.gupt 348
        user_email = order.customer_email
1569 varun.gupt 349
        html_tr = "<tr><td align='center'>" + str(order.id) + "</td>"
1262 varun.gupt 350
 
351
        for lineitem in order.lineitems:
2050 varun.gupt 352
            lineitem_total_price = round(lineitem.total_price, 2)
353
 
1276 chandransh 354
            html_tr += "<td>" + str(lineitem) + "</td>"
2050 varun.gupt 355
            html_tr += "<td align='center'>" + ("%.0f" % lineitem.quantity) + "</td>"
356
            html_tr += "<td align='center'> Rs. " + ("%.2f" % lineitem.unit_price) + "</td>"
357
            html_tr += "<td align='center'> Rs. " + ("%.2f" % lineitem_total_price) + "</td></tr>"
358
            total_amount += lineitem_total_price
1262 varun.gupt 359
            html_table += html_tr
2050 varun.gupt 360
 
1262 varun.gupt 361
    html_footer = """
362
        <tr><td colspan=5>&nbsp;</td></tr>
1565 varun.gupt 363
        <tr><td colspan=5><hr /></td></tr>
1262 varun.gupt 364
        <tr>
365
            <td colspan=4>Total Amount</td>
2050 varun.gupt 366
            <td> Rs. $total_amount</td>
1262 varun.gupt 367
        </tr>
1569 varun.gupt 368
        <tr><td colspan=5><hr /></td></tr>
4232 varun.gupt 369
        <tr>
370
            <td colspan=5>
371
                Note:- With the onset of dense fog in North India, it severely hits the operations of our courier partners. 
372
                We would like to mention that our deliveries might be slightly delayed. 
373
                We look forward to your support and understanding with regards to anticipated delays.
374
            </td>
375
        </tr>
1262 varun.gupt 376
        </table>
1569 varun.gupt 377
    </div>
1262 varun.gupt 378
    <p>
379
        Best Wishes,<br />
380
        Saholic Team
381
    </p>
382
</div>
383
</body>
384
</html>
385
    """
1398 varun.gupt 386
 
1569 varun.gupt 387
    dt = datetime.datetime.strptime(str(order_date), "%Y-%m-%d %H:%M:%S")
1565 varun.gupt 388
    formated_order_date = dt.strftime("%A, %d. %B %Y %I:%M%p")
389
 
1262 varun.gupt 390
    email_header = Template(html_header).substitute(dict(order_date = formated_order_date))
2050 varun.gupt 391
    email_footer = Template(html_footer).substitute(dict(total_amount = "%.2f" % total_amount))
1262 varun.gupt 392
 
1351 varun.gupt 393
    try:
394
        helper_client = HelperClient().get_client()
1398 varun.gupt 395
        helper_client.saveUserEmailForSending(user_email, "", "Saholic - Order Details", email_header + html_table + email_footer, str(transaction_id), "TransactionInfo")
1351 varun.gupt 396
        return True
397
    except Exception as e:
398
        print e
399
        return False
1262 varun.gupt 400
 
483 rajveer 401
def get_order(order_id):
402
    order = Order.get_by(id=order_id)
403
    if not order:
404
        raise TransactionServiceException(108, "no such order")
405
 
406
    return order
407
 
3014 chandransh 408
def get_orders_for_customer(customer_id, from_date, to_date, statuses):
483 rajveer 409
    if not customer_id:
410
        raise TransactionServiceException(101, "bad customer id")
411
    query = Order.query.filter(Order.customer_id == customer_id)
3014 chandransh 412
    if statuses:
413
        query = query.filter(Order.status.in_(tuple(statuses)))
483 rajveer 414
    if from_date:
415
        query = query.filter(Order.created_timestamp >from_date)
416
    if to_date:
417
        query = query.filter(Order.created_timestamp < to_date)
418
    return query.all()
419
 
1528 ankur.sing 420
def get_order_for_customer(order_id, customer_id):
421
    if not customer_id:
422
        raise TransactionServiceException(101, "bad customer id")
423
    order = get_order(order_id)
424
    if order.customer_id != customer_id:
425
        raise TransactionServiceException(108, "order: " + str(order_id) + " does not belong to customer: " + str(customer_id))
426
    return order
427
 
483 rajveer 428
def get_all_orders(status, from_date, to_date, warehouse_id):
429
    if not warehouse_id:
430
        raise TransactionServiceException(101, "bad warehouse id")
431
    query = Order.query.filter(Order.warehouse_id == warehouse_id)
432
    if status:
433
        query = query.filter(Order.status == status)
434
    if from_date:
435
        query = query.filter(Order.created_timestamp >from_date)
436
    if to_date:
437
        query = query.filter(Order.created_timestamp < to_date)
438
    return query.all()
439
 
4133 chandransh 440
def get_orders_in_batch(statuses=[], offset=0, limit=0, warehouse_id=None):
4296 rajveer 441
    query = Order.query
442
    if warehouse_id:
443
        query = query.filter(Order.warehouse_id == warehouse_id)
4133 chandransh 444
    if statuses:
445
        query = query.filter(Order.status.in_(statuses))
446
    query = query.offset(offset)
447
    if limit:
448
        query = query.limit(limit)
449
    return query.all()
450
 
451
def get_order_count(statuses=[], warehouse_id=None):
452
    if not warehouse_id:
453
        raise TransactionServiceException(101, "bad warehouse id")
454
    query = session.query(func.count(Order.id)).filter(Order.warehouse_id == warehouse_id)
455
    if statuses:
456
        query = query.filter(Order.status.in_(statuses))
457
    return query.scalar()
458
 
1382 varun.gupt 459
def get_returnable_orders_for_customer(customer_id, limit = None):
460
    if not customer_id:
461
        raise TransactionServiceException(101, "bad customer id")
462
 
463
    query = Order.query.filter(Order.customer_id == customer_id)
464
    query = query.filter(Order.status != OrderStatus.PAYMENT_FAILED)
465
    query = query.filter(Order.status != OrderStatus.REJECTED)
466
    query = query.filter(Order.status > OrderStatus.SHIPPED_FROM_WH)
467
    query = query.filter(or_(Order.status < OrderStatus.DELIVERY_SUCCESS, Order.delivery_timestamp < datetime.datetime.now() + datetime.timedelta(hours = 48)))
468
    orders = query.all()
469
    order_ids = [order.id for order in orders]
470
    return order_ids
471
 
472
def get_cancellable_orders_for_customer(customer_id, limit = None):
473
    if not customer_id:
474
        raise TransactionServiceException(101, "bad customer id")
475
 
476
    query = Order.query.filter(Order.customer_id == customer_id)
4343 varun.gupt 477
    query = query.filter(Order.status != OrderStatus.PAYMENT_FAILED)
1382 varun.gupt 478
    query = query.filter(Order.status != OrderStatus.REJECTED)
4288 anupam.sin 479
    query = query.filter(Order.status <= OrderStatus.BILLED)
1382 varun.gupt 480
    orders = query.all()
481
    return [order.id for order in orders]
482
 
995 varun.gupt 483
def get_orders_by_billing_date(status, start_billing_date, end_billing_date, warehouse_id):
484
    if not warehouse_id:
485
        raise TransactionServiceException(101, "bad warehouse id")
486
 
487
    query = Order.query.filter(Order.warehouse_id == warehouse_id)
488
 
489
    if status:
490
        query = query.filter(Order.status == status)
491
 
492
    if start_billing_date:
493
        query = query.filter(Order.billing_timestamp >= start_billing_date)
494
 
495
    if end_billing_date:
496
        query = query.filter(Order.billing_timestamp <= end_billing_date)
497
 
498
    return query.all()
499
 
3451 chandransh 500
def get_orders_by_shipping_date(from_shipping_date, to_shipping_date, provider_id, warehouse_id, cod):
501
    query = Order.query.filter(Order.cod == cod)
3427 chandransh 502
 
503
    if warehouse_id and warehouse_id != -1:
504
        query = query.filter(Order.warehouse_id == warehouse_id)
505
 
506
    if provider_id and provider_id != -1:
507
        query = query.filter(Order.logistics_provider_id == provider_id)
508
 
509
    if from_shipping_date:
510
        query = query.filter(Order.shipping_timestamp >= from_shipping_date)
511
 
512
    if to_shipping_date:
513
        query = query.filter(Order.shipping_timestamp <= to_shipping_date)
514
 
515
    query = query.order_by(Order.airwaybill_no)
516
 
517
    return query.all()
518
 
1528 ankur.sing 519
def get_orders_for_transaction(transaction_id, customer_id):
520
    orders = Order.query.filter_by(transaction_id=transaction_id, customer_id=customer_id).all()
521
 
1208 chandransh 522
    if not orders:
523
        raise TransactionServiceException(101, "No order for the transaction")
524
    return orders
525
 
1405 ankur.sing 526
def get_undelivered_orders(provider_id, warehouse_id):
527
    query = Order.query
528
    if provider_id != -1:
529
        query = query.filter_by(Order.logistics_provider_id == provider_id)
530
    if warehouse_id != -1:
531
        query = query.filter(Order.warehouse_id == warehouse_id)
532
    query = query.filter(and_(Order.status != OrderStatus.DELIVERY_SUCCESS, Order.status != OrderStatus.FAILED, \
533
                              Order.status > OrderStatus.SHIPPED_FROM_WH))
1479 ankur.sing 534
    #Get last midnight time instead of current time as courier company would have sent the 
535
    #delivery records updated at least till midnight and not by the current time.
536
    time_format = "%Y-%m-%d %H:%M:%S.%f"
537
    t = time.strptime(str(datetime.datetime.now()), time_format)
538
    midnightTime = datetime.datetime(*t[:3])
539
    query = query.filter(Order.expected_delivery_time < midnightTime)
1405 ankur.sing 540
    orders = query.all()
541
    return orders
542
 
1208 chandransh 543
def get_line_items_for_order(order_id):
544
    query = LineItem.query.filter(LineItem.order_id == order_id)
545
    return query.all()
546
 
483 rajveer 547
def change_order_status(self, orderId, status, description):
548
    order = get_order(orderId)
549
    order.status = status
550
    order.statusDescription = description
551
    session.commit()
3578 mandeep.dh 552
    update_trust_level(order)
553
    return True
3499 mandeep.dh 554
 
3578 mandeep.dh 555
def update_trust_level(order):
3530 mandeep.dh 556
    try:
3578 mandeep.dh 557
        trust_level_delta = 0
558
        if order.cod == True:
559
            trust_level_delta = ORDER_STATUS_TO_USER_TRUST_LEVEL_DELTA_DICT.get(order.status, 0)
560
 
3530 mandeep.dh 561
        if (trust_level_delta != 0):
562
            user_client = UserClient().get_client()
563
            user_client.increaseTrustLevel(order.customer_id, trust_level_delta)
564
    except Exception as e:
565
        print e
3499 mandeep.dh 566
 
483 rajveer 567
    return True
3064 chandransh 568
 
569
def verify_order(self, orderId):
570
    logging.info("Verifying order no: " + str(orderId))
571
    order = get_order(orderId)
572
    if order.status == OrderStatus.INIT:
573
        order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
574
        order.statusDescription = "Submitted for processing"
575
        order.verification_timestamp = datetime.datetime.now()
576
        session.commit()
577
        logging.info("Successfully verified order no: " + str(orderId))
578
        return True
579
    else:
580
        logging.warning("Verify called for order no." + str(orderId) +" which is not in verification pending state");
581
        return False
582
 
4285 rajveer 583
def accept_order(orderId):
3064 chandransh 584
    logging.info("Accepting order no: " + str(orderId))
921 rajveer 585
    order = get_order(orderId)
4306 rajveer 586
    if order.status in [OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW, OrderStatus.LOW_INV_PO_RAISED, OrderStatus.LOW_INV_REVERSAL_IN_PROCESS, OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT]:
3064 chandransh 587
        if not order.cod:
588
            if order.transaction.status == TransactionStatus.AUTHORIZED:
4421 mandeep.dh 589
                __capture_txn(order)
3010 chandransh 590
        order.status = OrderStatus.ACCEPTED
591
        order.statusDescription = "Order Accepted"
592
        order.accepted_timestamp = datetime.datetime.now()
593
        session.commit()
3064 chandransh 594
        logging.info("Successfully accepted the order no.:" + str(orderId))
3010 chandransh 595
        return True
596
    else:
3064 chandransh 597
        logging.warning("Accept called for the unacceptable order: " + str(orderId))
3010 chandransh 598
        return False
921 rajveer 599
 
4421 mandeep.dh 600
def __capture_txn(order):
601
    txnId = order.transaction_id
3010 chandransh 602
    logging.info("Capturing payment for merchant txn:" + str(txnId))
4421 mandeep.dh 603
    try:
604
        payment_client = PaymentClient().get_client()
605
        capture_result = payment_client.capturePayment(txnId)
606
        if capture_result:
607
            logging.info("Successfully captured payment for merchant txn:" + str(txnId))
608
            change_transaction_status(txnId, TransactionStatus.IN_PROCESS, "Payment received")
609
        else:
610
            raise TransactionServiceException(115, "Payment capture failed.")
611
    except PaymentException as e:
612
        if e.error_code == 106:
613
            order.status = OrderStatus.CAPTURE_IN_PROCESS
614
            session.commit()
615
            raise TransactionServiceException(122, "Unable to capture payment due to connection issue.")
616
        else:
617
            raise TransactionServiceException(115, "Payment capture failed.")
3010 chandransh 618
 
4285 rajveer 619
def add_billing_details(orderId, invoice_number, imeiNumber, itemNumber, billedBy, jacketNumber, billingType, vendorId):
620
    if jacketNumber is None or jacketNumber <= 0:
2783 chandransh 621
        raise TransactionServiceException(110, "Invalid jacket number")
622
 
4285 rajveer 623
    if billedBy is None or billedBy.strip() == "":
2783 chandransh 624
        raise TransactionServiceException(110, "Invalid Biller")
625
 
1149 chandransh 626
    order = Order.get_by(id=orderId)
627
    if not order:
2783 chandransh 628
        raise TransactionServiceException(101, "No order found for the given order id" + str(orderId))
629
 
4283 anupam.sin 630
    if order.status == OrderStatus.ACCEPTED:
4285 rajveer 631
        order.jacket_number = jacketNumber
632
        if billingType == BillingType.OURS:
633
            if itemNumber is None or itemNumber.strip() == "":
4283 anupam.sin 634
                raise TransactionServiceException(110, "Invalid item number")
635
 
636
            order.invoice_number = get_next_invoice_number()
637
            lineitem = order.lineitems[0]
4285 rajveer 638
            if lineitem.productGroup == "Handsets" and imeiNumber <= 0:
4283 anupam.sin 639
                raise TransactionServiceException(110, "No IMEI number supplied for a handset.")
4285 rajveer 640
            lineitem.item_number = itemNumber
641
            if imeiNumber > 0:
642
                lineitem.imei_number = str(imeiNumber)
4283 anupam.sin 643
        else:
644
            order.invoice_number = invoice_number
645
 
2842 chandransh 646
        order.status = OrderStatus.BILLED
647
        order.statusDescription = "Order Billed"
648
        order.billing_timestamp = datetime.datetime.now()
4285 rajveer 649
        order.billed_by = billedBy
2842 chandransh 650
        lineitem = order.lineitems[0]
4283 anupam.sin 651
        item_id = lineitem.item_id
652
        catalog_client = CatalogClient().get_client()
4285 rajveer 653
        item_pricing = catalog_client.getItemPricing(item_id, vendorId)
654
        order.vendorId = vendorId
4283 anupam.sin 655
        lineitems = order.lineitems
656
        for lineitem in lineitems:
657
            catalog_client.reduceReservationCount(item_id, order.warehouse_id, lineitem.quantity)
658
        order.lineitems[0].transfer_price = item_pricing.transferPrice
659
        session.commit()
4365 mandeep.dh 660
 
661
        # For Mahipal warehouse, we need to scan out items for every billed order
662
        if order.warehouse_id == 7:
663
            try:
664
                warehouse_client = WarehouseClient().get_client()
665
                warehouse_client.scanOut(itemNumber, str(imeiNumber), ScanType.SALE)
666
            except:
667
                print sys.exc_info()[0]
668
                print 'Could not scan out orders'
669
 
4283 anupam.sin 670
        return True
671
    else:
672
        return False
1149 chandransh 673
 
1220 chandransh 674
def batch_orders(warehouseId):
675
    if not warehouseId:
676
        raise TransactionServiceException(101, "bad warehouse id")
1225 chandransh 677
 
678
    batchno_generator = BatchNoGenerator()
679
    session.commit()
1220 chandransh 680
    query = Order.query.filter_by(warehouse_id=warehouseId)
4381 mandeep.dh 681
    query = query.filter(or_(Order.status == OrderStatus.SUBMITTED_FOR_PROCESSING, Order.status == OrderStatus.INVENTORY_LOW))
1220 chandransh 682
    query = query.order_by(Order.created_timestamp)
683
    pending_orders = query.all()
1225 chandransh 684
 
1220 chandransh 685
    serial_no = 1
686
    for order in pending_orders:
1276 chandransh 687
        order.batchNo = batchno_generator.id
1220 chandransh 688
        order.serialNo = serial_no
689
        serial_no += 1
690
    session.commit() 
691
    pending_orders = query.all()
692
    return pending_orders
693
 
694
def order_outofstock(orderId):
1911 chandransh 695
    '''
696
    Mark order as out of stock
697
    '''
1220 chandransh 698
    order = get_order(orderId)
699
    order.status = OrderStatus.INVENTORY_LOW
700
    order.statusDescription = "Low Inventory"
701
    order.outofstock_timestamp = datetime.datetime.now()
702
    session.commit()
703
    return True
704
 
3064 chandransh 705
def mark_orders_as_manifested(warehouse_id, provider_id, cod):
759 chandransh 706
    try:
3064 chandransh 707
        orders = Order.query.filter_by(warehouse_id = warehouse_id, logistics_provider_id = provider_id, status = OrderStatus.BILLED, cod = cod).all()
759 chandransh 708
        for order in orders:
4410 rajveer 709
            order.status = OrderStatus.MANIFESTED
710
            order.statusDescription = "Order manifested"
711
        session.commit()
712
        return True
713
    except:
714
        return False
715
 
716
def mark_orders_as_shipped_from_warehouse(warehouse_id, provider_id, cod):
717
    try:
718
        current_timestamp = datetime.datetime.now()
719
        orders = Order.query.filter_by(warehouse_id = warehouse_id, logistics_provider_id = provider_id, status = OrderStatus.MANIFESTED, cod = cod).all()
720
        for order in orders:
759 chandransh 721
            order.status = OrderStatus.SHIPPED_FROM_WH
987 chandransh 722
            order.statusDescription = "Order shipped from warehouse"
986 chandransh 723
            order.shipping_timestamp = current_timestamp
759 chandransh 724
        session.commit()
725
        return True
726
    except:
727
        return False
4410 rajveer 728
 
1113 chandransh 729
def mark_orders_as_picked_up(provider_id, pickup_details):
730
    for awb, pickup_timestamp in pickup_details.iteritems():
1135 chandransh 731
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
2684 chandransh 732
        if order == None or order.status != OrderStatus.SHIPPED_FROM_WH:
2220 chandransh 733
            #raise TransactionServiceException(102, "No order found for the awb: " + awb)
734
            continue
1113 chandransh 735
        order.status = OrderStatus.SHIPPED_TO_LOGST
736
        order.statusDescription = "Order picked up by Courier Company"
1246 chandransh 737
        order.pickup_timestamp = pickup_timestamp
1113 chandransh 738
    session.commit()
1217 chandransh 739
 
1132 chandransh 740
    current_time = datetime.datetime.now()
741
    to_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
1246 chandransh 742
    from_datetime = to_datetime - datetime.timedelta(2)
1132 chandransh 743
    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()
1113 chandransh 744
    return orders_not_picked_up
745
 
1132 chandransh 746
def mark_orders_as_delivered(provider_id, delivered_orders):
747
    for awb, detail in delivered_orders.iteritems():
1135 chandransh 748
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
2684 chandransh 749
        if order == None or order.status not in [OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST]:
1911 chandransh 750
            continue
751
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
1132 chandransh 752
        order.status = OrderStatus.DELIVERY_SUCCESS
753
        order.statusDescription = "Order delivered"
754
        order.delivery_timestamp, order.receiver = detail.split('|')
3578 mandeep.dh 755
        update_trust_level(order)
1132 chandransh 756
    session.commit()
757
 
1135 chandransh 758
def mark_orders_as_failed(provider_id, returned_orders):
759
    for awb, detail in returned_orders.iteritems():
760
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
2684 chandransh 761
        if order == None or order.status not in [OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST]:
762
            continue
763
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
764
        order.status = OrderStatus.SALES_RETURN_IN_TRANSIT
1135 chandransh 765
        order.delivery_timestamp, reason = detail.split('|')
766
        order.statusDescription = "Order Returned to Origin:" + reason
3578 mandeep.dh 767
        update_trust_level(order)
1911 chandransh 768
    session.commit()
1135 chandransh 769
 
1246 chandransh 770
def update_non_delivery_reason(provider_id, undelivered_orders):
771
    for awb, reason in undelivered_orders.iteritems():
772
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
773
        if order == None:
2684 chandransh 774
            continue
775
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
1246 chandransh 776
        order.statusDescription = reason
777
    session.commit()
778
 
4394 rajveer 779
def get_alerts(type, status, timestamp):
780
    query = Alert.query.filter(Alert.type == type)
781
    query = query.filter(Alert.status == status)
782
    if timestamp:
783
        query = query.filter(Alert.timestamp >= to_py_date(timestamp))
4412 rajveer 784
    query = query.order_by(desc(Alert.timestamp))
483 rajveer 785
    return query.all()
786
 
4394 rajveer 787
def add_alert(type, description):
788
    alert = Alert()
789
    alert.type = type
790
    alert.status = 1
791
    alert.description = description
792
    alert.timestamp = datetime.datetime.now()
766 rajveer 793
    session.commit()    
794
 
1596 ankur.sing 795
def get_valid_order_count():
2851 chandransh 796
    '''
797
    Returns the number of orders which we processed. The reshipped orders are not
798
    counted since there'll always be a new compensating order present.
799
    '''
3216 chandransh 800
    return Order.query.filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING).filter(not_(Order.status.in_((OrderStatus.SALES_RET_RESHIPPED, OrderStatus.DOA_INVALID_RESHIPPED, OrderStatus.DOA_RESHIPPED, OrderStatus.CANCELED)))).count()
1596 ankur.sing 801
 
1627 ankur.sing 802
def get_cust_count_with_successful_txn():
2851 chandransh 803
    '''
804
    Returns the number of distinct customers who have done successful transactions.
805
    It uses the sqlalchemy func module to construct an efficient query.
806
    '''
807
    return session.query(func.count(distinct(Order.customer_id))).filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING).scalar()
1627 ankur.sing 808
 
1730 ankur.sing 809
def get_valid_orders_amount_range():
2851 chandransh 810
    '''
811
    Returns a list containing the minimum and maximum amount across all
812
    orders placed with us. No need to consider reshippped orders for min/max
813
    amount of orders.
814
    '''
815
    return session.query(func.min(Order.total_amount), func.max(Order.total_amount)).filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING).one()
1627 ankur.sing 816
 
1886 ankur.sing 817
def get_valid_orders(limit):
2851 chandransh 818
    '''
819
    Returns the last limit number of valid orders placed with us. Ignored the
820
    limit if it's passed as 0. Raises an excpetion if the supplied limit is 
821
    less than 0. 
822
    '''
823
    if limit < 0:
824
        raise TransactionServiceException(101, "Invalid argument limit " + limit)
3072 chandransh 825
    query = Order.query.filter(Order.status >= OrderStatus.INIT)
1886 ankur.sing 826
    query = query.order_by(desc(Order.created_timestamp))
2851 chandransh 827
    if limit != 0:
1886 ankur.sing 828
        query = query.limit(limit)
829
    return query.all()
830
 
2783 chandransh 831
def get_next_invoice_number():
832
    entity_id = InvoiceIDGenerator.query.with_lockmode("update").one()
833
    invoice_number = entity_id.id + 1
834
    entity_id.id = invoice_number
835
    return invoice_number
836
 
2536 chandransh 837
def toggle_doa_flag(order_id):
838
    order = get_order(order_id)
839
    if(order.doaFlag):
840
        order.doaFlag = False
841
    else:
842
        order.doaFlag = True
843
    session.commit()
844
    return order.doaFlag
845
 
846
def request_pickup_number(order_id):
847
    order = get_order(order_id)
848
    if order.status != OrderStatus.DELIVERY_SUCCESS and order.status != OrderStatus.DOA_PICKUP_REQUESTED:
849
        return False
850
    from_user = 'cnc.center@shop2020.in'
851
    from_pwd = '5h0p2o2o'
852
 
4227 rajveer 853
    subject = "Pickup request from " + order.customer_city
2536 chandransh 854
    try:
3133 rajveer 855
        catalog_client = CatalogClient().get_client()
2536 chandransh 856
        warehouse = catalog_client.getWarehouse(order.warehouse_id)
857
 
858
        logistics_client = LogisticsClient().get_client()
859
        provider = logistics_client.getProvider(order.logistics_provider_id)
3051 chandransh 860
        to_addr = provider.details[DeliveryType.PREPAID].email
2536 chandransh 861
        raw_message = '''
862
        Dear Sir/Madam,
863
 
2559 chandransh 864
        Kindly arrange a pickup today from %(customer_city)s. Pickup and delivery addresses are mentioned below.
2536 chandransh 865
 
866
        Pickup CODE: %(provider_code)s
867
        Total Weight: %(order_weight)s kg
868
 
2559 chandransh 869
        Pickup Address:
2536 chandransh 870
 
871
        %(customer_address)s
872
 
873
        Delivery Address:
874
 
875
        %(warehouse_executive)s
876
        %(warehouse_address)s
877
        PIN %(warehouse_pin)s
878
        Phone: %(warehouse_phone)s
879
 
880
        Thanks and Regards
4227 rajveer 881
        Sandeep Sachdeva
2536 chandransh 882
        '''
2559 chandransh 883
        message = dedent(raw_message) % { 'customer_city' : order.customer_city,
3051 chandransh 884
                                          'provider_code' : provider.details[DeliveryType.PREPAID].accountNo,
2536 chandransh 885
                                          'order_weight' : str(order.total_weight),
886
                                          'customer_address' : __get_order_address(order),
887
                                          'warehouse_executive' : 'Parmod Kumar',
888
                                          'warehouse_address' : warehouse.location,
889
                                          'warehouse_pin' : warehouse.pincode,
890
                                          'warehouse_phone': '9971573026'}
4227 rajveer 891
        #FIXME Email is hardcoded for bluedart
892
        mail(from_user, from_pwd, [to_addr, 'sonikap@bluedart.com'], subject, message)
2536 chandransh 893
        order.status = OrderStatus.DOA_PICKUP_REQUESTED
894
        order.statusDescription = "Pick up requested for DOA"
895
        session.commit()
896
        return True
897
    except Exception as e:
898
        print sys.exc_info()[0]
899
        return False
900
 
901
def authorize_pickup(order_id, pickup_number):
902
    order = get_order(order_id)
903
    if order.status != OrderStatus.DOA_PICKUP_REQUESTED:
904
        return False
905
    from_user = 'help@shop2020.in'
906
    from_pwd = '5h0p2o2o'
907
    subject = 'Pickup details'
908
    filename = "/tmp/" +  str(order.id) +".pdf" 
909
    try:
3133 rajveer 910
        catalog_client = CatalogClient().get_client()
2536 chandransh 911
        warehouse = catalog_client.getWarehouse(order.warehouse_id)
912
 
913
        logistics_client = LogisticsClient().get_client()
914
        provider = logistics_client.getProvider(order.logistics_provider_id)
915
        provider_name = provider.name
916
 
917
        to_addr = order.customer_email
918
        today = date.today().strftime("%d-%B-%Y (%A)")
919
 
920
        raw_message = '''
921
        Dear Mr. %(customer_name)s,
922
 
923
        In reference to the return of order ID %(order_id)d. We request you to kindly pack the box properly with bubble wrap, and send it along with the original "DOA" certificate and the invoice.
924
        Take a printout of the attachment in this mail which contains the delivery address and paste it on the packed parcel.
925
        We have instructed %(provider_name)s to pick up the material from the below mentioned address on %(date)s. %(provider_name)s pickup request number is %(pickup_request_no)s. Kindly keep the parcel ready.
926
 
927
        Pickup will happen from the below mentioned address:-
928
 
929
        %(customer_address)s
930
 
931
        Do let us know in case of any concerns
932
 
933
        Thanks & Regards
934
        Saholic Team
935
        '''
936
        message = dedent(raw_message) % {'customer_name' : order.customer_name,
937
                                         'order_id' : order_id,
938
                                         'provider_name' : provider_name,
939
                                         'date': today,
940
                                         'pickup_request_no' : pickup_number,
941
                                         'customer_address' : __get_order_address(order)}
942
        print message
943
        __generate_return_advice(order, warehouse, provider, filename)
3527 chandransh 944
        mail(from_user, from_pwd, [to_addr], subject, message, [get_attachment_part(filename)])
2536 chandransh 945
        order.pickupRequestNo = pickup_number
946
        order.status = OrderStatus.DOA_RETURN_AUTHORIZED
947
        order.statusDescription = "DOA pick up authorized"
2764 chandransh 948
        order.doa_auth_timestamp = datetime.datetime.now()
2536 chandransh 949
        session.commit()
950
        return True
951
    except Exception as e:
4234 rajveer 952
        print sys.exc_info()
953
	traceback.print_tb(sys.exc_info()[2])
2536 chandransh 954
        return False
955
    finally:
956
        if os.path.exists(filename):
957
            os.remove(filename)
958
 
2764 chandransh 959
def mark_doas_as_picked_up(provider_id, pickup_details):
960
    for pickupNo, doa_pickup_timestamp in pickup_details.iteritems():
961
        order = Order.query.filter_by(pickupRequestNo=pickupNo, logistics_provider_id = provider_id).first()
962
        if order == None or order.status != OrderStatus.DOA_RETURN_AUTHORIZED:
963
            #raise TransactionServiceException(102, "No order found for the awb: " + awb)
964
            continue
965
        order.status = OrderStatus.DOA_RETURN_IN_TRANSIT
966
        order.statusDescription = "DOA picked up by Courier Company"
967
        order.doa_pickup_timestamp = doa_pickup_timestamp
968
    session.commit()
969
 
970
    current_time = datetime.datetime.now()
971
    to_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
972
    from_datetime = to_datetime - datetime.timedelta(2)
973
    orders_not_picked_up = Order.query.filter_by(logistics_provider_id = provider_id).filter_by(status=OrderStatus.DOA_RETURN_AUTHORIZED).filter(Order.doa_auth_timestamp >= from_datetime).filter(Order.doa_auth_timestamp <= to_datetime).all()
974
    return orders_not_picked_up
975
 
2616 chandransh 976
def receive_return(order_id):
2591 chandransh 977
    order = get_order(order_id)
4365 mandeep.dh 978
 
979
    # FIXME: For Mahipal warehouse, we need to scan in items for every sales return
980
    if order.warehouse_id == 7:
981
        try:
982
            warehouse_client = WarehouseClient().get_client()
983
            lineitem = order.lineitems[0]
984
 
985
            # Inventory should not be updated for DOA returns 
986
            if order.status == OrderStatus.SALES_RETURN_IN_TRANSIT:
987
                warehouse_client.scanIn(order.id, lineitem.item_number, lineitem.imei_number, ScanType.SALE_RET)
988
                catalog_client = CatalogClient().get_client()
989
                catalog_client.reduceReservationCount(lineitem.item_id, order.warehouse_id, lineitem.quantity)
990
            elif order.status in [OrderStatus.DOA_RETURN_AUTHORIZED, OrderStatus.DOA_RETURN_IN_TRANSIT]:
991
                warehouse_client.scanIn(order.id, lineitem.item_number, lineitem.imei_number, ScanType.DOA_IN)
992
        except:
993
            print sys.exc_info()[0]
994
            print 'Could not scan in sales return orders'
995
 
2616 chandransh 996
    if order.status in [OrderStatus.DOA_RETURN_AUTHORIZED, OrderStatus.DOA_RETURN_IN_TRANSIT]:
997
        order.status = OrderStatus.DOA_RECEIVED
998
        order.statusDescription = "DOA package received"
2764 chandransh 999
        order.received_return_timestamp = datetime.datetime.now()
2616 chandransh 1000
        session.commit()
1001
    elif order.status == OrderStatus.SALES_RETURN_IN_TRANSIT :
1002
        order.status = OrderStatus.SALES_RET_RECEIVED
1003
        order.statusDescription = "Sales return received"
2764 chandransh 1004
        order.received_return_timestamp = datetime.datetime.now()
2616 chandransh 1005
        session.commit()
1006
    else:
2591 chandransh 1007
        return False
1008
    return True
1009
 
1010
def validate_doa(order_id, is_valid):
1011
    order = get_order(order_id)
2599 chandransh 1012
    if order.status != OrderStatus.DOA_RECEIVED:
2591 chandransh 1013
        return False
1014
    if is_valid:
2609 chandransh 1015
        order.status = OrderStatus.DOA_CERT_VALID
1016
        order.statusDescription = "DOA Certificate Valid"
2591 chandransh 1017
    else:
1018
        order.status = OrderStatus.DOA_CERT_INVALID
1019
        order.statusDescription = "DOA Certificate Invalid"
3578 mandeep.dh 1020
        update_trust_level(order)
2591 chandransh 1021
    session.commit()
1022
    return True
1023
 
2628 chandransh 1024
def reship_order(order_id):
1025
    """
1026
    If the order is in SALES_RET_RECEIVED or DOA_CERT_INVALID state, it does the following:
1027
        1. Creates a new order for processing in the BILLED state. All billing information is saved.
1028
        2. Marks the current order as one of the final states SALES_RET_RESHIPPED and DOA_INVALID_RESHIPPED depending on what state the order started in.
1029
 
1030
    If the order is in DOA_CERT_VALID state, it does the following:
1031
        1. Creates a new order for processing in the SUBMITTED_FOR_PROCESSING state.
1032
        2. Creates a return order for the warehouse executive to return the DOA material.
1033
        3. Marks the current order as the final DOA_RESHIPPED state.
1034
 
1035
    Returns the id of the newly created order.
1036
 
1037
    Throws an exception if the order with the given id couldn't be found.
1038
 
1039
    Parameters:
1040
     - orderId
1041
    """
1042
    order = get_order(order_id)
1043
    if order.status == OrderStatus.SALES_RET_RECEIVED:
4220 rajveer 1044
        new_order = __clone_order(order, True, order.cod)
2628 chandransh 1045
        order.status = OrderStatus.SALES_RET_RESHIPPED
1046
        order.statusDescription = "Order Reshipped"
1047
        session.commit()
3578 mandeep.dh 1048
        update_trust_level(order)
2628 chandransh 1049
    elif order.status == OrderStatus.DOA_CERT_INVALID:
4220 rajveer 1050
        new_order = __clone_order(order, True, False)
2628 chandransh 1051
        order.status = OrderStatus.DOA_INVALID_RESHIPPED
1052
        order.statusDescription = "Order Reshipped"
1053
        session.commit()
1054
    elif order.status == OrderStatus.DOA_CERT_VALID:
4220 rajveer 1055
        new_order = __clone_order(order, False, False)
2628 chandransh 1056
        ret_order = __create_return_order(order)
1057
        order.status = OrderStatus.DOA_RESHIPPED
1058
        order.statusDescription = "Order Reshipped"
1059
        session.commit()
1060
    else:
1061
        raise TransactionServiceException(112, "This order can't be reshipped")
1062
 
2764 chandransh 1063
    order.reship_timestamp = datetime.datetime.now()
2628 chandransh 1064
    order.new_order_id = new_order.id
1065
    session.commit()
1066
 
1067
    return new_order.id
1068
 
3226 chandransh 1069
def refund_order(order_id, refunded_by, reason):
2628 chandransh 1070
    """
1071
    If the order is in SALES_RET_RECEIVED, DOA_CERT_VALID or DOA_CERT_INVALID state, it does the following:
1072
        1. Creates a refund request for batch processing.
1073
        2. Creates a return order for the warehouse executive to return the shipped material.
1074
        3. Marks the current order as SALES_RET_REFUNDED, DOA_VALID_REFUNDED or DOA_INVALID_REFUNDED final states.
1075
 
1076
    If the order is in SUBMITTED_FOR_PROCESSING or INVENTORY_LOW state, it does the following:
1077
        1. Creates a refund request for batch processing.
3226 chandransh 1078
        2. Cancels the reservation of the item in the warehouse.
1079
        3. Marks the current order as the REFUNDED final state.
2628 chandransh 1080
 
3226 chandransh 1081
    For all COD orders, if the order is in INIT, SUBMITTED_FOR_PROCESSING or INVENTORY_LOW state, it does the following:
1082
        1. Cancels the reservation of the item in the warehouse.
1083
        2. Marks the current order as CANCELED.
1084
 
1085
    In all cases, it updates the reason for cancellation or refund and the person who performed the action.
1086
 
1087
    Returns True if it is successful, False otherwise.
2628 chandransh 1088
 
1089
    Throws an exception if the order with the given id couldn't be found.
1090
 
1091
    Parameters:
3226 chandransh 1092
     - order_id
1093
     - refunded_by
1094
     - reason
2628 chandransh 1095
    """
3414 chandransh 1096
    logging.info("Refunding order id: " + str(order_id))
2628 chandransh 1097
    order = get_order(order_id)
3186 chandransh 1098
 
1099
 
3366 chandransh 1100
 
3226 chandransh 1101
    if order.cod:
3414 chandransh 1102
        logging.info("Refunding COD order with status " + str(order.status))
3366 chandransh 1103
        status_transition = {OrderStatus.SALES_RET_RECEIVED : OrderStatus.SALES_RET_REFUNDED,
1104
                     OrderStatus.DOA_CERT_INVALID : OrderStatus.DOA_INVALID_REFUNDED,
1105
                     OrderStatus.DOA_CERT_VALID : OrderStatus.DOA_VALID_REFUNDED,
1106
                     OrderStatus.INIT : OrderStatus.CANCELED,
1107
                     OrderStatus.SUBMITTED_FOR_PROCESSING : OrderStatus.CANCELED,
1108
                     OrderStatus.INVENTORY_LOW : OrderStatus.CANCELED,
4306 rajveer 1109
                     OrderStatus.LOW_INV_PO_RAISED : OrderStatus.CANCELED,
1110
                     OrderStatus.LOW_INV_REVERSAL_IN_PROCESS : OrderStatus.CANCELED,
1111
                     OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT : OrderStatus.CANCELED,
3366 chandransh 1112
                     OrderStatus.ACCEPTED : OrderStatus.CANCELED,
4247 rajveer 1113
                     OrderStatus.BILLED : OrderStatus.CANCELED,
1114
                     OrderStatus.CANCEL_REQUEST_CONFIRMED : OrderStatus.CANCELLED_ON_CUSTOMER_REQUEST
3366 chandransh 1115
                     }
1116
        if order.status not in status_transition.keys():
1117
            raise TransactionServiceException(114, "This order can't be refunded")
1118
 
3413 chandransh 1119
        if order.status < OrderStatus.BILLED:
3226 chandransh 1120
            __update_inventory_reservation(order)
1121
            order.statusDescription = "Order Cancelled"
3415 chandransh 1122
        elif order.status == OrderStatus.BILLED:
3413 chandransh 1123
            __create_return_order(order)
1124
            order.statusDescription = "Order Cancelled"
4078 chandransh 1125
        elif order.status == OrderStatus.SALES_RET_RECEIVED:
3226 chandransh 1126
            __create_return_order(order)
4078 chandransh 1127
            order.statusDescription = "Order Returned to origin"
1128
        elif order.status in [OrderStatus.DOA_CERT_INVALID, OrderStatus.DOA_CERT_VALID] :
1129
            __create_return_order(order)
3226 chandransh 1130
            __create_refund(order)
1131
            order.statusDescription = "Order Refunded"
4247 rajveer 1132
        elif order.status == OrderStatus.CANCEL_REQUEST_CONFIRMED:
1133
            if order.previousStatus  < OrderStatus.BILLED:
1134
                __update_inventory_reservation(order)
1135
                order.statusDescription = "Order Cancelled on customer request"
1136
            elif order.previousStatus == OrderStatus.BILLED:
1137
                __create_return_order(order)
1138
                order.statusDescription = "Order Cancelled on customer request"
3226 chandransh 1139
    else:
3366 chandransh 1140
        status_transition = {OrderStatus.SALES_RET_RECEIVED : OrderStatus.SALES_RET_REFUNDED,
1141
                     OrderStatus.DOA_CERT_INVALID : OrderStatus.DOA_INVALID_REFUNDED,
1142
                     OrderStatus.DOA_CERT_VALID : OrderStatus.DOA_VALID_REFUNDED,
1143
                     OrderStatus.SUBMITTED_FOR_PROCESSING : OrderStatus.REFUNDED,
3731 chandransh 1144
                     OrderStatus.INVENTORY_LOW : OrderStatus.REFUNDED,
4306 rajveer 1145
                     OrderStatus.LOW_INV_PO_RAISED : OrderStatus.REFUNDED,
1146
                     OrderStatus.LOW_INV_REVERSAL_IN_PROCESS : OrderStatus.REFUNDED,
1147
                     OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT : OrderStatus.REFUNDED,
3731 chandransh 1148
                     OrderStatus.ACCEPTED : OrderStatus.REFUNDED,
4247 rajveer 1149
                     OrderStatus.BILLED : OrderStatus.REFUNDED,
1150
                     OrderStatus.CANCEL_REQUEST_CONFIRMED : OrderStatus.CANCELLED_ON_CUSTOMER_REQUEST,
1151
                     OrderStatus.PAYMENT_FLAGGED : OrderStatus.PAYMENT_FLAGGED_DENIED
3366 chandransh 1152
                     }
1153
        if order.status not in status_transition.keys():
1154
            raise TransactionServiceException(114, "This order can't be refunded")
1155
 
3226 chandransh 1156
        if order.status in [OrderStatus.SALES_RET_RECEIVED, OrderStatus.DOA_CERT_INVALID, OrderStatus.DOA_CERT_VALID] :
1157
            __create_return_order(order)
1158
            __create_refund(order)
1159
            order.statusDescription = "Order Refunded"
4306 rajveer 1160
        elif order.status in [OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW, OrderStatus.LOW_INV_PO_RAISED, OrderStatus.LOW_INV_REVERSAL_IN_PROCESS, OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT]:
3191 chandransh 1161
            __create_cancellation(order)
3226 chandransh 1162
            __update_inventory_reservation(order)
1163
            order.statusDescription = "Order Refunded"
4247 rajveer 1164
        elif order.status == OrderStatus.CANCEL_REQUEST_CONFIRMED:
1165
            if order.previousStatus  < OrderStatus.BILLED:
1166
                __create_refund(order)
1167
                __update_inventory_reservation(order)
1168
                order.statusDescription = "Order Cancelled on customer request"
1169
            elif order.previousStatus == OrderStatus.BILLED:
1170
                __create_return_order(order)
1171
                __create_refund(order)
1172
                order.statusDescription = "Order Cancelled on customer request"
1173
        elif order.status == OrderStatus.PAYMENT_FLAGGED:
1174
            __update_inventory_reservation(order)
1175
            order.statusDescription = "Order Cancelled due to payment flagged"
3195 chandransh 1176
 
1177
    order.status = status_transition[order.status]
1178
    order.refund_timestamp = datetime.datetime.now()
3226 chandransh 1179
    order.refunded_by = refunded_by
1180
    order.refund_reason = reason
2628 chandransh 1181
 
1182
    session.commit()
1183
    return True
1184
 
3186 chandransh 1185
def __update_inventory_reservation(order):
3191 chandransh 1186
    '''
1187
    Reduce the reservation count for all line items of the given order.
1188
    '''
3186 chandransh 1189
    try:
1190
        catalog_client = CatalogClient().get_client()
1191
        for lineitem in order.lineitems:
1192
            catalog_client.reduceReservationCount(lineitem.item_id, order.warehouse_id, lineitem.quantity);
1193
    except:
1194
        print "Unable to reduce reservation count"
1195
 
4220 rajveer 1196
def __clone_order(order, should_copy_billing_info, is_cod):
2628 chandransh 1197
    current_time = datetime.datetime.now()
1198
    new_order = Order()
1199
    new_order.customer_id = order.customer_id
1200
    new_order.customer_name = order.customer_name
1201
    new_order.customer_city = order.customer_city
1202
    new_order.customer_state = order.customer_state
1203
    new_order.customer_mobilenumber = order.customer_mobilenumber
1204
    new_order.customer_pincode = order.customer_pincode
1205
    new_order.customer_address1 = order.customer_address1
1206
    new_order.customer_address2 = order.customer_address2
1207
    new_order.customer_email = order.customer_email
1208
    new_order.total_amount = order.total_amount
1209
    new_order.total_weight = order.total_weight
1210
    new_order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
1211
    new_order.statusDescription = 'Submitted for Processing'
1212
    new_order.created_timestamp = current_time
1213
 
1214
    new_order.transaction = order.transaction
4220 rajveer 1215
    new_order.cod = is_cod
2628 chandransh 1216
 
1217
    for line_item in order.lineitems:
1218
        litem = LineItem()
1219
        litem.item_id = line_item.item_id
1220
        litem.productGroup = line_item.productGroup
1221
        litem.brand = line_item.brand
1222
        if line_item.model_number:
1223
            litem.model_number = line_item.model_number
1224
        if line_item.model_name:    
1225
            litem.model_name = line_item.model_name
1226
        if line_item.color:
1227
            litem.color = line_item.color
1228
        if line_item.extra_info:
1229
            litem.extra_info = line_item.extra_info
1230
        litem.quantity = line_item.quantity
1231
        litem.unit_price = line_item.unit_price
1232
        litem.unit_weight = line_item.unit_weight
1233
        litem.total_price = line_item.total_price
1234
        litem.total_weight = line_item.total_weight
1235
        litem.transfer_price = line_item.transfer_price
1236
        litem.order = new_order
1237
 
1238
    logistics_client = LogisticsClient().get_client()
1239
    item_id = new_order.lineitems[0].item_id
3239 chandransh 1240
    logistics_info = logistics_client.getLogisticsInfo(new_order.customer_pincode, item_id, DeliveryType.PREPAID) #TODO: We should be able to pass another flag to suggest ignoring the inventory situation.
2628 chandransh 1241
    logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
1242
 
1243
    new_order.warehouse_id = logistics_info.warehouseId
1244
    new_order.logistics_provider_id = logistics_info.providerId
1245
    new_order.airwaybill_no = logistics_info.airway_billno
1246
    new_order.tracking_id = new_order.airwaybill_no
1247
    new_order.expected_delivery_time = current_time + datetime.timedelta(days=logistics_info.deliveryTime)
3986 chandransh 1248
    new_order.promised_delivery_time = new_order.expected_delivery_time
4299 rajveer 1249
 
2628 chandransh 1250
    if should_copy_billing_info:
1251
        new_order.invoice_number = order.invoice_number
1252
        new_order.billed_by = order.billed_by
1253
        new_order.warehouse_id = order.warehouse_id
1254
        new_order.accepted_timestamp = current_time
1255
        new_order.billing_timestamp = current_time    
1256
        new_order.status = OrderStatus.BILLED
1257
        new_order.statusDescription = 'Order Billed'
1258
    else:       
3133 rajveer 1259
        catalog_client = CatalogClient().get_client()
2628 chandransh 1260
        catalog_client.reserveItemInWarehouse(item_id, logistics_info.warehouseId, new_order.lineitems[0].quantity)
1261
 
1262
    return new_order
1263
 
1264
def __create_return_order(order):
2687 chandransh 1265
    ret_order = ReturnOrder(order)
2628 chandransh 1266
    return ret_order
1267
 
1268
def __create_refund(order):
4078 chandransh 1269
    payment_client = PaymentClient().get_client()
1270
    payment_client.createRefund(order.id, order.transaction.id, order.total_amount)
2747 chandransh 1271
    return
2628 chandransh 1272
 
3035 chandransh 1273
def __create_cancellation(order):
1274
    return
1275
 
2536 chandransh 1276
def __get_order_address(order):
1277
    address = order.customer_name + "\n" + order.customer_address1 + "\n"
1278
    if order.customer_address2:
1279
        address = address + order.customer_address2 + "\n"
1280
    address = address + order.customer_city + "\n"
1281
    address = address + order.customer_state + "\n"
1282
    address = address + "PIN " + order.customer_pincode + "\n"
1283
    address = address + "Phone: " + order.customer_mobilenumber
1284
    return address
1285
 
1286
def __generate_return_advice(order, warehouse, provider, filename):    
1287
    pdf = Canvas(filename)
1288
    pdf.setFont('Times-Bold',16)
1289
    address_text = pdf.beginText(inch, PAGE_HEIGHT - inch)
1290
    address_text.textLine("To")
1291
    address_text.textLine("Parmod Kumar")
1292
    for line in warehouse.location.split("\n"):
1293
        address_text.textLine(line)
1294
    address_text.textLine("PIN " + warehouse.pincode)
1295
    address_text.textLine("")
1296
    address_text.textLine("Phone: 9971573026")
1297
    pdf.drawText(address_text)
1298
 
1299
    pdf.setFont('Times-Roman',12)
1300
    order_text = pdf.beginText(inch, PAGE_HEIGHT - 4 * inch)
3051 chandransh 1301
    order_text.textLine("Pickup CODE: " + provider.details[DeliveryType.PREPAID].accountNo)
2536 chandransh 1302
    lineitem = order.lineitems[0] 
4234 rajveer 1303
    order_text.textLine("Content : " + lineitem.brand + " " + str(lineitem.model_number) + " " + str(lineitem.color))
2536 chandransh 1304
    order_text.textLine("Declared Value: Rs. " + str(order.total_amount))
1305
    order_text.textLine("Order ID : " + str(order.id))
1306
    pdf.drawText(order_text)
1307
    pdf.showPage()
1308
    pdf.save()
1309
    return filename
1310
 
2697 chandransh 1311
def get_return_orders(warehouse_id, from_date, to_date):
1312
    query = ReturnOrder.query.filter_by(processedStatus = False)
1313
    if warehouse_id != -1:
1314
        query = query.filter_by(warehouseId = warehouse_id)
1315
    if from_date:
4118 chandransh 1316
        query = query.filter(ReturnOrder.createdAt >from_date)
2697 chandransh 1317
    if to_date:
4118 chandransh 1318
        query = query.filter(ReturnOrder.createdAt < to_date)
2697 chandransh 1319
    return [return_order.to_thrift_object() for return_order in query.all()]
1320
 
2700 chandransh 1321
def get_return_order(id):
1322
    ret_order = ReturnOrder.get_by(orderId = id)
1323
    if ret_order is None:
1324
        raise TransactionServiceException(116, "No return order found for the given order id")
1325
    return ret_order.to_thrift_object()
1326
 
2697 chandransh 1327
def process_return(ret_order_id):
1328
    ret_order = ReturnOrder.get_by(orderId = ret_order_id)
1329
    if ret_order is None:
1330
        raise TransactionServiceException(116, "No return order found for the given order id")
1331
    ret_order.processedStatus = True
2701 chandransh 1332
    ret_order.processedAt = datetime.datetime.now()
2697 chandransh 1333
    session.commit()
1334
 
2819 chandransh 1335
def create_purchase_order(warehouseId):
1336
    if not warehouseId:
1337
        raise TransactionServiceException(101, "bad warehouse id")
1338
 
3451 chandransh 1339
    query = Order.query.with_lockmode("update").filter_by(warehouse_id=warehouseId)
4380 mandeep.dh 1340
    query = query.filter(or_(Order.status == OrderStatus.SUBMITTED_FOR_PROCESSING, Order.status == OrderStatus.INVENTORY_LOW))
2819 chandransh 1341
    query = query.filter_by(purchase_order_id=None)
1342
    query = query.order_by(Order.created_timestamp)
1343
    pending_orders = query.all()
1344
 
1345
    if not pending_orders:
1346
        return -1
4434 mandeep.dh 1347
 
1348
    catalog_client = CatalogClient().get_client()
1349
    availability = {}
1350
    for item in catalog_client.getAllItemsForWarehouse(warehouseId):
1351
        availability[item.id] = item.itemInventory.availability[warehouseId]
1352
 
1353
    query = Order.query.with_lockmode("update").filter_by(warehouse_id=warehouseId)
1354
    query = query.filter(Order.status == OrderStatus.ACCEPTED)
1355
    accepted_orders = query.all()
1356
 
2819 chandransh 1357
    t_purchase_order = PurchaseOrder()
4365 mandeep.dh 1358
    t_purchase_order.supplierId = 3 # Putting supplier id as 3 for sarvottam for time being
2819 chandransh 1359
    t_purchase_order.warehouseId = warehouseId
1360
    t_purchase_order.lineitems = []
1361
 
4434 mandeep.dh 1362
    t_po_lineitems = []
2819 chandransh 1363
    lineitems = {}
4434 mandeep.dh 1364
 
1365
    # Considering all pending orders and accepted as well
1366
    accepted_orders.extend(pending_orders)
1367
    for order in accepted_orders:
2819 chandransh 1368
        for lineitem in order.lineitems:
1369
            item_id = lineitem.item_id
1370
            if lineitems.has_key(item_id):
4434 mandeep.dh 1371
                lineitems[item_id].quantity += lineitem.quantity
2819 chandransh 1372
            else:
1373
                t_po_lineitem = POLineItem()
1374
                t_po_lineitem.productGroup = lineitem.productGroup
1375
                t_po_lineitem.brand = lineitem.brand
1376
                t_po_lineitem.modelNumber = lineitem.model_number
1377
                t_po_lineitem.modelName = lineitem.model_name
1378
                t_po_lineitem.color = lineitem.color
1379
                t_po_lineitem.itemId = lineitem.item_id
4434 mandeep.dh 1380
                t_po_lineitem.quantity = lineitem.quantity - availability.get(item_id, 0)
2819 chandransh 1381
                lineitems[item_id] = t_po_lineitem
4434 mandeep.dh 1382
                t_po_lineitems.append(t_po_lineitem)
1383
                #FIXME vendor is hardcoded for sarvottam
4292 rajveer 1384
                item_pricing = catalog_client.getItemPricing(item_id, 3)
1385
                t_po_lineitem.unitPrice = item_pricing.transferPrice
4434 mandeep.dh 1386
 
1387
    for lineitem in t_po_lineitems:
1388
        if lineitem.quantity > 0:
1389
            t_purchase_order.lineitems.append(lineitem)
1390
 
1391
    if not t_purchase_order.lineitems:
1392
        return -1
1393
 
2819 chandransh 1394
    warehouse_client = WarehouseClient().get_client()
1395
    po_id = warehouse_client.createPurchaseOrder(t_purchase_order)
1396
 
1397
    for order in pending_orders:
1398
        order.purchase_order_id = po_id
4434 mandeep.dh 1399
        order.status = OrderStatus.LOW_INV_PO_RAISED
1400
        order.statusDescription = 'In Process'
2819 chandransh 1401
    session.commit()
1402
    return po_id
1403
 
3451 chandransh 1404
def update_weight(order_id, weight):
3469 chandransh 1405
    '''
1406
    Update the weight of order
1407
    '''
3451 chandransh 1408
    order = get_order(order_id)
1409
    order.total_weight = weight
3469 chandransh 1410
    lineitem = order.lineitems[0]
1411
    lineitem.total_weight = weight
1412
    lineitem.unit_weight = weight
3451 chandransh 1413
 
3469 chandransh 1414
    session.commit()
1415
    return order
1416
 
1417
def change_product(order_id, item_id):
1418
    '''
1419
    Ship a product of a different color to the customer.
1420
    '''
1421
    order = get_order(order_id)
4306 rajveer 1422
    if order.status not in [OrderStatus.INIT, OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW, OrderStatus.LOW_INV_PO_RAISED, OrderStatus.LOW_INV_REVERSAL_IN_PROCESS, OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT]:
3469 chandransh 1423
        raise TransactionServiceException(120, "This order has already been processed. Please seek help from engineering.")
1424
 
1425
    lineitem = order.lineitems[0]
3451 chandransh 1426
 
3469 chandransh 1427
    catalog_client = CatalogClient().get_client()
1428
 
1429
    old_item = catalog_client.getItem(lineitem.item_id)
1430
    item = catalog_client.getItem(item_id)
1431
    if old_item.catalogItemId != item.catalogItemId:
1432
        raise TransactionServiceException(121, "You can't ship a different item. You can only ship the same item in a different color.")
1433
 
1434
    catalog_client.reserveItemInWarehouse(item_id, order.warehouse_id, lineitem.quantity)
1435
    catalog_client.reduceReservationCount(lineitem.item_id, order.warehouse_id, lineitem.quantity)
1436
    #TODO: Check that this new item has the same price
1437
 
1438
    lineitem.item_id = item_id
1439
    lineitem.color = item.color
1440
 
3451 chandransh 1441
    session.commit()
3469 chandransh 1442
 
1443
    order = get_order(order_id)
3451 chandransh 1444
    return order
3469 chandransh 1445
 
1446
def change_warehouse(order_id, warehouse_id):
1447
    '''
1448
    Update the warehouse which will be used to fulfil this order.
1449
    '''
1450
    order = get_order(order_id)
4306 rajveer 1451
    if order.status not in [OrderStatus.INIT, OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW, OrderStatus.LOW_INV_PO_RAISED, OrderStatus.LOW_INV_REVERSAL_IN_PROCESS, OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT]:
3469 chandransh 1452
        raise TransactionServiceException(117, "This order has already been processed. Please seek help from engineering.")
1453
 
1454
    if warehouse_id == order.warehouse_id:
1455
        raise TransactionServiceException(118, "You have selected the current warehouse again. Nothing to do")
1456
 
1457
    lineitem = order.lineitems[0]
1458
    catalog_client = CatalogClient().get_client()
1459
    try:
1460
        warehouse = catalog_client.getWarehouse(warehouse_id)
1461
    except:
1462
        raise TransactionServiceException(119, "No warehouse with id" + str(warehouse_id))
1463
 
1464
    catalog_client.reserveItemInWarehouse(lineitem.item_id, warehouse_id, lineitem.quantity)
1465
    catalog_client.reduceReservationCount(lineitem.item_id, order.warehouse_id, lineitem.quantity)
3451 chandransh 1466
 
3469 chandransh 1467
    order.warehouse_id = warehouse_id
1468
    session.commit()
1469
    return order
3553 chandransh 1470
 
3986 chandransh 1471
def add_delay_reason(order_id, reason, further_delay=0):
3553 chandransh 1472
    '''
3994 chandransh 1473
    Adds a delay reason to the order and updates the expected delivery time.
3553 chandransh 1474
    '''
1475
    order = get_order(order_id)
1476
    try:
3581 chandransh 1477
        order.delay_reason = DelayReason._VALUES_TO_NAMES[reason]
4009 chandransh 1478
        actual_delivery_delay = adjust_delivery_time(order.expected_delivery_time, further_delay)
1479
        order.expected_delivery_time = order.expected_delivery_time + datetime.timedelta(days=actual_delivery_delay)
4102 chandransh 1480
 
1481
        if order.status < OrderStatus.SHIPPED_FROM_WH:
1482
            actual_shipping_delay = adjust_delivery_time(order.expected_shipping_time, further_delay)
1483
            order.expected_shipping_time = order.expected_shipping_time + datetime.timedelta(days=actual_shipping_delay)
1484
 
3553 chandransh 1485
        session.commit()
4008 mandeep.dh 1486
 
1487
        try:
1488
            transaction_requiring_extra_processing = TransactionRequiringExtraProcessing()
1489
            transaction_requiring_extra_processing.category = 'DELAYED_DELIVERY'
1490
            transaction_requiring_extra_processing.transaction_id = order.transaction_id
1491
            session.commit()
1492
        except Exception as e:
4065 mandeep.dh 1493
            print 'Could not persist transaction id: ' + str(order.transaction_id) + ' for further processing due to: ' + str(e)
4008 mandeep.dh 1494
 
3553 chandransh 1495
        return True
1496
    except:
3994 chandransh 1497
        print sys.exc_info()[0]
3553 chandransh 1498
        return False
3956 chandransh 1499
 
1500
def reconcile_cod_collection(collected_amount_map, xferBy, xferTxnId, xferDate):
1501
    unprocessed_awbs = {}
1502
    for awb, amount in collected_amount_map.iteritems():
1503
        try:
1504
            order = Order.query.filter_by(airwaybill_no=awb).one()
1505
        except NoResultFound:
1506
            unprocessed_awbs[awb] = "No order was found for the given AWB: " + awb
1507
            continue
1508
        except MultipleResultsFound:
1509
            unprocessed_awbs[awb] = "Multiple orders were found for the given AWB:" + awb
1510
            continue
1511
 
1512
        if order.cod_reconciliation_timestamp:
1513
            #This order has been processed already! This may be a re-run. Let's allow other orders to be processed.
1514
            continue
1515
 
1516
        if order.status < OrderStatus.DELIVERY_SUCCESS:
1517
            #Order has not been delivered yet. No way we can receive the payment.
1518
            unprocessed_awbs[awb] = "Payment has been received for order: " + str(order.id) + " before delivery reconciliation"
1519
            continue
1520
 
4252 rajveer 1521
        ##As per ticket #743 if amount difference less than 0.5 we should reconcile
1522
        if abs(amount - order.total_amount) > 0.5:
3956 chandransh 1523
            #Received amount is less than or more than the order amount. Mustn't let the user proceed.
1524
            unprocessed_awbs[awb] = "Payment of Rs. " + str(amount) + " has been received against the total value of Rs. " + str(order.total_amount) + " for order: " + str(order.id)
1525
            continue
1526
 
1527
        try:
1528
            payment_client = PaymentClient().get_client()
1529
            payment_client.partiallyCapturePayment(order.transaction.id, amount, xferBy, xferTxnId, xferDate)
1530
        except Exception:
1531
            unprocessed_awbs[awb] = "We were unable to partially capture payment for order id " + str(order.id) + ", AWB: " + awb
1532
            continue
1533
 
1534
        #Payment has been recorded now. We can update the order peacefully.
1535
        order.cod_reconciliation_timestamp = datetime.datetime.now()
1536
        session.commit()
3469 chandransh 1537
 
3956 chandransh 1538
    return unprocessed_awbs
4008 mandeep.dh 1539
 
1540
def get_transactions_requiring_extra_processing(category):
4065 mandeep.dh 1541
    """
1542
    Returns the list of transaction ids that require some extra processing and
1543
    which belong to a particular category. This is currently used by CRM
1544
    application. If no such transaction ids are present, it returns an empty list.
1545
    """
1546
    query = TransactionRequiringExtraProcessing.query
4008 mandeep.dh 1547
 
4065 mandeep.dh 1548
    if category is not None:
1549
        query = query.filter_by(category = ExtraTransactionProcessingType._VALUES_TO_NAMES.get(category))
4008 mandeep.dh 1550
 
4065 mandeep.dh 1551
    return [a.transaction_id for a in query.all()]
4008 mandeep.dh 1552
 
1553
def mark_transaction_as_processed(transactionId, category):
4065 mandeep.dh 1554
    """
1555
    Marks a particular transaction as processed for a particular cateogory.
1556
    It essentially deletes the transaction id record for a particular
1557
    processing type category (if present) from DB.
1558
    This is currently used by CRM application.
1559
    """
4008 mandeep.dh 1560
    TransactionRequiringExtraProcessing.query.filter_by(transaction_id = transactionId).filter_by(category = ExtraTransactionProcessingType._VALUES_TO_NAMES.get(category)).delete()
1561
    session.commit()
1562
 
4018 chandransh 1563
def get_item_wise_risky_orders_count():
1564
    """
1565
    Returns a map containing the number of risky orders keyed by item id. A risky order
1566
    is defined as one whose shipping date is about to expire.
1567
    """
1568
    item_wise_risky_orders_count = {}
4019 chandransh 1569
    shipping_cutoff_time = (datetime.datetime.now() + datetime.timedelta(days = 1)).replace(hour=PREPAID_SHIPPING_CUTOFF_TIME, minute=0, second=0)
4018 chandransh 1570
    orders = Order.query.filter(Order.status.in_(tuple([OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW, OrderStatus.ACCEPTED]))).filter(Order.expected_shipping_time <= shipping_cutoff_time).all()
1571
    for order in orders:
1572
        for lineitem in order.lineitems:
1573
            quantity = lineitem.quantity
1574
            if item_wise_risky_orders_count.has_key(lineitem.item_id):
1575
                quantity = quantity + item_wise_risky_orders_count[lineitem.item_id]
1576
 
1577
            item_wise_risky_orders_count[lineitem.item_id] = quantity
1578
    return item_wise_risky_orders_count
1579
 
4324 mandeep.dh 1580
def update_shipment_address(order_id, address_id):
1581
    """
1582
    Updates shipment address of an order. Delivery and shipping date estimates
1583
    etc. are also updated here.
1584
 
1585
    Throws TransactionServiceException in case address change is not
1586
    possible due to certain reasons such as new pincode in address is
1587
    not serviceable etc.
1588
 
1589
    Parameters:
1590
     - orderId
1591
     - addressId
1592
    """
1593
    user_client = UserClient().get_client()
1594
    address     = user_client.getAddressById(address_id)
1595
    order       = get_order(order_id)
1596
 
1597
    logistics_client = LogisticsClient().get_client()
1598
    logistics_info = logistics_client.getLogisticsEstimation(order.lineitems[0].item_id, address.pin)
1599
 
1600
    # Check for new estimate. Raise exception if new address is not serviceable
1601
    if logistics_info.deliveryTime == -1:
1602
        raise TransactionServiceException(1, 'Location not serviceable')
1603
 
1604
    # COD services are not available everywhere
1605
    if order.cod:
1606
        if not logistics_client.isCodAllowed(address.pin):
1607
            raise TransactionServiceException(2, 'COD service not available')
1608
 
1609
    current_time = datetime.datetime.now()
1610
    logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
1611
    logistics_info.shippingTime = adjust_delivery_time(current_time, logistics_info.shippingTime)
1612
 
1613
    order.customer_name         = address.name
1614
    order.customer_pincode      = address.pin
1615
    order.customer_address1     = address.line1
1616
    order.customer_address2     = address.line2
1617
    order.customer_city         = address.city
1618
    order.customer_state        = address.state
1619
    order.customer_mobilenumber = address.phone
1620
 
1621
    if order.cod:
1622
        order.expected_shipping_time = (current_time + datetime.timedelta(days=logistics_info.shippingTime)).replace(hour=COD_SHIPPING_CUTOFF_TIME, minute=0, second=0)
1623
    else:
1624
        order.expected_shipping_time = (current_time + datetime.timedelta(days=logistics_info.shippingTime)).replace(hour=PREPAID_SHIPPING_CUTOFF_TIME, minute=0, second=0)
1625
 
1626
    order.expected_delivery_time = current_time + datetime.timedelta(days=logistics_info.deliveryTime)
1627
    order.promised_shipping_time = order.expected_shipping_time
1628
    order.promised_delivery_time = order.expected_delivery_time 
1629
 
1630
    session.commit()
1631
 
4247 rajveer 1632
def mark_order_cancellation_request_received(orderId):
1633
    """
1634
    Mark order as cancellation request received. If customer sends request of cancellation of
1635
    a particular order, this method will be called. It will just change status of the order
1636
    depending on its current status. It also records the previous status, so that we can move
1637
    back to that status if cancellation request is denied.
1638
 
1639
    Parameters:
1640
     - orderId
1641
    """
1642
    status_transition = {OrderStatus.INIT : OrderStatus.CANCEL_REQUEST_RECEIVED,
1643
             OrderStatus.SUBMITTED_FOR_PROCESSING : OrderStatus.CANCEL_REQUEST_RECEIVED,
1644
             OrderStatus.INVENTORY_LOW : OrderStatus.CANCEL_REQUEST_RECEIVED,
4306 rajveer 1645
             OrderStatus.LOW_INV_PO_RAISED : OrderStatus.CANCEL_REQUEST_RECEIVED,
1646
             OrderStatus.LOW_INV_REVERSAL_IN_PROCESS : OrderStatus.CANCEL_REQUEST_RECEIVED,
1647
             OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT : OrderStatus.CANCEL_REQUEST_RECEIVED,
4247 rajveer 1648
             OrderStatus.ACCEPTED : OrderStatus.CANCEL_REQUEST_RECEIVED,
1649
             OrderStatus.BILLED : OrderStatus.CANCEL_REQUEST_RECEIVED,
1650
             OrderStatus.PAYMENT_FLAGGED : OrderStatus.CANCEL_REQUEST_RECEIVED
1651
             }
1652
    if order.status not in status_transition.keys():
1653
        raise TransactionServiceException(114, "This order can't be considered for cancellation")
1654
 
1655
    order = get_order(orderId)
1656
    order.previousStatus = order.status
1657
    order.status = OrderStatus.CANCEL_REQUEST_RECEIVED
1658
    order.statusDescription = "Cancellation request received from user"
1659
    session.commit()
1660
 
4258 rajveer 1661
def mark_transaction_as_payment_flag_removed(transactionId):
4247 rajveer 1662
    """
4258 rajveer 1663
    If we and/or payment gateway has decided to accept the payment, this method needs to be called.
1664
    Changed transaction and all orders status to payment accepted.
4247 rajveer 1665
 
1666
    Parameters:
4258 rajveer 1667
     - transactionId
4247 rajveer 1668
    """
4258 rajveer 1669
    transaction = get_transaction(transactionId)
1670
    transaction.status = TransactionStatus.AUTHORIZED
1671
    for order in transaction.orders:
1672
        order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
1673
        order.statusDescription = "Submitted to warehouse"
4247 rajveer 1674
    session.commit()
1675
 
4259 anupam.sin 1676
def refund_transaction(transactionId, refundedBy, reason):
1677
    """
1678
    This method is called when a flagged payment is deemed unserviceable and the corresponding orders
1679
    need to be cancelled
1680
 
1681
    Parameters:
1682
     - transactionId
1683
    """
1684
    transaction = get_transaction(transactionId)
1685
    transaction.status = TransactionStatus.FAILED
1686
    for order in transaction.orders:
1687
        refund_order(order.id, refundedBy, reason)
1688
    session.commit()
1689
 
4247 rajveer 1690
def mark_order_cancellation_request_denied(orderId):
1691
    """
4283 anupam.sin 1692
    If we decide to not to cancel order, we will move the order to previous status.
4247 rajveer 1693
 
1694
    Parameters:
1695
     - orderId
1696
    """
1697
    order = get_order(orderId)
1698
    order.status = order.previousStatus
1699
    order.previousStatus = None
1700
    order.statusDescription = "Cancellation request denied"
1701
    session.commit()
1702
 
1703
def mark_order_cancellation_request_confirmed(orderId):
1704
    """
1705
    If we decide to to cancel order, CRM will call this method to move the status of order to
1706
    cancellation request confirmed. After this OM will be able to cancel the order.
1707
 
1708
    Parameters:
1709
     - orderId
1710
    """
1711
    order = get_order(orderId)
1712
    order.status = OrderStatus.CANCEL_REQUEST_CONFIRMED
1713
    order.statusDescription = "Cancellation request confirmed"
1714
    session.commit()
1715
 
4285 rajveer 1716
def accept_orders_for_item_id(itemId, inventory):
1717
    """
1718
    Marks the orders as ACCEPTED for the given itemId and inventory. It also updates the accepted timestamp. If the
1719
    given order is not a COD order, it also captures the payment if the same has not been captured.
1720
 
1721
    Parameters:
1722
     - itemId
1723
     - inventory
1724
    """
4351 rajveer 1725
    orders = Order.query.filter(Order.status.in_(tuple([OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW, OrderStatus.LOW_INV_PO_RAISED, OrderStatus.LOW_INV_REVERSAL_IN_PROCESS]))).order_by(Order.expected_shipping_time).all()
4285 rajveer 1726
    for order in orders:
4301 rajveer 1727
        if inventory > 0:
1728
            lineitem = order.lineitems[0]
1729
            if itemId == lineitem.item_id:
1730
                try:
1731
                    accept_order(order.id)
1732
                    inventory = inventory - lineitem.quantity
1733
                except:
1734
                    logging.info("Unable to accept the order")
1735
        else:
1736
            order_outofstock(order.id)
4285 rajveer 1737
    return
1738
 
4369 rajveer 1739
def mark_orders_as_po_raised(vendorId, itemId, quantity, estimate, isReminder):
1740
    if isReminder:
1741
        statuses = tuple([OrderStatus.LOW_INV_PO_RAISED_TIMEOUT, OrderStatus.LOW_INV_REVERSAL_TIMEOUT])
1742
    else:
1743
        statuses = tuple([OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW])
1744
 
1745
    orders = Order.query.filter(Order.status.in_(statuses)).order_by(Order.expected_shipping_time).all()
4303 rajveer 1746
    for order in orders:
1747
        lineitem = order.lineitems[0]
1748
        if quantity >= lineitem.quantity and itemId == lineitem.item_id:
1749
            if estimate > 0:
1750
                add_delay_reason(order.id, DelayReason.OTHERS, estimate)
1751
            order.status = OrderStatus.LOW_INV_PO_RAISED
4362 rajveer 1752
            order.statusDescription = "PO Raised"
4303 rajveer 1753
            quantity = quantity - lineitem.quantity
1754
            store_inventory_action(order, itemId, HotspotAction.PO_RAISED, estimate, lineitem.quantity)
1755
            session.commit()
1756
 
4369 rajveer 1757
def mark_orders_as_reversal_initiated(vendorId, itemId, quantity, estimate, isReminder):
1758
    if isReminder:
1759
        statuses = tuple([OrderStatus.LOW_INV_PO_RAISED_TIMEOUT, OrderStatus.LOW_INV_REVERSAL_TIMEOUT])
1760
    else:
1761
        statuses = tuple([OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW])
1762
    orders = Order.query.filter(Order.status.in_(statuses)).order_by(Order.expected_shipping_time).all()
4303 rajveer 1763
    for order in orders:
1764
        lineitem = order.lineitems[0]
1765
        if quantity >= lineitem.quantity and itemId == lineitem.item_id:
1766
            if estimate > 0:
1767
                add_delay_reason(order.id, DelayReason.OTHERS, estimate)
1768
            order.status = OrderStatus.LOW_INV_REVERSAL_IN_PROCESS
4362 rajveer 1769
            order.statusDescription = "Reversal Initiated"
4303 rajveer 1770
            quantity = quantity - lineitem.quantity
1771
            store_inventory_action(order, itemId, HotspotAction.REVERSAL_INITIATED, estimate, lineitem.quantity)
1772
            session.commit()
1773
 
4369 rajveer 1774
def mark_orders_as_not_available(vendorId, itemId, quantity, estimate, isReminder):
1775
    if isReminder:
1776
        statuses = tuple([OrderStatus.LOW_INV_PO_RAISED_TIMEOUT, OrderStatus.LOW_INV_REVERSAL_TIMEOUT])
1777
    else:
1778
        statuses = tuple([OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW])
1779
 
1780
    orders = Order.query.filter(Order.status.in_(statuses)).order_by(Order.expected_shipping_time).all()
4303 rajveer 1781
    for order in orders:
1782
        lineitem = order.lineitems[0]
1783
        if quantity >= lineitem.quantity and itemId == lineitem.item_id:
1784
            order.status = OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT
4362 rajveer 1785
            order.statusDescription = "Not Available"
4303 rajveer 1786
            quantity = quantity - lineitem.quantity
1787
            store_inventory_action(order, itemId, HotspotAction.NOT_AVAILABLE, estimate, lineitem.quantity)
1788
            session.commit()
1789
 
1790
def store_inventory_action(order, itemId, hotspotAction, estimate, quantity):
4369 rajveer 1791
    orderInv = OrderInventory.get_by(order_id=order.id)
1792
    if not orderInv:
1793
        orderInv = OrderInventory()
1794
        orderInv.order = order
4303 rajveer 1795
    orderInv.hotspotAction = hotspotAction  
1796
    orderInv.estimate = estimate
1797
    orderInv.itemId = itemId
1798
    orderInv.timestamp = datetime.datetime.now()
1799
    orderInv.quantity = quantity
1800
 
4369 rajveer 1801
 
1802
def mark_orders_as_timeout(vendorId):
1803
    ret_timeouts = {}
1804
    orderInvs = OrderInventory.query.all()
1805
    for orderInv in orderInvs:
1806
        if orderInv.timestamp +  timedelta(days=orderInv.estimate) < datetime.datetime.now():
1807
            if not ret_timeouts.has_key(orderInv.itemId):
1808
                timeout = TimeoutSummary()
1809
                ret_timeouts[orderInv.itemId] = timeout
1810
            else:
1811
                timeout = ret_timeouts.get(orderInv.itemId)
1812
            if orderInv.hotspotAction == HotspotAction.PO_RAISED and orderInv.order.status == OrderStatus.LOW_INV_PO_RAISED:
1813
                if timeout.poRaised:
1814
                    timeout.poRaised += 1
1815
                else:
1816
                    timeout.poRaised = 1
1817
 
1818
                if timeout.poEstimate:
1819
                    timeout.poEstimate += orderInv.estimate
1820
                else:
1821
                    timeout.poEstimate = orderInv.estimate
1822
                orderInv.order.status = OrderStatus.LOW_INV_PO_RAISED_TIMEOUT
1823
                orderInv.order.statusDescription = "PO Raised Timeout"
1824
            elif orderInv.hotspotAction == HotspotAction.REVERSAL_INITIATED and orderInv.order.status == OrderStatus.LOW_INV_REVERSAL_IN_PROCESS:
1825
                if timeout.reversalInitiated:
1826
                    timeout.reversalInitiated += 1
1827
                else:
1828
                    timeout.reversalInitiated = 1
1829
 
1830
                if timeout.reversalEstimate:
1831
                    timeout.reversalEstimate += orderInv.estimate
1832
                else:
1833
                    timeout.reversalEstimate = orderInv.estimate
1834
                orderInv.order.status = OrderStatus.LOW_INV_REVERSAL_TIMEOUT
1835
                orderInv.order.statusDescription = "Reversal Initiated Timeout"
1836
            else:
1837
                orderInv.delete()
1838
    session.commit()
1839
    return ret_timeouts
1840
 
4386 anupam.sin 1841
def get_order_for_awb(awb):
1842
    order = Order.get_by(airwaybill_no=awb)
1843
    if not order:
1844
        raise TransactionServiceException(108, "no such order")
1845
 
1846
    return order
4369 rajveer 1847
 
4386 anupam.sin 1848
 
766 rajveer 1849
def close_session():
1850
    if session.is_active:
1851
        print "session is active. closing it."
2783 chandransh 1852
        session.close()
3376 rajveer 1853
 
1854
def is_alive():
1855
    try:
1856
        session.query(Transaction.id).limit(1).one()
1857
        return True
1858
    except:
4343 varun.gupt 1859
        return False