Subversion Repositories SmartDukaan

Rev

Rev 4118 | Rev 4172 | 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
 
7
from datetime import date
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, \
22
    TransactionRequiringExtraProcessing
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, \
28
    ExtraTransactionProcessingType
3499 mandeep.dh 29
from shop2020.thriftpy.warehouse.ttypes import PurchaseOrder, \
30
    LineItem as POLineItem
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
41
import sys
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
1262 varun.gupt 142
            litem.transfer_price = line_item.transfer_price
1976 varun.gupt 143
 
483 rajveer 144
            """
145
            if line_item.addedOn:
146
                litem.added_on = to_py_date(line_item.addedOn)
147
            else:
148
                litem.added_on = datetime.datetime.now()
149
            """
150
            litem.order = order
151
    session.commit()
152
    return transaction.id
153
 
154
def get_transaction(transaction_id):
155
    transaction = Transaction.get_by(id=transaction_id)
156
    if not transaction:
157
        raise TransactionServiceException(108, "no such transaction")
158
 
159
    return transaction
160
 
161
def get_transactions_for_customer(customer_id, from_date, to_date, status):
162
    if not customer_id:
163
        raise TransactionServiceException(101, "bad customer id")
164
    query = Transaction.query.filter(Transaction.customer_id == customer_id)
1493 vikas 165
    if status is not None:
483 rajveer 166
        query = query.filter(Transaction.status == status)
167
    if from_date:
168
        query = query.filter(Transaction.createdOn >from_date)
169
    if to_date:
170
        query = query.filter(Transaction.createdOn < to_date)
171
    return query.all()
172
 
173
def get_transactions_for_shopping_cart_id(shopping_cart_id):
174
    transactions = Transaction.query.filter_by(shopping_cart_id=shopping_cart_id).all()
175
    return transactions
176
 
177
def get_transaction_status(transaction_id):
178
    if not transaction_id:
179
        raise TransactionServiceException(101, "bad transaction id")
180
 
181
    transaction = get_transaction(transaction_id)
182
 
183
    return transaction.status
184
 
185
def change_transaction_status(transaction_id, new_status, description):
186
    transaction = get_transaction(transaction_id)
187
    transaction.status = new_status
188
    transaction.status_message = description
690 chandransh 189
    if new_status == TransactionStatus.FAILED:
190
        for order in transaction.orders:
191
            order.status = OrderStatus.PAYMENT_FAILED
2339 chandransh 192
            order.statusDescription = "Payment Failed"
3010 chandransh 193
    elif new_status == TransactionStatus.AUTHORIZED:
690 chandransh 194
        for order in transaction.orders:
195
            order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
1219 chandransh 196
            order.statusDescription = "Submitted to warehouse"
3092 chandransh 197
            order.cod = False
743 rajveer 198
            #After we got payment success, we will set logistics info also 
199
            logistics_client = LogisticsClient().get_client()
200
            #FIXME line item is only one now. If multiple will come, need to fix.
871 chandransh 201
            item_id = order.lineitems[0].item_id
3044 chandransh 202
            logistics_info = logistics_client.getLogisticsInfo(order.customer_pincode, item_id, DeliveryType.PREPAID)
743 rajveer 203
 
1730 ankur.sing 204
            current_time = datetime.datetime.now()
205
            logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
4009 chandransh 206
            logistics_info.shippingTime = adjust_delivery_time(current_time, logistics_info.shippingTime)
1730 ankur.sing 207
 
743 rajveer 208
            order.warehouse_id = logistics_info.warehouseId
209
            order.logistics_provider_id = logistics_info.providerId
210
            order.airwaybill_no = logistics_info.airway_billno
211
            order.tracking_id = order.airwaybill_no
4019 chandransh 212
            order.expected_shipping_time = (current_time + datetime.timedelta(days=logistics_info.shippingTime)).replace(hour=PREPAID_SHIPPING_CUTOFF_TIME, minute=0, second=0)
4102 chandransh 213
            order.promised_shipping_time = order.expected_shipping_time
1730 ankur.sing 214
            order.expected_delivery_time = current_time + datetime.timedelta(days=logistics_info.deliveryTime)
3986 chandransh 215
            order.promised_delivery_time = order.expected_delivery_time 
871 chandransh 216
 
3133 rajveer 217
            catalog_client = CatalogClient().get_client()
871 chandransh 218
            catalog_client.reserveItemInWarehouse(item_id, logistics_info.warehouseId, order.lineitems[0].quantity)
1351 varun.gupt 219
 
1341 chandransh 220
            item_pricing = catalog_client.getItemPricing(item_id, order.warehouse_id)
221
            order.lineitems[0].transfer_price = item_pricing.transferPrice
3064 chandransh 222
    elif new_status == TransactionStatus.COD_IN_PROCESS:
223
        for order in transaction.orders:
224
            order.status = OrderStatus.INIT
225
            order.statusDescription = "Verification Pending"
226
            order.cod = True
227
            #After we got payment success, we will set logistics info also 
228
            logistics_client = LogisticsClient().get_client()
229
            #FIXME line item is only one now. If multiple will come, need to fix.
230
            item_id = order.lineitems[0].item_id
231
            logistics_info = logistics_client.getLogisticsInfo(order.customer_pincode, item_id, DeliveryType.COD)
232
 
233
            current_time = datetime.datetime.now()
234
            logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
4009 chandransh 235
            logistics_info.shippingTime = adjust_delivery_time(current_time, logistics_info.shippingTime)
3064 chandransh 236
 
237
            order.warehouse_id = logistics_info.warehouseId
238
            order.logistics_provider_id = logistics_info.providerId
239
            order.airwaybill_no = logistics_info.airway_billno
240
            order.tracking_id = order.airwaybill_no
4019 chandransh 241
            order.expected_shipping_time = (current_time + datetime.timedelta(days=logistics_info.shippingTime)).replace(hour=COD_SHIPPING_CUTOFF_TIME, minute=0, second=0)
4102 chandransh 242
            order.promised_shipping_time = order.expected_shipping_time
3064 chandransh 243
            order.expected_delivery_time = current_time + datetime.timedelta(days=logistics_info.deliveryTime)
3986 chandransh 244
            order.promised_delivery_time = order.expected_delivery_time
3064 chandransh 245
 
3133 rajveer 246
            catalog_client = CatalogClient().get_client()
3064 chandransh 247
            catalog_client.reserveItemInWarehouse(item_id, logistics_info.warehouseId, order.lineitems[0].quantity)
248
 
249
            item_pricing = catalog_client.getItemPricing(item_id, order.warehouse_id)
250
            order.lineitems[0].transfer_price = item_pricing.transferPrice        
3499 mandeep.dh 251
 
483 rajveer 252
    session.commit()
3499 mandeep.dh 253
 
3530 mandeep.dh 254
    try:
255
        if new_status == TransactionStatus.COD_IN_PROCESS:
4008 mandeep.dh 256
            transaction_requiring_extra_processing = TransactionRequiringExtraProcessing()
257
            transaction_requiring_extra_processing.category = 'COD_VERIFICATION'
258
            transaction_requiring_extra_processing.transaction_id = transaction_id
259
            session.commit()
3530 mandeep.dh 260
    except Exception as e:
4065 mandeep.dh 261
        print "Error inserting transaction Id: " + str(transaction_id) + " due to " + str(e)
3499 mandeep.dh 262
 
483 rajveer 263
    return True
264
 
3994 chandransh 265
def __get_holidays(start_time=0L, to_time=-1L):
266
    '''
267
    Get the list of all public holidays since start time including the
268
    day of start time if it's a holiday
269
    '''
270
    midnightTime = start_time.replace(hour=0, minute=0, second=0, microsecond=0)
1730 ankur.sing 271
    fromDate = to_java_date(midnightTime)
272
    logistics_client = LogisticsClient().get_client()
3994 chandransh 273
    #TODO: This list should be cached after the first call.
274
    #Calling logistics server is also unnecessary.
275
    holidays = logistics_client.getHolidays(fromDate, to_time)
276
    holidays = [to_py_date(holiday).date() for holiday in holidays]
277
    return holidays
278
 
279
 
280
def adjust_delivery_time(start_time, delivery_days):
281
    '''
282
    Returns the actual no. of days which will pass while 'delivery_days'
283
    no. of business days will pass since 'order_time'. 
284
    '''
285
    start_date = start_time.date()
286
    end_date = start_date + datetime.timedelta(days = delivery_days)
