Subversion Repositories SmartDukaan

Rev

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