287
    holidays = __get_holidays(start_time)
1730 ankur.sing 288
 
3994 chandransh 289
    while start_date <= end_date:
290
        if start_date.weekday() == 6 or start_date in holidays:
1730 ankur.sing 291
            delivery_days = delivery_days + 1
3994 chandransh 292
            end_date = end_date + datetime.timedelta(days = 1)
4088 chandransh 293
        start_date = start_date + datetime.timedelta(days = 1)
3994 chandransh 294
 
1730 ankur.sing 295
    return delivery_days
296
 
1398 varun.gupt 297
def enqueue_transaction_info_email(transaction_id):
1262 varun.gupt 298
    transaction = get_transaction(transaction_id)
299
 
300
    html_header = """
301
<html>
302
<body>
303
<div>
304
    <p>
305
        Hello,<br /><br />
1742 rajveer 306
        Thanks for placing order with us. Following are the details of your order:
1262 varun.gupt 307
    </p>
308
    <div>
309
        Order Date: $order_date
1569 varun.gupt 310
    </div>
1262 varun.gupt 311
    <div>
312
        <table>
1569 varun.gupt 313
        <tr><td colspan="5"><hr /></td></tr>
314
        <tr><td colspan="5" align="left"><b>Order Details</b></td></tr>
315
        <tr><td colspan="5"><hr /></td></tr>
1262 varun.gupt 316
        <tr>
2050 varun.gupt 317
            <th width="100">Order No.</th>
318
            <th>Product</th>
319
            <th width="100">Quantity</th>
320
            <th width="100">Unit Price</th>
321
            <th width="100">Amount</th>
1262 varun.gupt 322
        </tr>
323
    """
1398 varun.gupt 324
    user_email = ""
1262 varun.gupt 325
    total_amount = 0.0
326
    html_table = ""
1569 varun.gupt 327
    order_date = datetime.datetime.now()
1262 varun.gupt 328
 
329
    for order in transaction.orders:
330
        order_date = order.created_timestamp
1398 varun.gupt 331
        user_email = order.customer_email
1569 varun.gupt 332
        html_tr = "<tr><td align='center'>" + str(order.id) + "</td>"
1262 varun.gupt 333
 
334
        for lineitem in order.lineitems:
2050 varun.gupt 335
            lineitem_total_price = round(lineitem.total_price, 2)
336
 
1276 chandransh 337
            html_tr += "<td>" + str(lineitem) + "</td>"
2050 varun.gupt 338
            html_tr += "<td align='center'>" + ("%.0f" % lineitem.quantity) + "</td>"
339
            html_tr += "<td align='center'> Rs. " + ("%.2f" % lineitem.unit_price) + "</td>"
340
            html_tr += "<td align='center'> Rs. " + ("%.2f" % lineitem_total_price) + "</td></tr>"
341
            total_amount += lineitem_total_price
1262 varun.gupt 342
            html_table += html_tr
2050 varun.gupt 343
 
1262 varun.gupt 344
    html_footer = """
345
        <tr><td colspan=5>&nbsp;</td></tr>
1565 varun.gupt 346
        <tr><td colspan=5><hr /></td></tr>
1262 varun.gupt 347
        <tr>
348
            <td colspan=4>Total Amount</td>
2050 varun.gupt 349
            <td> Rs. $total_amount</td>
1262 varun.gupt 350
        </tr>
1569 varun.gupt 351
        <tr><td colspan=5><hr /></td></tr>
1262 varun.gupt 352
        </table>
1569 varun.gupt 353
    </div>
1262 varun.gupt 354
    <p>
355
        Best Wishes,<br />
356
        Saholic Team
357
    </p>
358
</div>
359
</body>
360
</html>
361
    """
1398 varun.gupt 362
 
1569 varun.gupt 363
    dt = datetime.datetime.strptime(str(order_date), "%Y-%m-%d %H:%M:%S")
1565 varun.gupt 364
    formated_order_date = dt.strftime("%A, %d. %B %Y %I:%M%p")
365
 
1262 varun.gupt 366
    email_header = Template(html_header).substitute(dict(order_date = formated_order_date))
2050 varun.gupt 367
    email_footer = Template(html_footer).substitute(dict(total_amount = "%.2f" % total_amount))
1262 varun.gupt 368
 
1351 varun.gupt 369
    try:
370
        helper_client = HelperClient().get_client()
1398 varun.gupt 371
        helper_client.saveUserEmailForSending(user_email, "", "Saholic - Order Details", email_header + html_table + email_footer, str(transaction_id), "TransactionInfo")
1351 varun.gupt 372
        return True
373
    except Exception as e:
374
        print e
375
        return False
1262 varun.gupt 376
 
483 rajveer 377
def get_order(order_id):
378
    order = Order.get_by(id=order_id)
379
    if not order:
380
        raise TransactionServiceException(108, "no such order")
381
 
382
    return order
383
 
3014 chandransh 384
def get_orders_for_customer(customer_id, from_date, to_date, statuses):
483 rajveer 385
    if not customer_id:
386
        raise TransactionServiceException(101, "bad customer id")
387
    query = Order.query.filter(Order.customer_id == customer_id)
3014 chandransh 388
    if statuses:
389
        query = query.filter(Order.status.in_(tuple(statuses)))
483 rajveer 390
    if from_date:
391
        query = query.filter(Order.created_timestamp >from_date)
392
    if to_date:
393
        query = query.filter(Order.created_timestamp < to_date)
394
    return query.all()
395
 
1528 ankur.sing 396
def get_order_for_customer(order_id, customer_id):
397
    if not customer_id:
398
        raise TransactionServiceException(101, "bad customer id")
399
    order = get_order(order_id)
400
    if order.customer_id != customer_id:
401
        raise TransactionServiceException(108, "order: " + str(order_id) + " does not belong to customer: " + str(customer_id))
402
    return order
403
 
483 rajveer 404
def get_all_orders(status, from_date, to_date, warehouse_id):
405
    if not warehouse_id:
406
        raise TransactionServiceException(101, "bad warehouse id")
407
    query = Order.query.filter(Order.warehouse_id == warehouse_id)
408
    if status:
409
        query = query.filter(Order.status == status)
410
    if from_date:
411
        query = query.filter(Order.created_timestamp >from_date)
412
    if to_date:
413
        query = query.filter(Order.created_timestamp < to_date)
414
    return query.all()
415
 
4133 chandransh 416
def get_orders_in_batch(statuses=[], offset=0, limit=0, warehouse_id=None):
417
    if not warehouse_id:
418
        raise TransactionServiceException(101, "bad warehouse id")
419
    query = Order.query.filter(Order.warehouse_id == warehouse_id)
420
    if statuses:
421
        query = query.filter(Order.status.in_(statuses))
422
    query = query.offset(offset)
423
    if limit:
424
        query = query.limit(limit)
425
    return query.all()
426
 
427
def get_order_count(statuses=[], warehouse_id=None):
428
    if not warehouse_id:
429
        raise TransactionServiceException(101, "bad warehouse id")
430
    query = session.query(func.count(Order.id)).filter(Order.warehouse_id == warehouse_id)
431
    if statuses:
432
        query = query.filter(Order.status.in_(statuses))
433
    return query.scalar()
434
 
1382 varun.gupt 435
def get_returnable_orders_for_customer(customer_id, limit = None):
436
    if not customer_id:
437
        raise TransactionServiceException(101, "bad customer id")
438
 
439
    query = Order.query.filter(Order.customer_id == customer_id)
440
    query = query.filter(Order.status != OrderStatus.PAYMENT_FAILED)
441
    query = query.filter(Order.status != OrderStatus.REJECTED)
442
    query = query.filter(Order.status > OrderStatus.SHIPPED_FROM_WH)
443
    query = query.filter(or_(Order.status < OrderStatus.DELIVERY_SUCCESS, Order.delivery_timestamp < datetime.datetime.now() + datetime.timedelta(hours = 48)))
444
    orders = query.all()
445
    order_ids = [order.id for order in orders]
446
    return order_ids
447
 
448
def get_cancellable_orders_for_customer(customer_id, limit = None):
449
    if not customer_id:
450
        raise TransactionServiceException(101, "bad customer id")
451
 
452
    query = Order.query.filter(Order.customer_id == customer_id)
453
    query = query.filter(Order.status != OrderStatus.REJECTED)
1483 varun.gupt 454
    query = query.filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING)
1382 varun.gupt 455
    query = query.filter(Order.status < OrderStatus.BILLED)
456
    orders = query.all()
457
    return [order.id for order in orders]
458
 
995 varun.gupt 459
def get_orders_by_billing_date(status, start_billing_date, end_billing_date, warehouse_id):
460
    if not warehouse_id:
461
        raise TransactionServiceException(101, "bad warehouse id")
462
 
463
    query = Order.query.filter(Order.warehouse_id == warehouse_id)
464
 
465
    if status:
466
        query = query.filter(Order.status == status)
467
 
468
    if start_billing_date:
469
        query = query.filter(Order.billing_timestamp >= start_billing_date)
470
 
471
    if end_billing_date:
472
        query = query.filter(Order.billing_timestamp <= end_billing_date)
473
 
474
    return query.all()
475
 
3451 chandransh 476
def get_orders_by_shipping_date(from_shipping_date, to_shipping_date, provider_id, warehouse_id, cod):
477
    query = Order.query.filter(Order.cod == cod)
3427 chandransh 478
 
479
    if warehouse_id and warehouse_id != -1:
480
        query = query.filter(Order.warehouse_id == warehouse_id)
481
 
482
    if provider_id and provider_id != -1:
483
        query = query.filter(Order.logistics_provider_id == provider_id)
484
 
485
    if from_shipping_date:
486
        query = query.filter(Order.shipping_timestamp >= from_shipping_date)
487
 
488
    if to_shipping_date:
489
        query = query.filter(Order.shipping_timestamp <= to_shipping_date)
490
 
491
    query = query.order_by(Order.airwaybill_no)
492
 
493
    return query.all()
494
 
1528 ankur.sing 495
def get_orders_for_transaction(transaction_id, customer_id):
496
    orders = Order.query.filter_by(transaction_id=transaction_id, customer_id=customer_id).all()
497
 
1208 chandransh 498
    if not orders:
499
        raise TransactionServiceException(101, "No order for the transaction")
500
    return orders
501
 
1405 ankur.sing 502
def get_undelivered_orders(provider_id, warehouse_id):
503
    query = Order.query
504
    if provider_id != -1:
505
        query = query.filter_by(Order.logistics_provider_id == provider_id)
506
    if warehouse_id != -1:
507
        query = query.filter(Order.warehouse_id == warehouse_id)
508
    query = query.filter(and_(Order.status != OrderStatus.DELIVERY_SUCCESS, Order.status != OrderStatus.FAILED, \
509
                              Order.status > OrderStatus.SHIPPED_FROM_WH))
1479 ankur.sing 510
    #Get last midnight time instead of current time as courier company would have sent the 
511
    #delivery records updated at least till midnight and not by the current time.
512
    time_format = "%Y-%m-%d %H:%M:%S.%f"
513
    t = time.strptime(str(datetime.datetime.now()), time_format)
514
    midnightTime = datetime.datetime(*t[:3])
515
    query = query.filter(Order.expected_delivery_time < midnightTime)
1405 ankur.sing 516
    orders = query.all()
517
    return orders
518
 
1208 chandransh 519
def get_line_items_for_order(order_id):
520
    query = LineItem.query.filter(LineItem.order_id == order_id)
521
    return query.all()
522
 
483 rajveer 523
def change_order_status(self, orderId, status, description):
524
    order = get_order(orderId)
525
    order.status = status
526
    order.statusDescription = description
527
    session.commit()
3578 mandeep.dh 528
    update_trust_level(order)
529
    return True
3499 mandeep.dh 530
 
3578 mandeep.dh 531
def update_trust_level(order):
3530 mandeep.dh 532
    try:
3578 mandeep.dh 533
        trust_level_delta = 0
534
        if order.cod == True:
535
            trust_level_delta = ORDER_STATUS_TO_USER_TRUST_LEVEL_DELTA_DICT.get(order.status, 0)
536
 
3530 mandeep.dh 537
        if (trust_level_delta != 0):
538
            user_client = UserClient().get_client()
539
            user_client.increaseTrustLevel(order.customer_id, trust_level_delta)
540
    except Exception as e:
541
        print e
3499 mandeep.dh 542
 
483 rajveer 543
    return True
3064 chandransh 544
 
545
def verify_order(self, orderId):
546
    logging.info("Verifying order no: " + str(orderId))
547
    order = get_order(orderId)
548
    if order.status == OrderStatus.INIT:
549
        order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
550
        order.statusDescription = "Submitted for processing"
551
        order.verification_timestamp = datetime.datetime.now()
552
        session.commit()
553
        logging.info("Successfully verified order no: " + str(orderId))
554
        return True
555
    else:
556
        logging.warning("Verify called for order no." + str(orderId) +" which is not in verification pending state");
557
        return False
558
 
921 rajveer 559
def accept_order(self, orderId):
3064 chandransh 560
    logging.info("Accepting order no: " + str(orderId))
921 rajveer 561
    order = get_order(orderId)
3036 chandransh 562
    if order.status in [OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW]:
3064 chandransh 563
        if not order.cod:
564
            if order.transaction.status == TransactionStatus.AUTHORIZED:
565
                __capture_txn(order.transaction.id)
3010 chandransh 566
        order.status = OrderStatus.ACCEPTED
567
        order.statusDescription = "Order Accepted"
568
        order.accepted_timestamp = datetime.datetime.now()
569
        session.commit()
3064 chandransh 570
        logging.info("Successfully accepted the order no.:" + str(orderId))
3010 chandransh 571
        return True
572
    else:
3064 chandransh 573
        logging.warning("Accept called for the unacceptable order: " + str(orderId))
3010 chandransh 574
        return False
921 rajveer 575
 
3010 chandransh 576
def __capture_txn(txnId):
577
    logging.info("Capturing payment for merchant txn:" + str(txnId))
578
    payment_client = PaymentClient().get_client()
579
    capture_result = payment_client.capturePayment(txnId)
580
    if capture_result:
3064 chandransh 581
        logging.info("Successfully captured payment for merchant txn:" + str(txnId))
582
        change_transaction_status(txnId, TransactionStatus.IN_PROCESS, "Payment received")
3010 chandransh 583
    else:
584
        raise TransactionServiceException(115, "Payment capture failed.")
585
 
921 rajveer 586
def bill_order(self, orderId):
587
    order = get_order(orderId)
588
    order.status = OrderStatus.BILLED
589
    order.statusDescription = "Order Billed"
590
    order.billing_timestamp = datetime.datetime.now()
591
    session.commit()
1208 chandransh 592
    return True
921 rajveer 593
 
1149 chandransh 594
def add_billing_details(orderId, invoice_number, billed_by):
494 rajveer 595
    order = Order.get_by(id=orderId)
596
    if not order:
2783 chandransh 597
        raise TransactionServiceException(101, "No order found for the given order id:" + str(orderId))
494 rajveer 598
    order.invoice_number = invoice_number
599
    order.billed_by = billed_by
600
    session.commit()
601
    return True
759 chandransh 602
 
2842 chandransh 603
def add_jacket_number(self, orderId, jacket_number, imei_number, item_number, billed_by, billing_type):
2783 chandransh 604
    if jacket_number is None or jacket_number <= 0:
605
        raise TransactionServiceException(110, "Invalid jacket number")
606
 
607
    if item_number is None or item_number.strip() == "":
608
        raise TransactionServiceException(110, "Invalid item number")
609
 
610
    if billed_by is None or billed_by.strip() == "":
611
        raise TransactionServiceException(110, "Invalid Biller")
612
 
1149 chandransh 613
    order = Order.get_by(id=orderId)
614
    if not order:
2783 chandransh 615
        raise TransactionServiceException(101, "No order found for the given order id" + str(orderId))
616
 
617
    order.jacket_number = jacket_number
2842 chandransh 618
    if billing_type == BillingType.OURS:
619
        order.invoice_number = get_next_invoice_number()
620
        order.billed_by = billed_by
621
        order.status = OrderStatus.BILLED
622
        order.statusDescription = "Order Billed"
623
        order.billing_timestamp = datetime.datetime.now()
2783 chandransh 624
 
2842 chandransh 625
        lineitem = order.lineitems[0]
626
        if lineitem.productGroup == "Handsets" and imei_number <= 0:
627
            raise TransactionServiceException(110, "No IMEI number supplied for a handset.")
628
        lineitem.item_number = item_number
629
        if imei_number > 0:
630
            lineitem.imei_number = str(imei_number)
2783 chandransh 631
 
1149 chandransh 632
    session.commit()
633
    return True
634
 
1220 chandransh 635
def batch_orders(warehouseId):
636
    if not warehouseId:
637
        raise TransactionServiceException(101, "bad warehouse id")
1225 chandransh 638
 
639
    batchno_generator = BatchNoGenerator()
640
    session.commit()
1220 chandransh 641
    query = Order.query.filter_by(warehouse_id=warehouseId)
642
    query = query.filter_by(status=OrderStatus.SUBMITTED_FOR_PROCESSING)
643
    query = query.order_by(Order.created_timestamp)
644
    pending_orders = query.all()
1225 chandransh 645
 
1220 chandransh 646
    serial_no = 1
647
    for order in pending_orders:
1276 chandransh 648
        order.batchNo = batchno_generator.id
1220 chandransh 649
        order.serialNo = serial_no
650
        serial_no += 1
651
    session.commit() 
652
    pending_orders = query.all()
653
    return pending_orders
654
 
655
def order_outofstock(orderId):
1911 chandransh 656
    '''
657
    Mark order as out of stock
658
    '''
1220 chandransh 659
    order = get_order(orderId)
660
    order.status = OrderStatus.INVENTORY_LOW
661
    order.statusDescription = "Low Inventory"
662
    order.outofstock_timestamp = datetime.datetime.now()
663
    session.commit()
664
    return True
665
 
3064 chandransh 666
def mark_orders_as_manifested(warehouse_id, provider_id, cod):
759 chandransh 667
    try:
986 chandransh 668
        current_timestamp = datetime.datetime.now()
3064 chandransh 669
        orders = Order.query.filter_by(warehouse_id = warehouse_id, logistics_provider_id = provider_id, status = OrderStatus.BILLED, cod = cod).all()
759 chandransh 670
        for order in orders:
671
            order.status = OrderStatus.SHIPPED_FROM_WH
987 chandransh 672
            order.statusDescription = "Order shipped from warehouse"
986 chandransh 673
            order.shipping_timestamp = current_timestamp
759 chandransh 674
        session.commit()
675
        return True
676
    except:
677
        return False
1113 chandransh 678
 
679
def mark_orders_as_picked_up(provider_id, pickup_details):
680
    for awb, pickup_timestamp in pickup_details.iteritems():
1135 chandransh 681
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
2684 chandransh 682
        if order == None or order.status != OrderStatus.SHIPPED_FROM_WH:
2220 chandransh 683
            #raise TransactionServiceException(102, "No order found for the awb: " + awb)
684
            continue
1113 chandransh 685
        order.status = OrderStatus.SHIPPED_TO_LOGST
686
        order.statusDescription = "Order picked up by Courier Company"
1246 chandransh 687
        order.pickup_timestamp = pickup_timestamp
1113 chandransh 688
    session.commit()
1217 chandransh 689
 
1132 chandransh 690
    current_time = datetime.datetime.now()
691
    to_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
1246 chandransh 692
    from_datetime = to_datetime - datetime.timedelta(2)
1132 chandransh 693
    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 694
    return orders_not_picked_up
695
 
1132 chandransh 696
def mark_orders_as_delivered(provider_id, delivered_orders):
697
    for awb, detail in delivered_orders.iteritems():
1135 chandransh 698
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
2684 chandransh 699
        if order == None or order.status not in [OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST]:
1911 chandransh 700
            continue
701
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
1132 chandransh 702
        order.status = OrderStatus.DELIVERY_SUCCESS
703
        order.statusDescription = "Order delivered"
704
        order.delivery_timestamp, order.receiver = detail.split('|')
3578 mandeep.dh 705
        update_trust_level(order)
1132 chandransh 706
    session.commit()
707
 
1135 chandransh 708
def mark_orders_as_failed(provider_id, returned_orders):
709
    for awb, detail in returned_orders.iteritems():
710
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
2684 chandransh 711
        if order == None or order.status not in [OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST]:
712
            continue
713
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
714
        order.status = OrderStatus.SALES_RETURN_IN_TRANSIT
1135 chandransh 715
        order.delivery_timestamp, reason = detail.split('|')
716
        order.statusDescription = "Order Returned to Origin:" + reason
3578 mandeep.dh 717
        update_trust_level(order)
1911 chandransh 718
    session.commit()
1135 chandransh 719
 
1246 chandransh 720
def update_non_delivery_reason(provider_id, undelivered_orders):
721
    for awb, reason in undelivered_orders.iteritems():
722
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
723
        if order == None:
2684 chandransh 724
            continue
725
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
1246 chandransh 726
        order.statusDescription = reason
727
    session.commit()
728
 
483 rajveer 729
def get_alerts(order_id, all):
730
    query = Alerts.query.filter_by(order_id=order_id)
731
    if not all:
732
        query = query.filter_by(valid=True)
733
    return query.all()
734
 
735
def set_alert(order_id, unset, type, comment):
736
    #get existing alert
737
    if unset:
738
        query = Alerts.query.filter_by(order_id=order_id)
739
        query = query.filter_by(type=type)
740
        alerts = query.all()
741
        for alert in alerts:
742
            if alert.valid:
743
                alert.valid = False
744
                alert.comment = comment
745
                alert.time_unset = datetime.datetime.now()
746
    else:
747
        alert = Alerts()
748
        alert.order_id = order_id
749
        alert.valid = True
750
        alert.type = type
751
        alert.comment = comment
752
        alert.time_set = datetime.datetime.now()
766 rajveer 753
    session.commit()    
754
 
1596 ankur.sing 755
def get_valid_order_count():
2851 chandransh 756
    '''
757
    Returns the number of orders which we processed. The reshipped orders are not
758
    counted since there'll always be a new compensating order present.
759
    '''
3216 chandransh 760
    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 761
 
1627 ankur.sing 762
def get_cust_count_with_successful_txn():
2851 chandransh 763
    '''
764
    Returns the number of distinct customers who have done successful transactions.
765
    It uses the sqlalchemy func module to construct an efficient query.
766
    '''
767
    return session.query(func.count(distinct(Order.customer_id))).filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING).scalar()
1627 ankur.sing 768
 
1730 ankur.sing 769
def get_valid_orders_amount_range():
2851 chandransh 770
    '''
771
    Returns a list containing the minimum and maximum amount across all
772
    orders placed with us. No need to consider reshippped orders for min/max
773
    amount of orders.
774
    '''
775
    return session.query(func.min(Order.total_amount), func.max(Order.total_amount)).filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING).one()
1627 ankur.sing 776
 
1886 ankur.sing 777
def get_valid_orders(limit):
2851 chandransh 778
    '''
779
    Returns the last limit number of valid orders placed with us. Ignored the
780
    limit if it's passed as 0. Raises an excpetion if the supplied limit is 
781
    less than 0. 
782
    '''
783
    if limit < 0:
784
        raise TransactionServiceException(101, "Invalid argument limit " + limit)
3072 chandransh 785
    query = Order.query.filter(Order.status >= OrderStatus.INIT)
1886 ankur.sing 786
    query = query.order_by(desc(Order.created_timestamp))
2851 chandransh 787
    if limit != 0:
1886 ankur.sing 788
        query = query.limit(limit)
789
    return query.all()
790
 
2783 chandransh 791
def get_next_invoice_number():
792
    entity_id = InvoiceIDGenerator.query.with_lockmode("update").one()
793
    invoice_number = entity_id.id + 1
794
    entity_id.id = invoice_number
795
    session.commit()
796
    return invoice_number
797
 
2536 chandransh 798
def toggle_doa_flag(order_id):
799
    order = get_order(order_id)
800
    if(order.doaFlag):
801
        order.doaFlag = False
802
    else:
803
        order.doaFlag = True
804
    session.commit()
805
    return order.doaFlag
806
 
807
def request_pickup_number(order_id):
808
    order = get_order(order_id)
809
    if order.status != OrderStatus.DELIVERY_SUCCESS and order.status != OrderStatus.DOA_PICKUP_REQUESTED:
810
        return False
811
    from_user = 'cnc.center@shop2020.in'
812
    from_pwd = '5h0p2o2o'
813
 
814
    subject = "Pickup request"
815
    try:
3133 rajveer 816
        catalog_client = CatalogClient().get_client()
2536 chandransh 817
        warehouse = catalog_client.getWarehouse(order.warehouse_id)
818
 
819
        logistics_client = LogisticsClient().get_client()
820
        provider = logistics_client.getProvider(order.logistics_provider_id)
3051 chandransh 821
        to_addr = provider.details[DeliveryType.PREPAID].email
2536 chandransh 822
        raw_message = '''
823
        Dear Sir/Madam,
824
 
2559 chandransh 825
        Kindly arrange a pickup today from %(customer_city)s. Pickup and delivery addresses are mentioned below.
2536 chandransh 826
 
827
        Pickup CODE: %(provider_code)s
828
        Total Weight: %(order_weight)s kg
829
 
2559 chandransh 830
        Pickup Address:
2536 chandransh 831
 
832
        %(customer_address)s
833
 
834
        Delivery Address:
835
 
836
        %(warehouse_executive)s
837
        %(warehouse_address)s
838
        PIN %(warehouse_pin)s
839
        Phone: %(warehouse_phone)s
840
 
841
        Thanks and Regards
842
        Anand Sinha
843
        '''
2559 chandransh 844
        message = dedent(raw_message) % { 'customer_city' : order.customer_city,
3051 chandransh 845
                                          'provider_code' : provider.details[DeliveryType.PREPAID].accountNo,
2536 chandransh 846
                                          'order_weight' : str(order.total_weight),
847
                                          'customer_address' : __get_order_address(order),
848
                                          'warehouse_executive' : 'Parmod Kumar',
849
                                          'warehouse_address' : warehouse.location,
850
                                          'warehouse_pin' : warehouse.pincode,
851
                                          'warehouse_phone': '9971573026'}
3527 chandransh 852
        mail(from_user, from_pwd, [to_addr], subject, message)
2536 chandransh 853
        order.status = OrderStatus.DOA_PICKUP_REQUESTED
854
        order.statusDescription = "Pick up requested for DOA"
855
        session.commit()
856
        return True
857
    except Exception as e:
858
        print sys.exc_info()[0]
859
        return False
860
 
861
def authorize_pickup(order_id, pickup_number):
862
    order = get_order(order_id)
863
    if order.status != OrderStatus.DOA_PICKUP_REQUESTED:
864
        return False
865
    from_user = 'help@shop2020.in'
866
    from_pwd = '5h0p2o2o'
867
    subject = 'Pickup details'
868
    filename = "/tmp/" +  str(order.id) +".pdf" 
869
    try:
3133 rajveer 870
        catalog_client = CatalogClient().get_client()
2536 chandransh 871
        warehouse = catalog_client.getWarehouse(order.warehouse_id)
872
 
873
        logistics_client = LogisticsClient().get_client()
874
        provider = logistics_client.getProvider(order.logistics_provider_id)
875
        provider_name = provider.name
876
 
877
        to_addr = order.customer_email
878
        today = date.today().strftime("%d-%B-%Y (%A)")
879
 
880
        raw_message = '''
881
        Dear Mr. %(customer_name)s,
882
 
883
        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.
884
        Take a printout of the attachment in this mail which contains the delivery address and paste it on the packed parcel.
885
        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.
886
 
887
        Pickup will happen from the below mentioned address:-
888
 
889
        %(customer_address)s
890
 
891
        Do let us know in case of any concerns
892
 
893
        Thanks & Regards
894
        Saholic Team
895
        '''
896
        message = dedent(raw_message) % {'customer_name' : order.customer_name,
897
                                         'order_id' : order_id,
898
                                         'provider_name' : provider_name,
899
                                         'date': today,
900
                                         'pickup_request_no' : pickup_number,
901
                                         'customer_address' : __get_order_address(order)}
902
        print message
903
        __generate_return_advice(order, warehouse, provider, filename)
3527 chandransh 904
        mail(from_user, from_pwd, [to_addr], subject, message, [get_attachment_part(filename)])
2536 chandransh 905
        order.pickupRequestNo = pickup_number
906
        order.status = OrderStatus.DOA_RETURN_AUTHORIZED
907
        order.statusDescription = "DOA pick up authorized"
2764 chandransh 908
        order.doa_auth_timestamp = datetime.datetime.now()
2536 chandransh 909
        session.commit()
910
        return True
911
    except Exception as e:
912
        print sys.exc_info()[0]
913
        return False
914
    finally:
915
        if os.path.exists(filename):
916
            os.remove(filename)
917
 
2764 chandransh 918
def mark_doas_as_picked_up(provider_id, pickup_details):
919
    for pickupNo, doa_pickup_timestamp in pickup_details.iteritems():
920
        order = Order.query.filter_by(pickupRequestNo=pickupNo, logistics_provider_id = provider_id).first()
921
        if order == None or order.status != OrderStatus.DOA_RETURN_AUTHORIZED:
922
            #raise TransactionServiceException(102, "No order found for the awb: " + awb)
923
            continue
924
        order.status = OrderStatus.DOA_RETURN_IN_TRANSIT
925
        order.statusDescription = "DOA picked up by Courier Company"
926
        order.doa_pickup_timestamp = doa_pickup_timestamp
927
    session.commit()
928
 
929
    current_time = datetime.datetime.now()
930
    to_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
931
    from_datetime = to_datetime - datetime.timedelta(2)
932
    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()
933
    return orders_not_picked_up
934
 
2616 chandransh 935
def receive_return(order_id):
2591 chandransh 936
    order = get_order(order_id)
2616 chandransh 937
    if order.status in [OrderStatus.DOA_RETURN_AUTHORIZED, OrderStatus.DOA_RETURN_IN_TRANSIT]:
938
        order.status = OrderStatus.DOA_RECEIVED
939
        order.statusDescription = "DOA package received"
2764 chandransh 940
        order.received_return_timestamp = datetime.datetime.now()
2616 chandransh 941
        session.commit()
942
    elif order.status == OrderStatus.SALES_RETURN_IN_TRANSIT :
943
        order.status = OrderStatus.SALES_RET_RECEIVED
944
        order.statusDescription = "Sales return received"
2764 chandransh 945
        order.received_return_timestamp = datetime.datetime.now()
2616 chandransh 946
        session.commit()
947
    else:
2591 chandransh 948
        return False
949
    return True
950
 
951
def validate_doa(order_id, is_valid):
952
    order = get_order(order_id)
2599 chandransh 953
    if order.status != OrderStatus.DOA_RECEIVED:
2591 chandransh 954
        return False
955
    if is_valid:
2609 chandransh 956
        order.status = OrderStatus.DOA_CERT_VALID
957
        order.statusDescription = "DOA Certificate Valid"
2591 chandransh 958
    else:
959
        order.status = OrderStatus.DOA_CERT_INVALID
960
        order.statusDescription = "DOA Certificate Invalid"
3578 mandeep.dh 961
        update_trust_level(order)
2591 chandransh 962
    session.commit()
963
    return True
964
 
2628 chandransh 965
def reship_order(order_id):
966
    """
967
    If the order is in SALES_RET_RECEIVED or DOA_CERT_INVALID state, it does the following:
968
        1. Creates a new order for processing in the BILLED state. All billing information is saved.
969
        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.
970
 
971
    If the order is in DOA_CERT_VALID state, it does the following:
972
        1. Creates a new order for processing in the SUBMITTED_FOR_PROCESSING state.
973
        2. Creates a return order for the warehouse executive to return the DOA material.
974
        3. Marks the current order as the final DOA_RESHIPPED state.
975
 
976
    Returns the id of the newly created order.
977
 
978
    Throws an exception if the order with the given id couldn't be found.
979
 
980
    Parameters:
981
     - orderId
982
    """
983
    order = get_order(order_id)
984
    if order.status == OrderStatus.SALES_RET_RECEIVED:
985
        new_order = __clone_order(order, True)
986
        order.status = OrderStatus.SALES_RET_RESHIPPED
987
        order.statusDescription = "Order Reshipped"
988
        session.commit()
3578 mandeep.dh 989
        update_trust_level(order)
2628 chandransh 990
    elif order.status == OrderStatus.DOA_CERT_INVALID:
991
        new_order = __clone_order(order, True)
992
        order.status = OrderStatus.DOA_INVALID_RESHIPPED
993
        order.statusDescription = "Order Reshipped"
994
        session.commit()
995
    elif order.status == OrderStatus.DOA_CERT_VALID:
996
        new_order = __clone_order(order, False)
997
        ret_order = __create_return_order(order)
998
        order.status = OrderStatus.DOA_RESHIPPED
999
        order.statusDescription = "Order Reshipped"
1000
        session.commit()
1001
    else:
1002
        raise TransactionServiceException(112, "This order can't be reshipped")
1003
 
2764 chandransh 1004
    order.reship_timestamp = datetime.datetime.now()
2628 chandransh 1005
    order.new_order_id = new_order.id
1006
    session.commit()
1007
 
1008
    return new_order.id
1009
 
3226 chandransh 1010
def refund_order(order_id, refunded_by, reason):
2628 chandransh 1011
    """
1012
    If the order is in SALES_RET_RECEIVED, DOA_CERT_VALID or DOA_CERT_INVALID state, it does the following:
1013
        1. Creates a refund request for batch processing.
1014
        2. Creates a return order for the warehouse executive to return the shipped material.
1015
        3. Marks the current order as SALES_RET_REFUNDED, DOA_VALID_REFUNDED or DOA_INVALID_REFUNDED final states.
1016
 
1017
    If the order is in SUBMITTED_FOR_PROCESSING or INVENTORY_LOW state, it does the following:
1018
        1. Creates a refund request for batch processing.
3226 chandransh 1019
        2. Cancels the reservation of the item in the warehouse.
1020
        3. Marks the current order as the REFUNDED final state.
2628 chandransh 1021
 
3226 chandransh 1022
    For all COD orders, if the order is in INIT, SUBMITTED_FOR_PROCESSING or INVENTORY_LOW state, it does the following:
1023
        1. Cancels the reservation of the item in the warehouse.
1024
        2. Marks the current order as CANCELED.
1025
 
1026
    In all cases, it updates the reason for cancellation or refund and the person who performed the action.
1027
 
1028
    Returns True if it is successful, False otherwise.
2628 chandransh 1029
 
1030
    Throws an exception if the order with the given id couldn't be found.
1031
 
1032
    Parameters:
3226 chandransh 1033
     - order_id
1034
     - refunded_by
1035
     - reason
2628 chandransh 1036
    """
3414 chandransh 1037
    logging.info("Refunding order id: " + str(order_id))
2628 chandransh 1038
    order = get_order(order_id)
3186 chandransh 1039
 
1040
 
3366 chandransh 1041
 
3226 chandransh 1042
    if order.cod:
3414 chandransh 1043
        logging.info("Refunding COD order with status " + str(order.status))
3366 chandransh 1044
        status_transition = {OrderStatus.SALES_RET_RECEIVED : OrderStatus.SALES_RET_REFUNDED,
1045
                     OrderStatus.DOA_CERT_INVALID : OrderStatus.DOA_INVALID_REFUNDED,
1046
                     OrderStatus.DOA_CERT_VALID : OrderStatus.DOA_VALID_REFUNDED,
1047
                     OrderStatus.INIT : OrderStatus.CANCELED,
1048
                     OrderStatus.SUBMITTED_FOR_PROCESSING : OrderStatus.CANCELED,
1049
                     OrderStatus.INVENTORY_LOW : OrderStatus.CANCELED,
1050
                     OrderStatus.ACCEPTED : OrderStatus.CANCELED,
3731 chandransh 1051
                     OrderStatus.BILLED : OrderStatus.CANCELED
3366 chandransh 1052
                     }
1053
        if order.status not in status_transition.keys():
1054
            raise TransactionServiceException(114, "This order can't be refunded")
1055
 
3413 chandransh 1056
        if order.status < OrderStatus.BILLED:
3226 chandransh 1057
            __update_inventory_reservation(order)
1058
            order.statusDescription = "Order Cancelled"
3415 chandransh 1059
        elif order.status == OrderStatus.BILLED:
3413 chandransh 1060
            __create_return_order(order)
1061
            order.statusDescription = "Order Cancelled"
4078 chandransh 1062
        elif order.status == OrderStatus.SALES_RET_RECEIVED:
3226 chandransh 1063
            __create_return_order(order)
4078 chandransh 1064
            order.statusDescription = "Order Returned to origin"
1065
        elif order.status in [OrderStatus.DOA_CERT_INVALID, OrderStatus.DOA_CERT_VALID] :
1066
            __create_return_order(order)
3226 chandransh 1067
            __create_refund(order)
1068
            order.statusDescription = "Order Refunded"
1069
    else:
3366 chandransh 1070
        status_transition = {OrderStatus.SALES_RET_RECEIVED : OrderStatus.SALES_RET_REFUNDED,
1071
                     OrderStatus.DOA_CERT_INVALID : OrderStatus.DOA_INVALID_REFUNDED,
1072
                     OrderStatus.DOA_CERT_VALID : OrderStatus.DOA_VALID_REFUNDED,
1073
                     OrderStatus.SUBMITTED_FOR_PROCESSING : OrderStatus.REFUNDED,
3731 chandransh 1074
                     OrderStatus.INVENTORY_LOW : OrderStatus.REFUNDED,
1075
                     OrderStatus.ACCEPTED : OrderStatus.REFUNDED,
1076
                     OrderStatus.BILLED : OrderStatus.REFUNDED
3366 chandransh 1077
                     }
1078
        if order.status not in status_transition.keys():
1079
            raise TransactionServiceException(114, "This order can't be refunded")
1080
 
3226 chandransh 1081
        if order.status in [OrderStatus.SALES_RET_RECEIVED, OrderStatus.DOA_CERT_INVALID, OrderStatus.DOA_CERT_VALID] :
1082
            __create_return_order(order)
1083
            __create_refund(order)
1084
            order.statusDescription = "Order Refunded"
1085
        elif order.status in [OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW]:
3191 chandransh 1086
            __create_cancellation(order)
3226 chandransh 1087
            __update_inventory_reservation(order)
1088
            order.statusDescription = "Order Refunded"
3195 chandransh 1089
 
1090
    order.status = status_transition[order.status]
1091
    order.refund_timestamp = datetime.datetime.now()
3226 chandransh 1092
    order.refunded_by = refunded_by
1093
    order.refund_reason = reason
2628 chandransh 1094
 
1095
    session.commit()
1096
    return True
1097
 
3186 chandransh 1098
def __update_inventory_reservation(order):
3191 chandransh 1099
    '''
1100
    Reduce the reservation count for all line items of the given order.
1101
    '''
3186 chandransh 1102
    try:
1103
        catalog_client = CatalogClient().get_client()
1104
        for lineitem in order.lineitems:
1105
            catalog_client.reduceReservationCount(lineitem.item_id, order.warehouse_id, lineitem.quantity);
1106
    except:
1107
        print "Unable to reduce reservation count"
1108
 
2628 chandransh 1109
def __clone_order(order, should_copy_billing_info):
1110
    current_time = datetime.datetime.now()
1111
    new_order = Order()
1112
    new_order.customer_id = order.customer_id
1113
    new_order.customer_name = order.customer_name
1114
    new_order.customer_city = order.customer_city
1115
    new_order.customer_state = order.customer_state
1116
    new_order.customer_mobilenumber = order.customer_mobilenumber
1117
    new_order.customer_pincode = order.customer_pincode
1118
    new_order.customer_address1 = order.customer_address1
1119
    new_order.customer_address2 = order.customer_address2
1120
    new_order.customer_email = order.customer_email
1121
    new_order.total_amount = order.total_amount
1122
    new_order.total_weight = order.total_weight
1123
    new_order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
1124
    new_order.statusDescription = 'Submitted for Processing'
1125
    new_order.created_timestamp = current_time
1126
 
1127
    new_order.transaction = order.transaction
3239 chandransh 1128
    new_order.cod = False
2628 chandransh 1129
 
1130
    for line_item in order.lineitems:
1131
        litem = LineItem()
1132
        litem.item_id = line_item.item_id
1133
        litem.productGroup = line_item.productGroup
1134
        litem.brand = line_item.brand
1135
        if line_item.model_number:
1136
            litem.model_number = line_item.model_number
1137
        if line_item.model_name:    
1138
            litem.model_name = line_item.model_name
1139
        if line_item.color:
1140
            litem.color = line_item.color
1141
        if line_item.extra_info:
1142
            litem.extra_info = line_item.extra_info
1143
        litem.quantity = line_item.quantity
1144
        litem.unit_price = line_item.unit_price
1145
        litem.unit_weight = line_item.unit_weight
1146
        litem.total_price = line_item.total_price
1147
        litem.total_weight = line_item.total_weight
1148
        litem.transfer_price = line_item.transfer_price
1149
        litem.order = new_order
1150
 
1151
    logistics_client = LogisticsClient().get_client()
1152
    item_id = new_order.lineitems[0].item_id
3239 chandransh 1153
    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 1154
    logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
1155
 
1156
    new_order.warehouse_id = logistics_info.warehouseId
1157
    new_order.logistics_provider_id = logistics_info.providerId
1158
    new_order.airwaybill_no = logistics_info.airway_billno
1159
    new_order.tracking_id = new_order.airwaybill_no
1160
    new_order.expected_delivery_time = current_time + datetime.timedelta(days=logistics_info.deliveryTime)
3986 chandransh 1161
    new_order.promised_delivery_time = new_order.expected_delivery_time
2628 chandransh 1162
 
1163
    if should_copy_billing_info:
1164
        new_order.invoice_number = order.invoice_number
1165
        new_order.billed_by = order.billed_by
1166
        new_order.warehouse_id = order.warehouse_id
1167
        new_order.accepted_timestamp = current_time
1168
        new_order.billing_timestamp = current_time    
1169
        new_order.status = OrderStatus.BILLED
1170
        new_order.statusDescription = 'Order Billed'
1171
    else:       
3133 rajveer 1172
        catalog_client = CatalogClient().get_client()
2628 chandransh 1173
        catalog_client.reserveItemInWarehouse(item_id, logistics_info.warehouseId, new_order.lineitems[0].quantity)
1174
 
1175
        item_pricing = catalog_client.getItemPricing(item_id, order.warehouse_id)
1176
        new_order.lineitems[0].transfer_price = item_pricing.transferPrice
1177
 
1178
    return new_order
1179
 
1180
def __create_return_order(order):
2687 chandransh 1181
    ret_order = ReturnOrder(order)
2628 chandransh 1182
    return ret_order
1183
 
1184
def __create_refund(order):
4078 chandransh 1185
    payment_client = PaymentClient().get_client()
1186
    payment_client.createRefund(order.id, order.transaction.id, order.total_amount)
2747 chandransh 1187
    return
2628 chandransh 1188
 
3035 chandransh 1189
def __create_cancellation(order):
1190
    return
1191
 
2536 chandransh 1192
def __get_order_address(order):
1193
    address = order.customer_name + "\n" + order.customer_address1 + "\n"
1194
    if order.customer_address2:
1195
        address = address + order.customer_address2 + "\n"
1196
    address = address + order.customer_city + "\n"
1197
    address = address + order.customer_state + "\n"
1198
    address = address + "PIN " + order.customer_pincode + "\n"
1199
    address = address + "Phone: " + order.customer_mobilenumber
1200
    return address
1201
 
1202
def __generate_return_advice(order, warehouse, provider, filename):    
1203
    pdf = Canvas(filename)
1204
    pdf.setFont('Times-Bold',16)
1205
    address_text = pdf.beginText(inch, PAGE_HEIGHT - inch)
1206
    address_text.textLine("To")
1207
    address_text.textLine("Parmod Kumar")
1208
    for line in warehouse.location.split("\n"):
1209
        address_text.textLine(line)
1210
    address_text.textLine("PIN " + warehouse.pincode)
1211
    address_text.textLine("")
1212
    address_text.textLine("Phone: 9971573026")
1213
    pdf.drawText(address_text)
1214
 
1215
    pdf.setFont('Times-Roman',12)
1216
    order_text = pdf.beginText(inch, PAGE_HEIGHT - 4 * inch)
3051 chandransh 1217
    order_text.textLine("Pickup CODE: " + provider.details[DeliveryType.PREPAID].accountNo)
2536 chandransh 1218
    lineitem = order.lineitems[0] 
1219
    order_text.textLine("Content : " + lineitem.brand + " " + lineitem.model_number + " " + lineitem.color)
1220
    order_text.textLine("Declared Value: Rs. " + str(order.total_amount))
1221
    order_text.textLine("Order ID : " + str(order.id))
1222
    pdf.drawText(order_text)
1223
    pdf.showPage()
1224
    pdf.save()
1225
    return filename
1226
 
2697 chandransh 1227
def get_return_orders(warehouse_id, from_date, to_date):
1228
    query = ReturnOrder.query.filter_by(processedStatus = False)
1229
    if warehouse_id != -1:
1230
        query = query.filter_by(warehouseId = warehouse_id)
1231
    if from_date:
4118 chandransh 1232
        query = query.filter(ReturnOrder.createdAt >from_date)
2697 chandransh 1233
    if to_date:
4118 chandransh 1234
        query = query.filter(ReturnOrder.createdAt < to_date)
2697 chandransh 1235
    return [return_order.to_thrift_object() for return_order in query.all()]
1236
 
2700 chandransh 1237
def get_return_order(id):
1238
    ret_order = ReturnOrder.get_by(orderId = id)
1239
    if ret_order is None:
1240
        raise TransactionServiceException(116, "No return order found for the given order id")
1241
    return ret_order.to_thrift_object()
1242
 
2697 chandransh 1243
def process_return(ret_order_id):
1244
    ret_order = ReturnOrder.get_by(orderId = ret_order_id)
1245
    if ret_order is None:
1246
        raise TransactionServiceException(116, "No return order found for the given order id")
1247
    ret_order.processedStatus = True
2701 chandransh 1248
    ret_order.processedAt = datetime.datetime.now()
2697 chandransh 1249
    session.commit()
1250
 
2819 chandransh 1251
def create_purchase_order(warehouseId):
1252
    if not warehouseId:
1253
        raise TransactionServiceException(101, "bad warehouse id")
1254
 
3451 chandransh 1255
    query = Order.query.with_lockmode("update").filter_by(warehouse_id=warehouseId)
2819 chandransh 1256
    query = query.filter_by(status=OrderStatus.SUBMITTED_FOR_PROCESSING)
1257
    query = query.filter_by(purchase_order_id=None)
1258
    query = query.order_by(Order.created_timestamp)
1259
    pending_orders = query.all()
1260
 
1261
    if not pending_orders:
1262
        return -1
1263
 
1264
    t_purchase_order = PurchaseOrder()
2832 chandransh 1265
    t_purchase_order.supplierId = warehouseId
2819 chandransh 1266
    t_purchase_order.warehouseId = warehouseId
1267
    t_purchase_order.lineitems = []
1268
 
1269
    lineitems = {}
1270
 
1271
    for order in pending_orders:
1272
        for lineitem in order.lineitems:
1273
            item_id = lineitem.item_id
1274
            if lineitems.has_key(item_id):
1275
                lineitems[item_id].quantity = lineitems[item_id].quantity + lineitem.quantity
1276
            else:
1277
                t_po_lineitem = POLineItem()
1278
                t_po_lineitem.productGroup = lineitem.productGroup
1279
                t_po_lineitem.brand = lineitem.brand
1280
                t_po_lineitem.modelNumber = lineitem.model_number
1281
                t_po_lineitem.modelName = lineitem.model_name
1282
                t_po_lineitem.color = lineitem.color
1283
                t_po_lineitem.itemId = lineitem.item_id
1284
                t_po_lineitem.quantity = lineitem.quantity
1285
                t_po_lineitem.unitPrice = lineitem.transfer_price
1286
                lineitems[item_id] = t_po_lineitem
1287
                t_purchase_order.lineitems.append(t_po_lineitem)
1288
 
1289
    warehouse_client = WarehouseClient().get_client()
1290
    po_id = warehouse_client.createPurchaseOrder(t_purchase_order)
1291
 
1292
    for order in pending_orders:
1293
        order.purchase_order_id = po_id
1294
    session.commit()
1295
    return po_id
1296
 
3451 chandransh 1297
def update_weight(order_id, weight):
3469 chandransh 1298
    '''
1299
    Update the weight of order
1300
    '''
3451 chandransh 1301
    order = get_order(order_id)
1302
    order.total_weight = weight
3469 chandransh 1303
    lineitem = order.lineitems[0]
1304
    lineitem.total_weight = weight
1305
    lineitem.unit_weight = weight
3451 chandransh 1306
 
3469 chandransh 1307
    session.commit()
1308
    return order
1309
 
1310
def change_product(order_id, item_id):
1311
    '''
1312
    Ship a product of a different color to the customer.
1313
    '''
1314
    order = get_order(order_id)
1315
    if order.status not in [OrderStatus.INIT, OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW]:
1316
        raise TransactionServiceException(120, "This order has already been processed. Please seek help from engineering.")
1317
 
1318
    lineitem = order.lineitems[0]
3451 chandransh 1319
 
3469 chandransh 1320
    catalog_client = CatalogClient().get_client()
1321
 
1322
    old_item = catalog_client.getItem(lineitem.item_id)
1323
    item = catalog_client.getItem(item_id)
1324
    if old_item.catalogItemId != item.catalogItemId:
1325
        raise TransactionServiceException(121, "You can't ship a different item. You can only ship the same item in a different color.")
1326
 
1327
    catalog_client.reserveItemInWarehouse(item_id, order.warehouse_id, lineitem.quantity)
1328
    catalog_client.reduceReservationCount(lineitem.item_id, order.warehouse_id, lineitem.quantity)
1329
    #TODO: Check that this new item has the same price
1330
 
1331
    lineitem.item_id = item_id
1332
    lineitem.color = item.color
1333
 
3451 chandransh 1334
    session.commit()
3469 chandransh 1335
 
1336
    order = get_order(order_id)
3451 chandransh 1337
    return order
3469 chandransh 1338
 
1339
def change_warehouse(order_id, warehouse_id):
1340
    '''
1341
    Update the warehouse which will be used to fulfil this order.
1342
    '''
1343
    order = get_order(order_id)
1344
    if order.status not in [OrderStatus.INIT, OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW]:
1345
        raise TransactionServiceException(117, "This order has already been processed. Please seek help from engineering.")
1346
 
1347
    if warehouse_id == order.warehouse_id:
1348
        raise TransactionServiceException(118, "You have selected the current warehouse again. Nothing to do")
1349
 
1350
    lineitem = order.lineitems[0]
1351
    catalog_client = CatalogClient().get_client()
1352
    try:
1353
        warehouse = catalog_client.getWarehouse(warehouse_id)
1354
    except:
1355
        raise TransactionServiceException(119, "No warehouse with id" + str(warehouse_id))
1356
 
1357
    catalog_client.reserveItemInWarehouse(lineitem.item_id, warehouse_id, lineitem.quantity)
1358
    catalog_client.reduceReservationCount(lineitem.item_id, order.warehouse_id, lineitem.quantity)
3451 chandransh 1359
 
3469 chandransh 1360
    order.warehouse_id = warehouse_id
1361
    session.commit()
1362
    return order
3553 chandransh 1363
 
3986 chandransh 1364
def add_delay_reason(order_id, reason, further_delay=0):
3553 chandransh 1365
    '''
3994 chandransh 1366
    Adds a delay reason to the order and updates the expected delivery time.
3553 chandransh 1367
    '''
1368
    order = get_order(order_id)
1369
    try:
3581 chandransh 1370
        order.delay_reason = DelayReason._VALUES_TO_NAMES[reason]
4009 chandransh 1371
        actual_delivery_delay = adjust_delivery_time(order.expected_delivery_time, further_delay)
1372
        order.expected_delivery_time = order.expected_delivery_time + datetime.timedelta(days=actual_delivery_delay)
4102 chandransh 1373
 
1374
        if order.status < OrderStatus.SHIPPED_FROM_WH:
1375
            actual_shipping_delay = adjust_delivery_time(order.expected_shipping_time, further_delay)
1376
            order.expected_shipping_time = order.expected_shipping_time + datetime.timedelta(days=actual_shipping_delay)
1377
 
3553 chandransh 1378
        session.commit()
4008 mandeep.dh 1379
 
1380
        try:
1381
            transaction_requiring_extra_processing = TransactionRequiringExtraProcessing()
1382
            transaction_requiring_extra_processing.category = 'DELAYED_DELIVERY'
1383
            transaction_requiring_extra_processing.transaction_id = order.transaction_id
1384
            session.commit()
1385
        except Exception as e:
4065 mandeep.dh 1386
            print 'Could not persist transaction id: ' + str(order.transaction_id) + ' for further processing due to: ' + str(e)
4008 mandeep.dh 1387
 
3553 chandransh 1388
        return True
1389
    except:
3994 chandransh 1390
        print sys.exc_info()[0]
3553 chandransh 1391
        return False
3956 chandransh 1392
 
1393
def reconcile_cod_collection(collected_amount_map, xferBy, xferTxnId, xferDate):
1394
    unprocessed_awbs = {}
1395
    for awb, amount in collected_amount_map.iteritems():
1396
        try:
1397
            order = Order.query.filter_by(airwaybill_no=awb).one()
1398
        except NoResultFound:
1399
            unprocessed_awbs[awb] = "No order was found for the given AWB: " + awb
1400
            continue
1401
        except MultipleResultsFound:
1402
            unprocessed_awbs[awb] = "Multiple orders were found for the given AWB:" + awb
1403
            continue
1404
 
1405
        if order.cod_reconciliation_timestamp:
1406
            #This order has been processed already! This may be a re-run. Let's allow other orders to be processed.
1407
            continue
1408
 
1409
        if order.status < OrderStatus.DELIVERY_SUCCESS:
1410
            #Order has not been delivered yet. No way we can receive the payment.
1411
            unprocessed_awbs[awb] = "Payment has been received for order: " + str(order.id) + " before delivery reconciliation"
1412
            continue
1413
 
1414
        if amount != order.total_amount:
1415
            #Received amount is less than or more than the order amount. Mustn't let the user proceed.
1416
            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)
1417
            continue
1418
 
1419
        try:
1420
            payment_client = PaymentClient().get_client()
1421
            payment_client.partiallyCapturePayment(order.transaction.id, amount, xferBy, xferTxnId, xferDate)
1422
        except Exception:
1423
            unprocessed_awbs[awb] = "We were unable to partially capture payment for order id " + str(order.id) + ", AWB: " + awb
1424
            continue
1425
 
1426
        #Payment has been recorded now. We can update the order peacefully.
1427
        order.cod_reconciliation_timestamp = datetime.datetime.now()
1428
        session.commit()
3469 chandransh 1429
 
3956 chandransh 1430
    return unprocessed_awbs
4008 mandeep.dh 1431
 
1432
def get_transactions_requiring_extra_processing(category):
4065 mandeep.dh 1433
    """
1434
    Returns the list of transaction ids that require some extra processing and
1435
    which belong to a particular category. This is currently used by CRM
1436
    application. If no such transaction ids are present, it returns an empty list.
1437
    """
1438
    query = TransactionRequiringExtraProcessing.query
4008 mandeep.dh 1439
 
4065 mandeep.dh 1440
    if category is not None:
1441
        query = query.filter_by(category = ExtraTransactionProcessingType._VALUES_TO_NAMES.get(category))
4008 mandeep.dh 1442
 
4065 mandeep.dh 1443
    return [a.transaction_id for a in query.all()]
4008 mandeep.dh 1444
 
1445
def mark_transaction_as_processed(transactionId, category):
4065 mandeep.dh 1446
    """
1447
    Marks a particular transaction as processed for a particular cateogory.
1448
    It essentially deletes the transaction id record for a particular
1449
    processing type category (if present) from DB.
1450
    This is currently used by CRM application.
1451
    """
4008 mandeep.dh 1452
    TransactionRequiringExtraProcessing.query.filter_by(transaction_id = transactionId).filter_by(category = ExtraTransactionProcessingType._VALUES_TO_NAMES.get(category)).delete()
1453
    session.commit()
1454
 
4018 chandransh 1455
def get_item_wise_risky_orders_count():
1456
    """
1457
    Returns a map containing the number of risky orders keyed by item id. A risky order
1458
    is defined as one whose shipping date is about to expire.
1459
    """
1460
    item_wise_risky_orders_count = {}
4019 chandransh 1461
    shipping_cutoff_time = (datetime.datetime.now() + datetime.timedelta(days = 1)).replace(hour=PREPAID_SHIPPING_CUTOFF_TIME, minute=0, second=0)
4018 chandransh 1462
    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()
1463
    for order in orders:
1464
        for lineitem in order.lineitems:
1465
            quantity = lineitem.quantity
1466
            if item_wise_risky_orders_count.has_key(lineitem.item_id):
1467
                quantity = quantity + item_wise_risky_orders_count[lineitem.item_id]
1468
 
1469
            item_wise_risky_orders_count[lineitem.item_id] = quantity
1470
    return item_wise_risky_orders_count
1471
 
766 rajveer 1472
def close_session():
1473
    if session.is_active:
1474
        print "session is active. closing it."
2783 chandransh 1475
        session.close()
3376 rajveer 1476
 
1477
def is_alive():
1478
    try:
1479
        session.query(Transaction.id).limit(1).one()
1480
        return True
1481
    except:
1482
        return False
3413 chandransh 1483