Subversion Repositories SmartDukaan

Rev

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

Rev Author Line No. Line
104 ashish 1
'''
2
Created on 29-Mar-2010
3
 
2536 chandransh 4
@author: Chandranshu
104 ashish 5
'''
2536 chandransh 6
 
4369 rajveer 7
from datetime import date, timedelta
2536 chandransh 8
from elixir import *
3499 mandeep.dh 9
from reportlab.lib.units import inch
2536 chandransh 10
from reportlab.pdfgen.canvas import Canvas
11
from reportlab.rl_config import defaultPageSize
3499 mandeep.dh 12
from shop2020.clients.CatalogClient import CatalogClient
13
from shop2020.clients.HelperClient import HelperClient
14
from shop2020.clients.LogisticsClient import LogisticsClient
2747 chandransh 15
from shop2020.clients.PaymentClient import PaymentClient
3499 mandeep.dh 16
from shop2020.clients.UserClient import UserClient
17
from shop2020.clients.WarehouseClient import WarehouseClient
18
from shop2020.model.v1 import order
19
from shop2020.model.v1.order.impl.DataService import Transaction, LineItem, \
4435 mandeep.dh 20
    Order, BatchNoGenerator, InvoiceIDGenerator, TransactionRequiringExtraProcessing, \
4905 varun.gupt 21
    OrderInventory, Alert, PaymentSettlement, EBSSettlementSummary
2687 chandransh 22
from shop2020.model.v1.order.impl.model.ReturnOrder import ReturnOrder
4541 mandeep.dh 23
from shop2020.thriftpy.generic.ttypes import ExceptionType
3499 mandeep.dh 24
from shop2020.thriftpy.logistics.ttypes import DeliveryType
4435 mandeep.dh 25
from shop2020.thriftpy.model.v1.catalog.ttypes import BillingType, \
5110 mandeep.dh 26
    InventoryServiceException, WarehouseType, ItemType, InventoryType
4435 mandeep.dh 27
from shop2020.thriftpy.model.v1.order.ttypes import TransactionServiceException, \
28
    TransactionStatus, OrderStatus, DelayReason, ExtraTransactionProcessingType, \
4815 phani.kuma 29
    HotspotAction, TimeoutSummary, OrderStatusGroups
4421 mandeep.dh 30
from shop2020.thriftpy.payments.ttypes import PaymentException
5110 mandeep.dh 31
from shop2020.thriftpy.warehouse.ttypes import ScanType, \
32
    WarehouseServiceException
3499 mandeep.dh 33
from shop2020.utils.EmailAttachmentSender import mail, get_attachment_part
855 rajveer 34
from shop2020.utils.Utils import to_py_date, to_java_date
4008 mandeep.dh 35
from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
3499 mandeep.dh 36
from sqlalchemy.sql import func
37
from sqlalchemy.sql.expression import and_, or_, desc, not_, distinct
38
from string import Template
39
from textwrap import dedent
40
import datetime
41
import logging
42
import os
4421 mandeep.dh 43
import sys
4435 mandeep.dh 44
import time
4421 mandeep.dh 45
import traceback
3499 mandeep.dh 46
logging.basicConfig(level=logging.DEBUG)
104 ashish 47
 
3499 mandeep.dh 48
 
4763 rajveer 49
PREPAID_SHIPPING_CUTOFF_TIME = 15
4019 chandransh 50
COD_SHIPPING_CUTOFF_TIME = 12
3499 mandeep.dh 51
 
2819 chandransh 52
PAGE_HEIGHT=defaultPageSize[1]
53
PAGE_WIDTH=defaultPageSize[0]
54
 
4763 rajveer 55
billedOrdersColorMap = {}
56
 
3499 mandeep.dh 57
ORDER_STATUS_TO_USER_TRUST_LEVEL_DELTA_DICT = {
4873 mandeep.dh 58
        OrderStatus.RTO_RESHIPPED    :  3,
59
        OrderStatus.RTO_IN_TRANSIT   : -5,
60
        OrderStatus.DELIVERY_SUCCESS :  1,
61
        OrderStatus.DOA_CERT_INVALID : -5
3499 mandeep.dh 62
}
63
 
104 ashish 64
def get_new_transaction():
65
    transaction = Transaction()
66
    transaction.createdOn = datetime.datetime.now()
738 chandransh 67
    transaction.status = TransactionStatus.INIT
104 ashish 68
    transaction.status_message = "New transaction"
483 rajveer 69
    return transaction
70
 
71
def create_order(t_order):
72
    order = Order()
73
    if t_order.warehouse_id:
74
        order.warehouse_id = t_order.warehouse_id
509 rajveer 75
    if t_order.logistics_provider_id:    
483 rajveer 76
        order.logistics_provider_id = t_order.logistics_provider_id
77
        order.airwaybill_no = t_order.airwaybill_no
78
        order.tracking_id = t_order.tracking_id
4009 chandransh 79
    if t_order.expected_shipping_time:
4019 chandransh 80
        order.expected_shipping_time = to_py_date(t_order.expected_shipping_time).replace(hour=PREPAID_SHIPPING_CUTOFF_TIME, minute=0, second=0)
4102 chandransh 81
        order.promised_shipping_time = order.expected_shipping_time
4009 chandransh 82
    if t_order.expected_delivery_time:
483 rajveer 83
        order.expected_delivery_time = to_py_date(t_order.expected_delivery_time)
4102 chandransh 84
        order.promised_delivery_time = order.expected_delivery_time
483 rajveer 85
    if t_order.customer_id:    
86
        order.customer_id = t_order.customer_id
87
        order.customer_name = t_order.customer_name
860 rajveer 88
        order.customer_city = t_order.customer_city
89
        order.customer_state = t_order.customer_state
483 rajveer 90
        order.customer_mobilenumber = t_order.customer_mobilenumber
91
        order.customer_pincode = t_order.customer_pincode
738 chandransh 92
        order.customer_address1 = t_order.customer_address1
93
        order.customer_address2 = t_order.customer_address2
483 rajveer 94
        order.customer_email = t_order.customer_email
95
    #new status and status description to be added    
716 rajveer 96
    order.status = t_order.status  
483 rajveer 97
    order.statusDescription = t_order.statusDescription
98
    order.total_amount = t_order.total_amount
99
    order.total_weight = t_order.total_weight
100
    if t_order.created_timestamp:
101
        order.created_timestamp = to_py_date(t_order.created_timestamp)
102
    else:
685 chandransh 103
        order.created_timestamp = datetime.datetime.now()
483 rajveer 104
    return order
105
 
106
def create_transaction(t_transaction):
107
    t_orders = t_transaction.orders
108
    if not t_orders:
109
        raise TransactionServiceException(101, "Orders missing from the transaction")
110
    transaction = get_new_transaction()
111
    transaction.customer_id = t_transaction.customer_id 
112
    transaction.shopping_cart_id = t_transaction.shoppingCartid
2219 varun.gupt 113
    transaction.coupon_code = t_transaction.coupon_code
2815 vikas 114
    transaction.session_source = t_transaction.sessionSource
115
    transaction.session_start_time = to_py_date(t_transaction.sessionStartTime)
3858 vikas 116
    transaction.first_source = t_transaction.firstSource
117
    transaction.first_source_start_time = to_py_date(t_transaction.firstSourceTime)
483 rajveer 118
 
119
    for t_order in t_orders:
120
        order = create_order(t_order)
121
        order.transaction = transaction 
122
        for line_item in t_order.lineitems:
123
            litem = LineItem()
716 rajveer 124
            litem.item_id = line_item.item_id
963 chandransh 125
            litem.productGroup = line_item.productGroup
483 rajveer 126
            litem.brand = line_item.brand
127
            if line_item.model_number:
128
                litem.model_number = line_item.model_number
129
            if line_item.model_name:    
130
                litem.model_name = line_item.model_name
908 chandransh 131
            if line_item.color:
132
                litem.color = line_item.color
483 rajveer 133
            if line_item.extra_info:
134
                litem.extra_info = line_item.extra_info
135
            litem.quantity = line_item.quantity
136
            litem.unit_price = line_item.unit_price
137
            litem.unit_weight = line_item.unit_weight
138
            litem.total_price = line_item.total_price
139
            litem.total_weight = line_item.total_weight
4283 anupam.sin 140
            '''litem.transfer_price = line_item.transfer_price'''
4172 rajveer 141
            litem.dealText = line_item.dealText
4295 varun.gupt 142
            litem.warranty_expiry_timestamp = to_py_date(line_item.warrantry_expiry_timestamp)
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"
4247 rajveer 193
    elif new_status == TransactionStatus.AUTHORIZED or new_status == TransactionStatus.FLAGGED:
690 chandransh 194
        for order in transaction.orders:
4247 rajveer 195
            if new_status == TransactionStatus.AUTHORIZED:
196
                order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
197
                order.statusDescription = "Submitted to warehouse"
198
            elif new_status == TransactionStatus.FLAGGED:
199
                order.status = OrderStatus.PAYMENT_FLAGGED
200
                order.statusDescription = "Payment flagged by gateway"
3092 chandransh 201
            order.cod = False
743 rajveer 202
            #After we got payment success, we will set logistics info also 
203
            logistics_client = LogisticsClient().get_client()
204
            #FIXME line item is only one now. If multiple will come, need to fix.
871 chandransh 205
            item_id = order.lineitems[0].item_id
3044 chandransh 206
            logistics_info = logistics_client.getLogisticsInfo(order.customer_pincode, item_id, DeliveryType.PREPAID)
743 rajveer 207
 
1730 ankur.sing 208
            current_time = datetime.datetime.now()
209
            logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
4009 chandransh 210
            logistics_info.shippingTime = adjust_delivery_time(current_time, logistics_info.shippingTime)
5110 mandeep.dh 211
 
743 rajveer 212
            order.warehouse_id = logistics_info.warehouseId
5110 mandeep.dh 213
            order.fulfilmentWarehouseId = logistics_info.fulfilmentWarehouseId
743 rajveer 214
            order.logistics_provider_id = logistics_info.providerId
215
            order.airwaybill_no = logistics_info.airway_billno
216
            order.tracking_id = order.airwaybill_no
4019 chandransh 217
            order.expected_shipping_time = (current_time + datetime.timedelta(days=logistics_info.shippingTime)).replace(hour=PREPAID_SHIPPING_CUTOFF_TIME, minute=0, second=0)
4102 chandransh 218
            order.promised_shipping_time = order.expected_shipping_time
5165 rajveer 219
            order.expected_delivery_time = (current_time + datetime.timedelta(days=logistics_info.deliveryTime)).replace(hour=PREPAID_SHIPPING_CUTOFF_TIME, minute=0, second=0)
3986 chandransh 220
            order.promised_delivery_time = order.expected_delivery_time 
871 chandransh 221
 
3133 rajveer 222
            catalog_client = CatalogClient().get_client()
5110 mandeep.dh 223
            catalog_client.reserveItemInWarehouse(item_id, logistics_info.fulfilmentWarehouseId, order.lineitems[0].quantity)
1351 varun.gupt 224
 
4316 anupam.sin 225
            try:
226
                item_pricing = catalog_client.getItemPricing(item_id, -1)
227
                order.lineitems[0].transfer_price = item_pricing.transferPrice
228
            except:
229
                print "Not able to get transfer price. Skipping"
3064 chandransh 230
    elif new_status == TransactionStatus.COD_IN_PROCESS:
231
        for order in transaction.orders:
4662 rajveer 232
            order.status = OrderStatus.COD_VERIFICATION_PENDING
3064 chandransh 233
            order.statusDescription = "Verification Pending"
234
            order.cod = True
235
            #After we got payment success, we will set logistics info also 
236
            logistics_client = LogisticsClient().get_client()
237
            #FIXME line item is only one now. If multiple will come, need to fix.
238
            item_id = order.lineitems[0].item_id
239
            logistics_info = logistics_client.getLogisticsInfo(order.customer_pincode, item_id, DeliveryType.COD)
240
 
241
            current_time = datetime.datetime.now()
242
            logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
4009 chandransh 243
            logistics_info.shippingTime = adjust_delivery_time(current_time, logistics_info.shippingTime)
3064 chandransh 244
 
245
            order.warehouse_id = logistics_info.warehouseId
5110 mandeep.dh 246
            order.fulfilmentWarehouseId = logistics_info.fulfilmentWarehouseId
3064 chandransh 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
5165 rajveer 252
            order.expected_delivery_time = (current_time + datetime.timedelta(days=logistics_info.deliveryTime)).replace(hour=COD_SHIPPING_CUTOFF_TIME, minute=0, second=0)
3986 chandransh 253
            order.promised_delivery_time = order.expected_delivery_time
3064 chandransh 254
 
3133 rajveer 255
            catalog_client = CatalogClient().get_client()
5110 mandeep.dh 256
            catalog_client.reserveItemInWarehouse(item_id, logistics_info.fulfilmentWarehouseId, order.lineitems[0].quantity)
3064 chandransh 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
def adjust_delivery_time(start_time, delivery_days):
296
    '''
297
    Returns the actual no. of days which will pass while 'delivery_days'
298
    no. of business days will pass since 'order_time'. 
299
    '''
300
    start_date = start_time.date()
301
    end_date = start_date + datetime.timedelta(days = delivery_days)
302
    holidays = __get_holidays(start_time)
1730 ankur.sing 303
 
3994 chandransh 304
    while start_date <= end_date:
305
        if start_date.weekday() == 6 or start_date in holidays:
1730 ankur.sing 306
            delivery_days = delivery_days + 1
3994 chandransh 307
            end_date = end_date + datetime.timedelta(days = 1)
4088 chandransh 308
        start_date = start_date + datetime.timedelta(days = 1)
3994 chandransh 309
 
1730 ankur.sing 310
    return delivery_days
311
 
1398 varun.gupt 312
def enqueue_transaction_info_email(transaction_id):
1262 varun.gupt 313
    transaction = get_transaction(transaction_id)
314
 
315
    html_header = """
316
<html>
317
<body>
318
<div>
319
    <p>
320
        Hello,<br /><br />
1742 rajveer 321
        Thanks for placing order with us. Following are the details of your order:
1262 varun.gupt 322
    </p>
323
    <div>
324
        Order Date: $order_date
1569 varun.gupt 325
    </div>
1262 varun.gupt 326
    <div>
327
        <table>
1569 varun.gupt 328
        <tr><td colspan="5"><hr /></td></tr>
329
        <tr><td colspan="5" align="left"><b>Order Details</b></td></tr>
330
        <tr><td colspan="5"><hr /></td></tr>
1262 varun.gupt 331
        <tr>
2050 varun.gupt 332
            <th width="100">Order No.</th>
333
            <th>Product</th>
334
            <th width="100">Quantity</th>
335
            <th width="100">Unit Price</th>
336
            <th width="100">Amount</th>
1262 varun.gupt 337
        </tr>
338
    """
1398 varun.gupt 339
    user_email = ""
1262 varun.gupt 340
    total_amount = 0.0
341
    html_table = ""
1569 varun.gupt 342
    order_date = datetime.datetime.now()
1262 varun.gupt 343
 
344
    for order in transaction.orders:
345
        order_date = order.created_timestamp
1398 varun.gupt 346
        user_email = order.customer_email
1569 varun.gupt 347
        html_tr = "<tr><td align='center'>" + str(order.id) + "</td>"
1262 varun.gupt 348
 
349
        for lineitem in order.lineitems:
2050 varun.gupt 350
            lineitem_total_price = round(lineitem.total_price, 2)
351
 
1276 chandransh 352
            html_tr += "<td>" + str(lineitem) + "</td>"
2050 varun.gupt 353
            html_tr += "<td align='center'>" + ("%.0f" % lineitem.quantity) + "</td>"
354
            html_tr += "<td align='center'> Rs. " + ("%.2f" % lineitem.unit_price) + "</td>"
355
            html_tr += "<td align='center'> Rs. " + ("%.2f" % lineitem_total_price) + "</td></tr>"
356
            total_amount += lineitem_total_price
1262 varun.gupt 357
            html_table += html_tr
2050 varun.gupt 358
 
1262 varun.gupt 359
    html_footer = """
360
        <tr><td colspan=5>&nbsp;</td></tr>
1565 varun.gupt 361
        <tr><td colspan=5><hr /></td></tr>
1262 varun.gupt 362
        <tr>
363
            <td colspan=4>Total Amount</td>
2050 varun.gupt 364
            <td> Rs. $total_amount</td>
1262 varun.gupt 365
        </tr>
366
        </table>
1569 varun.gupt 367
    </div>
1262 varun.gupt 368
    <p>
369
        Best Wishes,<br />
370
        Saholic Team
371
    </p>
372
</div>
373
</body>
374
</html>
375
    """
1398 varun.gupt 376
 
1569 varun.gupt 377
    dt = datetime.datetime.strptime(str(order_date), "%Y-%m-%d %H:%M:%S")
1565 varun.gupt 378
    formated_order_date = dt.strftime("%A, %d. %B %Y %I:%M%p")
379
 
1262 varun.gupt 380
    email_header = Template(html_header).substitute(dict(order_date = formated_order_date))
2050 varun.gupt 381
    email_footer = Template(html_footer).substitute(dict(total_amount = "%.2f" % total_amount))
1262 varun.gupt 382
 
1351 varun.gupt 383
    try:
384
        helper_client = HelperClient().get_client()
1398 varun.gupt 385
        helper_client.saveUserEmailForSending(user_email, "", "Saholic - Order Details", email_header + html_table + email_footer, str(transaction_id), "TransactionInfo")
1351 varun.gupt 386
        return True
387
    except Exception as e:
388
        print e
389
        return False
1262 varun.gupt 390
 
483 rajveer 391
def get_order(order_id):
392
    order = Order.get_by(id=order_id)
393
    if not order:
394
        raise TransactionServiceException(108, "no such order")
395
 
396
    return order
397
 
4999 phani.kuma 398
def get_order_list(order_ids):
399
    orders = Order.query.filter(Order.id.in_(tuple(order_ids)))
400
    return orders
401
 
3014 chandransh 402
def get_orders_for_customer(customer_id, from_date, to_date, statuses):
483 rajveer 403
    if not customer_id:
404
        raise TransactionServiceException(101, "bad customer id")
405
    query = Order.query.filter(Order.customer_id == customer_id)
3014 chandransh 406
    if statuses:
407
        query = query.filter(Order.status.in_(tuple(statuses)))
483 rajveer 408
    if from_date:
409
        query = query.filter(Order.created_timestamp >from_date)
410
    if to_date:
411
        query = query.filter(Order.created_timestamp < to_date)
412
    return query.all()
413
 
1528 ankur.sing 414
def get_order_for_customer(order_id, customer_id):
415
    if not customer_id:
416
        raise TransactionServiceException(101, "bad customer id")
417
    order = get_order(order_id)
418
    if order.customer_id != customer_id:
419
        raise TransactionServiceException(108, "order: " + str(order_id) + " does not belong to customer: " + str(customer_id))
420
    return order
421
 
4801 anupam.sin 422
def get_all_orders(statuses, from_date, to_date, warehouse_id):
423
    if not len(statuses):
424
        raise TransactionServiceException(101, "Status list is empty")
425
    query = Order.query.filter(Order.status.in_(statuses))
426
    if warehouse_id:
427
        query = query.filter(Order.warehouse_id == warehouse_id)
428
        #raise TransactionServiceException(101, "bad warehouse id")
483 rajveer 429
    if from_date:
430
        query = query.filter(Order.created_timestamp >from_date)
431
    if to_date:
432
        query = query.filter(Order.created_timestamp < to_date)
433
    return query.all()
434
 
4133 chandransh 435
def get_orders_in_batch(statuses=[], offset=0, limit=0, warehouse_id=None):
4296 rajveer 436
    query = Order.query
437
    if warehouse_id:
438
        query = query.filter(Order.warehouse_id == warehouse_id)
4133 chandransh 439
    if statuses:
440
        query = query.filter(Order.status.in_(statuses))
441
    query = query.offset(offset)
442
    if limit:
443
        query = query.limit(limit)
444
    return query.all()
445
 
446
def get_order_count(statuses=[], warehouse_id=None):
447
    if not warehouse_id:
448
        raise TransactionServiceException(101, "bad warehouse id")
449
    query = session.query(func.count(Order.id)).filter(Order.warehouse_id == warehouse_id)
450
    if statuses:
451
        query = query.filter(Order.status.in_(statuses))
452
    return query.scalar()
453
 
1382 varun.gupt 454
def get_returnable_orders_for_customer(customer_id, limit = None):
455
    if not customer_id:
456
        raise TransactionServiceException(101, "bad customer id")
457
 
458
    query = Order.query.filter(Order.customer_id == customer_id)
459
    query = query.filter(Order.status != OrderStatus.PAYMENT_FAILED)
460
    query = query.filter(Order.status != OrderStatus.REJECTED)
461
    query = query.filter(Order.status > OrderStatus.SHIPPED_FROM_WH)
462
    query = query.filter(or_(Order.status < OrderStatus.DELIVERY_SUCCESS, Order.delivery_timestamp < datetime.datetime.now() + datetime.timedelta(hours = 48)))
463
    orders = query.all()
464
    order_ids = [order.id for order in orders]
465
    return order_ids
466
 
467
def get_cancellable_orders_for_customer(customer_id, limit = None):
468
    if not customer_id:
469
        raise TransactionServiceException(101, "bad customer id")
4815 phani.kuma 470
    cancellableOrderStatuses = OrderStatusGroups().codCancellable
1382 varun.gupt 471
    query = Order.query.filter(Order.customer_id == customer_id)
4815 phani.kuma 472
    query = query.filter(Order.status.in_(cancellableOrderStatuses))
1382 varun.gupt 473
    orders = query.all()
474
    return [order.id for order in orders]
475
 
995 varun.gupt 476
def get_orders_by_billing_date(status, start_billing_date, end_billing_date, warehouse_id):
477
    if not warehouse_id:
478
        raise TransactionServiceException(101, "bad warehouse id")
479
 
480
    query = Order.query.filter(Order.warehouse_id == warehouse_id)
481
 
482
    if status:
483
        query = query.filter(Order.status == status)
484
 
485
    if start_billing_date:
486
        query = query.filter(Order.billing_timestamp >= start_billing_date)
487
 
488
    if end_billing_date:
489
        query = query.filter(Order.billing_timestamp <= end_billing_date)
490
 
491
    return query.all()
492
 
3451 chandransh 493
def get_orders_by_shipping_date(from_shipping_date, to_shipping_date, provider_id, warehouse_id, cod):
494
    query = Order.query.filter(Order.cod == cod)
3427 chandransh 495
 
496
    if warehouse_id and warehouse_id != -1:
497
        query = query.filter(Order.warehouse_id == warehouse_id)
498
 
499
    if provider_id and provider_id != -1:
500
        query = query.filter(Order.logistics_provider_id == provider_id)
501
 
502
    if from_shipping_date:
503
        query = query.filter(Order.shipping_timestamp >= from_shipping_date)
504
 
505
    if to_shipping_date:
506
        query = query.filter(Order.shipping_timestamp <= to_shipping_date)
507
 
508
    query = query.order_by(Order.airwaybill_no)
509
 
510
    return query.all()
511
 
1528 ankur.sing 512
def get_orders_for_transaction(transaction_id, customer_id):
513
    orders = Order.query.filter_by(transaction_id=transaction_id, customer_id=customer_id).all()
514
 
1208 chandransh 515
    if not orders:
516
        raise TransactionServiceException(101, "No order for the transaction")
517
    return orders
518
 
1405 ankur.sing 519
def get_undelivered_orders(provider_id, warehouse_id):
520
    query = Order.query
521
    if provider_id != -1:
522
        query = query.filter_by(Order.logistics_provider_id == provider_id)
523
    if warehouse_id != -1:
524
        query = query.filter(Order.warehouse_id == warehouse_id)
525
    query = query.filter(and_(Order.status != OrderStatus.DELIVERY_SUCCESS, Order.status != OrderStatus.FAILED, \
526
                              Order.status > OrderStatus.SHIPPED_FROM_WH))
1479 ankur.sing 527
    #Get last midnight time instead of current time as courier company would have sent the 
528
    #delivery records updated at least till midnight and not by the current time.
529
    time_format = "%Y-%m-%d %H:%M:%S.%f"
530
    t = time.strptime(str(datetime.datetime.now()), time_format)
531
    midnightTime = datetime.datetime(*t[:3])
532
    query = query.filter(Order.expected_delivery_time < midnightTime)
1405 ankur.sing 533
    orders = query.all()
534
    return orders
535
 
1208 chandransh 536
def get_line_items_for_order(order_id):
537
    query = LineItem.query.filter(LineItem.order_id == order_id)
538
    return query.all()
539
 
483 rajveer 540
def change_order_status(self, orderId, status, description):
541
    order = get_order(orderId)
542
    order.status = status
543
    order.statusDescription = description
544
    session.commit()
3578 mandeep.dh 545
    update_trust_level(order)
546
    return True
3499 mandeep.dh 547
 
3578 mandeep.dh 548
def update_trust_level(order):
3530 mandeep.dh 549
    try:
3578 mandeep.dh 550
        trust_level_delta = 0
551
        if order.cod == True:
552
            trust_level_delta = ORDER_STATUS_TO_USER_TRUST_LEVEL_DELTA_DICT.get(order.status, 0)
553
 
3530 mandeep.dh 554
        if (trust_level_delta != 0):
555
            user_client = UserClient().get_client()
556
            user_client.increaseTrustLevel(order.customer_id, trust_level_delta)
557
    except Exception as e:
558
        print e
3499 mandeep.dh 559
 
483 rajveer 560
    return True
3064 chandransh 561
 
562
def verify_order(self, orderId):
563
    logging.info("Verifying order no: " + str(orderId))
564
    order = get_order(orderId)
4662 rajveer 565
    if order.status == OrderStatus.COD_VERIFICATION_PENDING:
3064 chandransh 566
        order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
567
        order.statusDescription = "Submitted for processing"
568
        order.verification_timestamp = datetime.datetime.now()
569
        session.commit()
570
        logging.info("Successfully verified order no: " + str(orderId))
571
        return True
572
    else:
573
        logging.warning("Verify called for order no." + str(orderId) +" which is not in verification pending state");
574
        return False
575
 
4285 rajveer 576
def accept_order(orderId):
3064 chandransh 577
    logging.info("Accepting order no: " + str(orderId))
921 rajveer 578
    order = get_order(orderId)
5110 mandeep.dh 579
    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, OrderStatus.CAPTURE_IN_PROCESS]:
3064 chandransh 580
        if not order.cod:
581
            if order.transaction.status == TransactionStatus.AUTHORIZED:
4421 mandeep.dh 582
                __capture_txn(order)
3010 chandransh 583
        order.status = OrderStatus.ACCEPTED
584
        order.statusDescription = "Order Accepted"
585
        order.accepted_timestamp = datetime.datetime.now()
586
        session.commit()
3064 chandransh 587
        logging.info("Successfully accepted the order no.:" + str(orderId))
3010 chandransh 588
        return True
589
    else:
3064 chandransh 590
        logging.warning("Accept called for the unacceptable order: " + str(orderId))
3010 chandransh 591
        return False
921 rajveer 592
 
4421 mandeep.dh 593
def __capture_txn(order):
594
    txnId = order.transaction_id
3010 chandransh 595
    logging.info("Capturing payment for merchant txn:" + str(txnId))
4421 mandeep.dh 596
    try:
597
        payment_client = PaymentClient().get_client()
598
        capture_result = payment_client.capturePayment(txnId)
599
        if capture_result:
600
            logging.info("Successfully captured payment for merchant txn:" + str(txnId))
601
            change_transaction_status(txnId, TransactionStatus.IN_PROCESS, "Payment received")
602
        else:
603
            raise TransactionServiceException(115, "Payment capture failed.")
604
    except PaymentException as e:
605
        if e.error_code == 106:
606
            order.status = OrderStatus.CAPTURE_IN_PROCESS
607
            session.commit()
608
            raise TransactionServiceException(122, "Unable to capture payment due to connection issue.")
609
        else:
610
            raise TransactionServiceException(115, "Payment capture failed.")
3010 chandransh 611
 
5110 mandeep.dh 612
def add_billing_details(orderId, invoice_number, serialNumber, itemNumber, billedBy, jacketNumber, billingType, fulfilmentWarehouseId, authorize):
4285 rajveer 613
    if jacketNumber is None or jacketNumber <= 0:
2783 chandransh 614
        raise TransactionServiceException(110, "Invalid jacket number")
615
 
4285 rajveer 616
    if billedBy is None or billedBy.strip() == "":
2783 chandransh 617
        raise TransactionServiceException(110, "Invalid Biller")
618
 
1149 chandransh 619
    order = Order.get_by(id=orderId)
620
    if not order:
2783 chandransh 621
        raise TransactionServiceException(101, "No order found for the given order id" + str(orderId))
5110 mandeep.dh 622
 
623
    lineitem = order.lineitems[0]
624
    item_id = lineitem.item_id
625
    catalog_client = CatalogClient().get_client()
626
    item = catalog_client.getItem(item_id)
4283 anupam.sin 627
    if order.status == OrderStatus.ACCEPTED:
4285 rajveer 628
        order.jacket_number = jacketNumber
629
        if billingType == BillingType.OURS:
630
            if itemNumber is None or itemNumber.strip() == "":
4283 anupam.sin 631
                raise TransactionServiceException(110, "Invalid item number")
632
 
633
            order.invoice_number = get_next_invoice_number()
5110 mandeep.dh 634
            if ItemType.SERIALIZED == item.type and not serialNumber:
635
                raise TransactionServiceException(110, "No Serial Number supplied")
4285 rajveer 636
            lineitem.item_number = itemNumber
4658 mandeep.dh 637
            if serialNumber:
638
                lineitem.serial_number = serialNumber
4283 anupam.sin 639
        else:
640
            order.invoice_number = invoice_number
4763 rajveer 641
            # In case of hotspot billing, we should try to verify that color billed in ETP is same as color in order.
642
            if billedOrdersColorMap.has_key(orderId):
643
                etpColor = billedOrdersColorMap.get(orderId)
644
                ourColor = order.lineitems[0].color
4781 rajveer 645
                if ourColor and etpColor != ourColor and not authorize:
4763 rajveer 646
                    raise TransactionServiceException(777, "ETP color: " + etpColor + " and Order color: " + ourColor)
647
                else:
648
                    billedOrdersColorMap.pop(orderId)
4283 anupam.sin 649
 
2842 chandransh 650
        order.status = OrderStatus.BILLED
651
        order.statusDescription = "Order Billed"
652
        order.billing_timestamp = datetime.datetime.now()
4285 rajveer 653
        order.billed_by = billedBy
4435 mandeep.dh 654
 
655
        # Not letting the billing process fail in cases where we are unable to 
656
        # fill in transfer price
657
        try:
658
            catalog_client = CatalogClient().get_client()
5110 mandeep.dh 659
            warehouse = catalog_client.getWarehouse(fulfilmentWarehouseId)
660
            item_pricing = catalog_client.getItemPricing(item_id, warehouse.vendor.id)
661
            lineitem.transfer_price = item_pricing.transferPrice
662
            order.vendorId = warehouse.vendor.id
4435 mandeep.dh 663
        except InventoryServiceException as e:
664
            print sys.exc_info()[0]
665
            print e.message
5110 mandeep.dh 666
            raise TransactionServiceException(110, 'Transfer price missing for itemId: ' + str(item_id) + ' and vendor: ' + str(warehouse.vendor.id))
4435 mandeep.dh 667
 
5110 mandeep.dh 668
        # For OUR warehouse, we need to scan out items for every billed order
669
        if billingType == BillingType.OURS:
670
            if ItemType.SERIALIZED == item.type:
4773 mandeep.dh 671
                try:
672
                    warehouse_client = WarehouseClient().get_client()
673
                    inventoryItem = warehouse_client.getInventoryItem(serialNumber)
674
                    if (inventoryItem.itemId != item_id):
5110 mandeep.dh 675
                        catalog_client = CatalogClient().get_client()
4773 mandeep.dh 676
                        item = catalog_client.getItem(inventoryItem.itemId)
4814 rajveer 677
                        scanItemString = " ".join([str(item.brand), str(item.modelName), str(item.modelNumber), str(item.color)])
678
                        lineItemString = " ".join([str(lineitem.brand), str(lineitem.model_name), str(lineitem.model_number), str(lineitem.color)])
4773 mandeep.dh 679
                        raise TransactionServiceException(110, 'Trying to scan ' + scanItemString + ' instead of ' + lineItemString)
5110 mandeep.dh 680
                    print order.fulfilmentWarehouseId, lineitem.quantity, order.warehouse_id
681
                    inventoryItem = warehouse_client.scanSerializedItemForOrder(serialNumber, ScanType.SALE, orderId, order.fulfilmentWarehouseId, lineitem.quantity, order.warehouse_id)
4773 mandeep.dh 682
                    lineitem.transfer_price = inventoryItem.unitPrice
683
                    order.vendorId = inventoryItem.supplierId
4887 mandeep.dh 684
                    catalog_client = CatalogClient().get_client()
5110 mandeep.dh 685
                    warehouse = catalog_client.getWarehouse(order.fulfilmentWarehouseId)
686
                    # Fetching GOOD w/h corresponding to the virtual one here
687
                    if warehouse.billingWarehouseId is None:
688
                        warehouse = catalog_client.getWarehouses(None, InventoryType.GOOD, warehouse.vendor.id, order.warehouse_id, 0)[0]
689
                        order.fulfilmentWarehouseId = warehouse.id
4773 mandeep.dh 690
                except WarehouseServiceException as e:
691
                    print sys.exc_info()[0]
692
                    print 'Could not scan out orders due to: ' + e.message
5110 mandeep.dh 693
                    raise TransactionServiceException(110, e.message)
5123 mandeep.dh 694
        else:
695
            if not warehouse.isAvailabilityMonitored:
696
                catalog_client = CatalogClient().get_client()
697
                catalog_client.addInventory(item.id, warehouse.id, -1 * lineitem.quantity)
4365 mandeep.dh 698
 
5110 mandeep.dh 699
        __update_inventory_reservation(order)
4541 mandeep.dh 700
        session.commit()
4283 anupam.sin 701
        return True
702
    else:
703
        return False
1149 chandransh 704
 
4763 rajveer 705
def add_invoice_number(orderId, invoiceNumber, color):
4579 rajveer 706
    order = Order.get_by(id=orderId)
707
    if not order:
708
        raise TransactionServiceException(101, "No order found for the given order id" + str(orderId))
709
 
710
    if order.status == OrderStatus.ACCEPTED:
711
        order.invoice_number = invoiceNumber
4767 rajveer 712
        if color:
713
            billedOrdersColorMap[orderId] = color;
4579 rajveer 714
    session.commit()
715
 
1220 chandransh 716
def batch_orders(warehouseId):
717
    if not warehouseId:
718
        raise TransactionServiceException(101, "bad warehouse id")
1225 chandransh 719
 
720
    batchno_generator = BatchNoGenerator()
721
    session.commit()
1220 chandransh 722
    query = Order.query.filter_by(warehouse_id=warehouseId)
4592 mandeep.dh 723
    query = query.filter(Order.status == OrderStatus.LOW_INV_PO_RAISED)
1220 chandransh 724
    query = query.order_by(Order.created_timestamp)
725
    pending_orders = query.all()
1225 chandransh 726
 
1220 chandransh 727
    serial_no = 1
728
    for order in pending_orders:
1276 chandransh 729
        order.batchNo = batchno_generator.id
1220 chandransh 730
        order.serialNo = serial_no
731
        serial_no += 1
732
    session.commit() 
733
    pending_orders = query.all()
734
    return pending_orders
735
 
736
def order_outofstock(orderId):
1911 chandransh 737
    '''
738
    Mark order as out of stock
739
    '''
1220 chandransh 740
    order = get_order(orderId)
741
    order.status = OrderStatus.INVENTORY_LOW
742
    order.statusDescription = "Low Inventory"
743
    order.outofstock_timestamp = datetime.datetime.now()
744
    session.commit()
745
    return True
746
 
4789 rajveer 747
def mark_orders_as_shipped_from_warehouse(warehouseId, providerId, cod, orderIds):
4410 rajveer 748
    try:
749
        current_timestamp = datetime.datetime.now()
4789 rajveer 750
        orders = Order.query.filter_by(warehouse_id = warehouseId, logistics_provider_id = providerId, status = OrderStatus.BILLED, cod = cod).all()
4410 rajveer 751
        for order in orders:
4789 rajveer 752
            if order.id in orderIds:
753
                order.status = OrderStatus.SHIPPED_FROM_WH
754
                order.statusDescription = "Order shipped from warehouse"
755
                order.shipping_timestamp = current_timestamp
759 chandransh 756
        session.commit()
4749 varun.gupt 757
 
758
        try:
759
            enqueue_shipping_confirmation_email(orders)
760
        except Exception as e:
761
            print e
762
 
759 chandransh 763
        return True
764
    except:
765
        return False
4410 rajveer 766
 
1113 chandransh 767
def mark_orders_as_picked_up(provider_id, pickup_details):
768
    for awb, pickup_timestamp in pickup_details.iteritems():
1135 chandransh 769
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
2684 chandransh 770
        if order == None or order.status != OrderStatus.SHIPPED_FROM_WH:
2220 chandransh 771
            #raise TransactionServiceException(102, "No order found for the awb: " + awb)
772
            continue
1113 chandransh 773
        order.status = OrderStatus.SHIPPED_TO_LOGST
774
        order.statusDescription = "Order picked up by Courier Company"
1246 chandransh 775
        order.pickup_timestamp = pickup_timestamp
1113 chandransh 776
    session.commit()
1217 chandransh 777
 
4910 phani.kuma 778
def get_orders_not_picked_up(provider_id):
1132 chandransh 779
    current_time = datetime.datetime.now()
780
    to_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
4741 phani.kuma 781
    orders_not_picked_up = Order.query.filter_by(logistics_provider_id = provider_id).filter_by(status=OrderStatus.SHIPPED_FROM_WH).filter(Order.shipping_timestamp <= to_datetime).all()
1113 chandransh 782
    return orders_not_picked_up
783
 
1132 chandransh 784
def mark_orders_as_delivered(provider_id, delivered_orders):
785
    for awb, detail in delivered_orders.iteritems():
1135 chandransh 786
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
4910 phani.kuma 787
        if order == None or order.status not in [OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST, OrderStatus.SHIPPED_TO_DESTINATION_CITY, OrderStatus.REACHED_DESTINATION_CITY, OrderStatus.FIRST_DELIVERY_ATTEMPT_MADE]:
1911 chandransh 788
            continue
789
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
1132 chandransh 790
        order.status = OrderStatus.DELIVERY_SUCCESS
791
        order.statusDescription = "Order delivered"
4910 phani.kuma 792
        timestamp, receiver = detail.split('|')
793
        if order.first_dlvyatmp_timestamp is None:
794
            order.first_dlvyatmp_timestamp = timestamp
795
        order.delivery_timestamp = timestamp
796
        order.receiver = receiver
3578 mandeep.dh 797
        update_trust_level(order)
1132 chandransh 798
    session.commit()
799
 
4712 rajveer 800
def mark_order_as_delivered(orderId, deliveryTimestamp, receiver):
801
    order = Order.get_by(id=orderId)
4982 rajveer 802
    if order == None or order.status not in [OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST, OrderStatus.SHIPPED_TO_DESTINATION_CITY, OrderStatus.REACHED_DESTINATION_CITY, OrderStatus.FIRST_DELIVERY_ATTEMPT_MADE, OrderStatus.DOA_PICKUP_REQUEST_RAISED, OrderStatus.DOA_PICKUP_CONFIRMED, OrderStatus.RET_REQUEST_RECEIVED, OrderStatus.RET_PICKUP_CONFIRMED, OrderStatus.RET_REQUEST_AUTHORIZED, OrderStatus.RET_PICKUP_REQUEST_RAISED, OrderStatus.RTO_IN_TRANSIT]:
4712 rajveer 803
        raise TransactionServiceException(101, "Either wrond order id or invalid state " + str(orderId))
804
 
4910 phani.kuma 805
    if order.status in [OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST, OrderStatus.SHIPPED_TO_DESTINATION_CITY, OrderStatus.REACHED_DESTINATION_CITY, OrderStatus.FIRST_DELIVERY_ATTEMPT_MADE, OrderStatus.RTO_IN_TRANSIT]:
4712 rajveer 806
        order.delivery_timestamp = deliveryTimestamp
807
        order.receiver = receiver
808
    order.status = OrderStatus.DELIVERY_SUCCESS
809
    order.statusDescription = "Order delivered"
810
    update_trust_level(order)
811
    session.commit()
812
 
4910 phani.kuma 813
def mark_orders_as_rto(provider_id, returned_orders):
1135 chandransh 814
    for awb, detail in returned_orders.iteritems():
815
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
4910 phani.kuma 816
        if order == None or order.status not in [OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST, OrderStatus.SHIPPED_TO_DESTINATION_CITY, OrderStatus.REACHED_DESTINATION_CITY, OrderStatus.FIRST_DELIVERY_ATTEMPT_MADE]:
2684 chandransh 817
            continue
818
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
4484 rajveer 819
        order.status = OrderStatus.RTO_IN_TRANSIT
1135 chandransh 820
        order.delivery_timestamp, reason = detail.split('|')
821
        order.statusDescription = "Order Returned to Origin:" + reason
3578 mandeep.dh 822
        update_trust_level(order)
1911 chandransh 823
    session.commit()
1135 chandransh 824
 
4910 phani.kuma 825
def get_rto_orders(provider_id):
826
    current_time = datetime.datetime.now()
827
    to_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
828
    rto_orders = Order.query.filter_by(logistics_provider_id = provider_id).filter_by(status=OrderStatus.RTO_IN_TRANSIT).filter(Order.delivery_timestamp <= to_datetime).all()
829
    return rto_orders
830
 
1246 chandransh 831
def update_non_delivery_reason(provider_id, undelivered_orders):
832
    for awb, reason in undelivered_orders.iteritems():
833
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
4920 phani.kuma 834
        if order == None or order.status == OrderStatus.FIRST_DELIVERY_ATTEMPT_MADE:
2684 chandransh 835
            continue
836
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
1246 chandransh 837
        order.statusDescription = reason
838
    session.commit()
4910 phani.kuma 839
 
840
def get_non_delivered_orders_by_courier(provider_id):
4581 phani.kuma 841
    current_time = datetime.datetime.now()
842
    today_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
843
    upto_datetime = today_datetime - datetime.timedelta(4)
4910 phani.kuma 844
    orders_not_delivered = Order.query.filter_by(logistics_provider_id = provider_id).filter(Order.status.in_((OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST, OrderStatus.SHIPPED_TO_DESTINATION_CITY, OrderStatus.REACHED_DESTINATION_CITY, OrderStatus.FIRST_DELIVERY_ATTEMPT_MADE))).filter(or_(Order.shipping_timestamp <= upto_datetime, Order.pickup_timestamp <= upto_datetime)).all()
4581 phani.kuma 845
    return orders_not_delivered
1246 chandransh 846
 
4910 phani.kuma 847
def mark_orders_as_local_connected(provider_id, local_connected_orders):
848
    for awb, timestamp in local_connected_orders.iteritems():
849
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
850
        if order == None or order.status not in [OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST]:
851
            #raise TransactionServiceException(102, "No order found for the awb: " + awb)
852
            continue
853
        order.status = OrderStatus.SHIPPED_TO_DESTINATION_CITY
854
        order.statusDescription = "Left Out of Origin City"
855
        order.local_connected_timestamp = timestamp
856
    session.commit()
857
 
858
def get_orders_not_local_connected(provider_id):
859
    current_time = datetime.datetime.now()
860
    to_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
861
    orders_pending_local_connection = Order.query.filter_by(logistics_provider_id = provider_id).filter(Order.status.in_((OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST))).filter(or_(Order.shipping_timestamp <= to_datetime, Order.pickup_timestamp <= to_datetime)).all()
862
    return orders_pending_local_connection
863
 
864
def mark_orders_as_destinationCityReached(provider_id, destination_city_reached_orders):
865
    for awb, timestamp in destination_city_reached_orders.iteritems():
866
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
867
        if order == None or order.status not in [OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST, OrderStatus.SHIPPED_TO_DESTINATION_CITY]:
868
            continue
869
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
870
        order.status = OrderStatus.REACHED_DESTINATION_CITY
871
        order.statusDescription = "Reached Destination City"
872
        order.reached_destination_timestamp = timestamp
873
    session.commit()
874
 
875
def mark_orders_as_firstDeliveryAttempted(provider_id, first_atdl_orders):
876
    for awb, detail in first_atdl_orders.iteritems():
877
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
878
        if order == None or order.status not in [OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST, OrderStatus.SHIPPED_TO_DESTINATION_CITY, OrderStatus.REACHED_DESTINATION_CITY]:
879
            continue
880
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
881
        order.status = OrderStatus.FIRST_DELIVERY_ATTEMPT_MADE
882
        order.first_dlvyatmp_timestamp, reason = detail.split('|')
883
        order.statusDescription = reason
884
    session.commit()
885
 
4783 phani.kuma 886
def get_orders_not_met_expected_delivery_date():
887
    current_time = datetime.datetime.now()
888
    today_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
4910 phani.kuma 889
    orders_not_delivered = Order.query.filter(Order.status.in_((OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST, OrderStatus.SHIPPED_TO_DESTINATION_CITY, OrderStatus.REACHED_DESTINATION_CITY))).filter(Order.expected_delivery_time <= today_datetime).all()
4783 phani.kuma 890
    return orders_not_delivered
891
 
4444 rajveer 892
def get_alerts(type, warehouseId, status, timestamp):
893
    query = Alert.query.filter(Alert.warehouseId == warehouseId)
894
    if type != -1 :
895
        query = query.filter(Alert.type == type)
896
    if status != -1 :
897
        query = query.filter(Alert.status == status)
4394 rajveer 898
    if timestamp:
899
        query = query.filter(Alert.timestamp >= to_py_date(timestamp))
4412 rajveer 900
    query = query.order_by(desc(Alert.timestamp))
483 rajveer 901
    return query.all()
902
 
4447 rajveer 903
def add_alert(type, warehouseId, description):
4394 rajveer 904
    alert = Alert()
905
    alert.type = type
906
    alert.status = 1
907
    alert.description = description
908
    alert.timestamp = datetime.datetime.now()
4447 rajveer 909
    alert.warehouseId = warehouseId
4444 rajveer 910
    session.commit()
766 rajveer 911
 
4444 rajveer 912
def mark_alerts_as_seen(warehouseId):
913
    query = Alert.query.filter(Alert.warehouseId == warehouseId).filter(Alert.status == 1)
914
    alerts = query.all()
915
    for alert in alerts:
916
        alert.status = 0    
917
    session.commit()
918
 
1596 ankur.sing 919
def get_valid_order_count():
2851 chandransh 920
    '''
921
    Returns the number of orders which we processed. The reshipped orders are not
922
    counted since there'll always be a new compensating order present.
923
    '''
4682 rajveer 924
    return Order.query.filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING).filter(not_(Order.status.in_((OrderStatus.RTO_RESHIPPED, OrderStatus.DOA_INVALID_RESHIPPED, OrderStatus.DOA_VALID_RESHIPPED, OrderStatus.COD_VERIFICATION_FAILED)))).count()
1596 ankur.sing 925
 
1627 ankur.sing 926
def get_cust_count_with_successful_txn():
2851 chandransh 927
    '''
928
    Returns the number of distinct customers who have done successful transactions.
929
    It uses the sqlalchemy func module to construct an efficient query.
930
    '''
931
    return session.query(func.count(distinct(Order.customer_id))).filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING).scalar()
1627 ankur.sing 932
 
1730 ankur.sing 933
def get_valid_orders_amount_range():
2851 chandransh 934
    '''
935
    Returns a list containing the minimum and maximum amount across all
936
    orders placed with us. No need to consider reshippped orders for min/max
937
    amount of orders.
938
    '''
939
    return session.query(func.min(Order.total_amount), func.max(Order.total_amount)).filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING).one()
1627 ankur.sing 940
 
1886 ankur.sing 941
def get_valid_orders(limit):
2851 chandransh 942
    '''
943
    Returns the last limit number of valid orders placed with us. Ignored the
944
    limit if it's passed as 0. Raises an excpetion if the supplied limit is 
945
    less than 0. 
946
    '''
947
    if limit < 0:
948
        raise TransactionServiceException(101, "Invalid argument limit " + limit)
4662 rajveer 949
    query = Order.query.filter(Order.status >= OrderStatus.COD_VERIFICATION_PENDING)
1886 ankur.sing 950
    query = query.order_by(desc(Order.created_timestamp))
2851 chandransh 951
    if limit != 0:
1886 ankur.sing 952
        query = query.limit(limit)
953
    return query.all()
954
 
2783 chandransh 955
def get_next_invoice_number():
956
    entity_id = InvoiceIDGenerator.query.with_lockmode("update").one()
957
    invoice_number = entity_id.id + 1
958
    entity_id.id = invoice_number
959
    return invoice_number
960
 
2536 chandransh 961
def toggle_doa_flag(order_id):
962
    order = get_order(order_id)
963
    if(order.doaFlag):
964
        order.doaFlag = False
965
    else:
966
        order.doaFlag = True
967
    session.commit()
968
    return order.doaFlag
969
 
4454 rajveer 970
def mark_order_doa_request_received(orderId):
971
    order = get_order(orderId)
972
    if order.status != OrderStatus.DELIVERY_SUCCESS:
973
        return False
974
    order.status = OrderStatus.DOA_REQUEST_RECEIVED
4459 rajveer 975
    order.statusDescription = "DOA Request Received"
4454 rajveer 976
    session.commit()
977
    return True
978
 
979
def mark_order_doa_request_authorized(orderId, isAuthorized):
980
    order = get_order(orderId)
981
    if order.status != OrderStatus.DOA_REQUEST_RECEIVED:
982
        return False
983
    if isAuthorized:
984
        order.status = OrderStatus.DOA_REQUEST_AUTHORIZED
4459 rajveer 985
        order.statusDescription = "DOA Request Authorized"
4454 rajveer 986
    else:
987
        order.status = OrderStatus.DELIVERY_SUCCESS
4459 rajveer 988
        order.statusDescription = "Order delivered"
4454 rajveer 989
    session.commit()
990
    return True
991
 
4488 rajveer 992
def mark_order_return_request_received(orderId):
993
    order = get_order(orderId)
994
    if order.status != OrderStatus.DELIVERY_SUCCESS:
995
        return False
996
    order.status = OrderStatus.RET_REQUEST_RECEIVED
997
    order.statusDescription = "Return Request Received"
998
    session.commit()
999
    return True
1000
 
1001
def mark_order_return_request_authorized(orderId, isAuthorized):
1002
    order = get_order(orderId)
1003
    if order.status != OrderStatus.RET_REQUEST_RECEIVED:
1004
        return False
1005
    if isAuthorized:
1006
        order.status = OrderStatus.RET_REQUEST_AUTHORIZED
1007
        order.statusDescription = "Return Request Authorized"
1008
    else:
1009
        order.status = OrderStatus.DELIVERY_SUCCESS
1010
        order.statusDescription = "Order delivered"
1011
    session.commit()
1012
    return True
1013
 
4579 rajveer 1014
def request_pickup_number(order_id, providerId):
2536 chandransh 1015
    order = get_order(order_id)
4495 rajveer 1016
    if order.status != OrderStatus.DELIVERY_SUCCESS and order.status != OrderStatus.DOA_REQUEST_AUTHORIZED and order.status != OrderStatus.RET_REQUEST_AUTHORIZED:
2536 chandransh 1017
        return False
1018
    from_user = 'cnc.center@shop2020.in'
1019
    from_pwd = '5h0p2o2o'
1020
 
4227 rajveer 1021
    subject = "Pickup request from " + order.customer_city
2536 chandransh 1022
    try:
3133 rajveer 1023
        catalog_client = CatalogClient().get_client()
2536 chandransh 1024
        warehouse = catalog_client.getWarehouse(order.warehouse_id)
1025
 
1026
        logistics_client = LogisticsClient().get_client()
4579 rajveer 1027
        provider = logistics_client.getProvider(providerId)
3051 chandransh 1028
        to_addr = provider.details[DeliveryType.PREPAID].email
2536 chandransh 1029
        raw_message = '''
1030
        Dear Sir/Madam,
1031
 
2559 chandransh 1032
        Kindly arrange a pickup today from %(customer_city)s. Pickup and delivery addresses are mentioned below.
2536 chandransh 1033
 
1034
        Pickup CODE: %(provider_code)s
1035
        Total Weight: %(order_weight)s kg
1036
 
2559 chandransh 1037
        Pickup Address:
2536 chandransh 1038
 
1039
        %(customer_address)s
1040
 
1041
        Delivery Address:
1042
 
1043
        %(warehouse_executive)s
1044
        %(warehouse_address)s
1045
        PIN %(warehouse_pin)s
1046
 
1047
        Thanks and Regards
4227 rajveer 1048
        Sandeep Sachdeva
2536 chandransh 1049
        '''
4579 rajveer 1050
 
1051
        if warehouse.id == 7:
1052
            executive = 'Amit Kumar'
1053
        else:
4966 phani.kuma 1054
            executive = 'Dinesh Kumar'
4579 rajveer 1055
 
2559 chandransh 1056
        message = dedent(raw_message) % { 'customer_city' : order.customer_city,
3051 chandransh 1057
                                          'provider_code' : provider.details[DeliveryType.PREPAID].accountNo,
2536 chandransh 1058
                                          'order_weight' : str(order.total_weight),
1059
                                          'customer_address' : __get_order_address(order),
4579 rajveer 1060
                                          'warehouse_executive' : executive,
2536 chandransh 1061
                                          'warehouse_address' : warehouse.location,
4966 phani.kuma 1062
                                          'warehouse_pin' : warehouse.pincode}
5256 rajveer 1063
        to_addresses = [to_addr, 'zaffar.kar@shop2020.in', 'suraj.sharma@shop2020.in']
4966 phani.kuma 1064
 
4606 rajveer 1065
        mail(from_user, from_pwd, to_addresses, subject, message)
4495 rajveer 1066
        if order.status == OrderStatus.RET_REQUEST_AUTHORIZED:
1067
            order.status = OrderStatus.RET_PICKUP_REQUEST_RAISED
1068
            order.statusDescription = "Pick up requested for RETURN"
1069
        else:
1070
            order.status = OrderStatus.DOA_PICKUP_REQUEST_RAISED
1071
            order.statusDescription = "Pick up requested for DOA"
4815 phani.kuma 1072
        order.doa_logistics_provider_id = providerId
2536 chandransh 1073
        session.commit()
1074
        return True
1075
    except Exception as e:
1076
        print sys.exc_info()[0]
1077
        return False
1078
 
4602 rajveer 1079
def authorize_pickup(order_id, pickup_number, providerId):
2536 chandransh 1080
    order = get_order(order_id)
4495 rajveer 1081
    if order.status not in [OrderStatus.DOA_PICKUP_REQUEST_RAISED, OrderStatus.RET_PICKUP_REQUEST_RAISED]:
2536 chandransh 1082
        return False
4815 phani.kuma 1083
    if order.doa_logistics_provider_id is not None:
1084
        providerId = order.doa_logistics_provider_id    #previously we are not storing this so data is taken from omdashboarduser
2536 chandransh 1085
    from_user = 'help@shop2020.in'
1086
    from_pwd = '5h0p2o2o'
1087
    subject = 'Pickup details'
1088
    filename = "/tmp/" +  str(order.id) +".pdf" 
1089
    try:
3133 rajveer 1090
        catalog_client = CatalogClient().get_client()
2536 chandransh 1091
        warehouse = catalog_client.getWarehouse(order.warehouse_id)
1092
 
1093
        logistics_client = LogisticsClient().get_client()
4602 rajveer 1094
        provider = logistics_client.getProvider(providerId)
2536 chandransh 1095
        provider_name = provider.name
1096
 
1097
        to_addr = order.customer_email
1098
        today = date.today().strftime("%d-%B-%Y (%A)")
1099
 
1100
        raw_message = '''
1101
        Dear Mr. %(customer_name)s,
1102
 
4815 phani.kuma 1103
        In reference to the return of order ID %(order_id)d, ''' + __generate_mail_body_for_authorize_pickup(order)
1104
        raw_message = raw_message + '''
2536 chandransh 1105
        Take a printout of the attachment in this mail which contains the delivery address and paste it on the packed parcel.
1106
        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.
1107
 
1108
        Pickup will happen from the below mentioned address:-
1109
 
1110
        %(customer_address)s
1111
 
1112
        Do let us know in case of any concerns
1113
 
1114
        Thanks & Regards
1115
        Saholic Team
1116
        '''
1117
        message = dedent(raw_message) % {'customer_name' : order.customer_name,
1118
                                         'order_id' : order_id,
1119
                                         'provider_name' : provider_name,
1120
                                         'date': today,
1121
                                         'pickup_request_no' : pickup_number,
1122
                                         'customer_address' : __get_order_address(order)}
1123
        print message
1124
        __generate_return_advice(order, warehouse, provider, filename)
3527 chandransh 1125
        mail(from_user, from_pwd, [to_addr], subject, message, [get_attachment_part(filename)])
2536 chandransh 1126
        order.pickupRequestNo = pickup_number
4495 rajveer 1127
        if order.status == OrderStatus.RET_PICKUP_REQUEST_RAISED:
1128
            order.status = OrderStatus.RET_PICKUP_CONFIRMED
1129
            order.statusDescription = "RETURN pick up confirmed"
1130
        else:
1131
            order.status = OrderStatus.DOA_PICKUP_CONFIRMED
1132
            order.statusDescription = "DOA pick up confirmed"
2764 chandransh 1133
        order.doa_auth_timestamp = datetime.datetime.now()
2536 chandransh 1134
        session.commit()
1135
        return True
1136
    except Exception as e:
4234 rajveer 1137
        print sys.exc_info()
4506 phani.kuma 1138
        traceback.print_tb(sys.exc_info()[2])
2536 chandransh 1139
        return False
1140
    finally:
1141
        if os.path.exists(filename):
1142
            os.remove(filename)
1143
 
4815 phani.kuma 1144
def __generate_mail_body_for_authorize_pickup(order):
1145
    brand_msgbody_map = {'Nokia' : 'we request you to kindly pack the box properly with bubble wrap, and send it along with the all original accessories, original handset and the invoice.',
1146
                         'Micromax' : 'we request you to kindly pack the box properly with bubble wrap, and send it along with the all original accessories, original handset and the invoice.',
1147
                         'Karbonn' : 'we request you to kindly pack the box properly with bubble wrap, and send it along with the all original accessories, original handset and the invoice.',
1148
                         'Sony Ericsson' : 'we request you to kindly pack the original DOA certificate and the invoice.',
1149
                         'Others Handsets' : 'we request you to kindly pack the box properly with bubble wrap, and send it along with the original "DOA" certificate and the invoice. Please paste the original DOA on the sealed box. Kindly ensure that the product is properly sealed. If we receive open sealed products, we will not be able to accept.',
1150
                         'Handsets Return' : 'we request you to kindly pack the box properly with bubble wrap, and send it along with the all original accessories, original handset and the invoice.',
1151
                         'Accessories' : 'we request you to kindly pack the box properly with bubble wrap, and send it along with the original product and the invoice.'}
1152
    categories = ["Handsets", "Tablets", "Laptops"]
1153
    lineitem = order.lineitems[0]
1154
    brand = lineitem.brand
1155
    productGroup = lineitem.productGroup
1156
    searchkey = None
1157
    if productGroup not in categories:
1158
        searchkey = 'Accessories'
1159
    elif order.status == OrderStatus.RET_PICKUP_REQUEST_RAISED:
1160
        searchkey = 'Handsets Return'
1161
    elif brand == 'Nokia':
1162
        searchkey = 'Nokia'
1163
    elif brand == 'Micromax':
1164
        searchkey = 'Micromax'
1165
    elif brand == 'Karbonn':
1166
        searchkey = 'Karbonn'
1167
    elif brand == 'Sony Ericsson':
1168
        searchkey = 'Sony Ericsson'
1169
    else:
1170
        searchkey = 'Others Handsets'
1171
    return brand_msgbody_map.get(searchkey)
1172
 
2764 chandransh 1173
def mark_doas_as_picked_up(provider_id, pickup_details):
1174
    for pickupNo, doa_pickup_timestamp in pickup_details.iteritems():
4815 phani.kuma 1175
        order = Order.query.filter_by(pickupRequestNo=pickupNo, doa_logistics_provider_id = provider_id).first()
4452 rajveer 1176
        if order == None or order.status != OrderStatus.DOA_PICKUP_CONFIRMED:
2764 chandransh 1177
            #raise TransactionServiceException(102, "No order found for the awb: " + awb)
1178
            continue
1179
        order.status = OrderStatus.DOA_RETURN_IN_TRANSIT
1180
        order.statusDescription = "DOA picked up by Courier Company"
1181
        order.doa_pickup_timestamp = doa_pickup_timestamp
1182
    session.commit()
1183
 
4910 phani.kuma 1184
def get_doas_not_picked_up(provider_id):
2764 chandransh 1185
    current_time = datetime.datetime.now()
1186
    to_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
4815 phani.kuma 1187
    orders_not_picked_up = Order.query.filter_by(doa_logistics_provider_id = provider_id).filter_by(status=OrderStatus.DOA_PICKUP_CONFIRMED).filter(Order.doa_auth_timestamp <= to_datetime).all()
2764 chandransh 1188
    return orders_not_picked_up
1189
 
4741 phani.kuma 1190
def mark_return_orders_as_picked_up(provider_id, pickup_details):
1191
    for pickupNo, return_order_pickup_timestamp in pickup_details.iteritems():
4815 phani.kuma 1192
        order = Order.query.filter_by(pickupRequestNo=pickupNo, doa_logistics_provider_id = provider_id).first()
4741 phani.kuma 1193
        if order == None or order.status != OrderStatus.RET_PICKUP_CONFIRMED:
1194
            #raise TransactionServiceException(102, "No order found for the awb: " + awb)
1195
            continue
1196
        order.status = OrderStatus.RET_RETURN_IN_TRANSIT
1197
        order.statusDescription = "Return order picked up by Courier Company"
1198
        order.doa_pickup_timestamp = return_order_pickup_timestamp
1199
    session.commit()
1200
 
4910 phani.kuma 1201
def get_return_orders_not_picked_up(provider_id):
4741 phani.kuma 1202
    current_time = datetime.datetime.now()
1203
    to_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
4815 phani.kuma 1204
    orders_not_picked_up = Order.query.filter_by(doa_logistics_provider_id = provider_id).filter_by(status=OrderStatus.RET_PICKUP_CONFIRMED).filter(Order.doa_auth_timestamp <= to_datetime).all()
4741 phani.kuma 1205
    return orders_not_picked_up
1206
 
4479 rajveer 1207
def receive_return(order_id, receiveCondition):
2591 chandransh 1208
    order = get_order(order_id)
4365 mandeep.dh 1209
 
4452 rajveer 1210
    if order.status in [OrderStatus.DOA_PICKUP_CONFIRMED, OrderStatus.DOA_RETURN_IN_TRANSIT]:
4479 rajveer 1211
        if receiveCondition == 0:
1212
            order.status = OrderStatus.DOA_RECEIVED_PRESTINE
1213
            order.statusDescription = "DOA package received"
1214
        elif receiveCondition == 1:
1215
            order.status = OrderStatus.DOA_RECEIVED_DAMAGED
1216
            order.statusDescription = "DOA received damaged"
1217
        elif receiveCondition == 2:
1218
            order.status = OrderStatus.DOA_LOST_IN_TRANSIT
1219
            order.statusDescription = "DOA lost in transit"
2764 chandransh 1220
        order.received_return_timestamp = datetime.datetime.now()
2616 chandransh 1221
        session.commit()
4495 rajveer 1222
    elif order.status in [OrderStatus.RET_PICKUP_CONFIRMED, OrderStatus.RET_RETURN_IN_TRANSIT]:
1223
        if receiveCondition == 0:
1224
            order.status = OrderStatus.RET_RECEIVED_PRESTINE
1225
            order.statusDescription = "RETURN package received"
1226
        elif receiveCondition == 1:
1227
            order.status = OrderStatus.RET_RECEIVED_DAMAGED
1228
            order.statusDescription = "RETURN received damaged"
1229
        elif receiveCondition == 2:
1230
            order.status = OrderStatus.RET_LOST_IN_TRANSIT
1231
            order.statusDescription = "RETURN lost in transit"
1232
        order.received_return_timestamp = datetime.datetime.now()
1233
        session.commit()
4484 rajveer 1234
    elif order.status == OrderStatus.RTO_IN_TRANSIT :
4486 rajveer 1235
        if receiveCondition == 0:
1236
            order.status = OrderStatus.RTO_RECEIVED_PRESTINE
4515 mandeep.dh 1237
            order.statusDescription = "Returned to origin"
4486 rajveer 1238
        elif receiveCondition == 1:
1239
            order.status = OrderStatus.RTO_RECEIVED_DAMAGED
1240
            order.statusDescription = "RTO received damaged"
1241
        elif receiveCondition == 2:
1242
            order.status = OrderStatus.RTO_LOST_IN_TRANSIT
1243
            order.statusDescription = "RTO lost in transit"
2764 chandransh 1244
        order.received_return_timestamp = datetime.datetime.now()
2616 chandransh 1245
        session.commit()
1246
    else:
2591 chandransh 1247
        return False
5110 mandeep.dh 1248
 
1249
    # For OUR warehouses, we need to scan in items for every return
1250
    catalogClient = CatalogClient().get_client()
1251
    warehouse = catalogClient.getWarehouse(order.warehouse_id)
1252
    if warehouse.billingType == BillingType.OURS:
1253
        try:
1254
            scanMap = {
1255
                OrderStatus.RTO_RECEIVED_PRESTINE : ScanType.SALE_RET,
1256
                OrderStatus.RTO_RECEIVED_DAMAGED  : ScanType.SALE_RET_UNUSABLE,
1257
                OrderStatus.RTO_LOST_IN_TRANSIT   : ScanType.LOST_IN_TRANSIT,
1258
                OrderStatus.DOA_RECEIVED_PRESTINE : ScanType.DOA_IN,
1259
                OrderStatus.DOA_RECEIVED_DAMAGED  : ScanType.DOA_IN,
1260
                OrderStatus.DOA_LOST_IN_TRANSIT   : ScanType.LOST_IN_TRANSIT
1261
            }
1262
 
1263
            scanType = scanMap[order.status]
1264
            if scanType:
1265
                lineitem = order.lineitems[0]
1266
                warehouseClient = WarehouseClient().get_client()
1267
                warehouseClient.scanSerializedItemForOrder(lineitem.serial_number, scanType, order.id, order.fulfilmentWarehouseId, lineitem.quantity, order.warehouse_id)
1268
        except Exception as e:
1269
            print sys.exc_info()[0]
1270
            print 'Could not scan in sales return orders' + str(e)
1271
 
2591 chandransh 1272
    return True
1273
 
1274
def validate_doa(order_id, is_valid):
1275
    order = get_order(order_id)
4452 rajveer 1276
    if order.status != OrderStatus.DOA_RECEIVED_PRESTINE:
2591 chandransh 1277
        return False
1278
    if is_valid:
2609 chandransh 1279
        order.status = OrderStatus.DOA_CERT_VALID
1280
        order.statusDescription = "DOA Certificate Valid"
2591 chandransh 1281
    else:
1282
        order.status = OrderStatus.DOA_CERT_INVALID
1283
        order.statusDescription = "DOA Certificate Invalid"
3578 mandeep.dh 1284
        update_trust_level(order)
2591 chandransh 1285
    session.commit()
1286
    return True
1287
 
4495 rajveer 1288
def validate_return_product(order_id, is_usable):
1289
    order = get_order(order_id)
1290
    if order.status != OrderStatus.RET_RECEIVED_PRESTINE:
1291
        return False
5110 mandeep.dh 1292
 
1293
    scanType = ScanType.SALE_RET_UNUSABLE
4495 rajveer 1294
    if is_usable:
1295
        order.status = OrderStatus.RET_PRODUCT_USABLE
1296
        order.statusDescription = "Return product usable"
5110 mandeep.dh 1297
        scanType = ScanType.SALE_RET
4495 rajveer 1298
    else:
1299
        order.status = OrderStatus.RET_PRODUCT_UNUSABLE
1300
        order.statusDescription = "Return product unusable"
1301
        update_trust_level(order)
1302
    session.commit()
5110 mandeep.dh 1303
 
1304
    # For OUR warehouses, we need to scan in items for every return
1305
    catalogClient = CatalogClient().get_client()
1306
    warehouse = catalogClient.getWarehouse(order.warehouse_id)
1307
    if warehouse.billingType == BillingType.OURS:
1308
        lineitem = order.lineitems[0]
1309
        warehouse_client = WarehouseClient().get_client()
1310
        warehouse_client.scanSerializedItemForOrder(lineitem.serial_number, scanType, order.id, order.fulfilmentWarehouseId, lineitem.quantity, order.warehouse_id)
4495 rajveer 1311
    return True
1312
 
2628 chandransh 1313
def reship_order(order_id):
1314
    """
4484 rajveer 1315
    If the order is in RTO_RECEIVED_PRESTINE or DOA_CERT_INVALID state, it does the following:
2628 chandransh 1316
        1. Creates a new order for processing in the BILLED state. All billing information is saved.
4484 rajveer 1317
        2. Marks the current order as one of the final states RTO_RESHIPPED and DOA_INVALID_RESHIPPED depending on what state the order started in.
2628 chandransh 1318
 
1319
    If the order is in DOA_CERT_VALID state, it does the following:
1320
        1. Creates a new order for processing in the SUBMITTED_FOR_PROCESSING state.
1321
        2. Creates a return order for the warehouse executive to return the DOA material.
4452 rajveer 1322
        3. Marks the current order as the final DOA_VALID_RESHIPPED state.
2628 chandransh 1323
 
1324
    Returns the id of the newly created order.
1325
 
1326
    Throws an exception if the order with the given id couldn't be found.
1327
 
1328
    Parameters:
1329
     - orderId
1330
    """
1331
    order = get_order(order_id)
4484 rajveer 1332
    if order.status == OrderStatus.RTO_RECEIVED_PRESTINE:
4220 rajveer 1333
        new_order = __clone_order(order, True, order.cod)
4484 rajveer 1334
        order.status = OrderStatus.RTO_RESHIPPED
2628 chandransh 1335
        order.statusDescription = "Order Reshipped"
1336
        session.commit()
3578 mandeep.dh 1337
        update_trust_level(order)
4486 rajveer 1338
    elif order.status == OrderStatus.RTO_RECEIVED_DAMAGED:
1339
        new_order = __clone_order(order, False, order.cod)
1340
        ret_order = __create_return_order(order)
1341
        order.status = OrderStatus.RTO_DAMAGED_RESHIPPED
1342
        order.statusDescription = "Order Reshipped Received Damaged"
1343
        session.commit()
1344
    elif order.status == OrderStatus.RTO_LOST_IN_TRANSIT:
1345
        new_order = __clone_order(order, False, order.cod)
1346
        order.status = OrderStatus.RTO_LOST_IN_TRANSIT_RESHIPPED
1347
        order.statusDescription = "Order Reshipped Lost In Transit"
1348
        session.commit()
4662 rajveer 1349
    elif order.status == OrderStatus.LOST_IN_TRANSIT:
1350
        new_order = __clone_order(order, False, order.cod)
1351
        order.status = OrderStatus.LOST_IN_TRANSIT_RESHIPPED
1352
        order.statusDescription = "Order Reshipped Lost In Transit"
1353
        session.commit()
2628 chandransh 1354
    elif order.status == OrderStatus.DOA_CERT_INVALID:
4220 rajveer 1355
        new_order = __clone_order(order, True, False)
2628 chandransh 1356
        order.status = OrderStatus.DOA_INVALID_RESHIPPED
1357
        order.statusDescription = "Order Reshipped"
1358
        session.commit()
1359
    elif order.status == OrderStatus.DOA_CERT_VALID:
4220 rajveer 1360
        new_order = __clone_order(order, False, False)
2628 chandransh 1361
        ret_order = __create_return_order(order)
4452 rajveer 1362
        order.status = OrderStatus.DOA_VALID_RESHIPPED
2628 chandransh 1363
        order.statusDescription = "Order Reshipped"
1364
        session.commit()
4479 rajveer 1365
    elif order.status == OrderStatus.DOA_RECEIVED_DAMAGED:
1366
        new_order = __clone_order(order, False, False)
1367
        ret_order = __create_return_order(order)
1368
        order.status = OrderStatus.DOA_RESHIPPED_RCVD_DAMAGED
1369
        order.statusDescription = "Order Reshipped Received Damaged"
1370
        session.commit()
1371
    elif order.status == OrderStatus.DOA_LOST_IN_TRANSIT:
1372
        new_order = __clone_order(order, False, False)
1373
        order.status = OrderStatus.DOA_RESHIPPED_LOST_IN_TRANSIT
1374
        order.statusDescription = "Order Reshipped Lost In Transit"
1375
        session.commit()
4614 rajveer 1376
    elif order.status == OrderStatus.RET_PRODUCT_USABLE:
4495 rajveer 1377
        new_order = __clone_order(order, True, False)
4614 rajveer 1378
        order.status = OrderStatus.RET_PRODUCT_USABLE_RESHIPPED
4495 rajveer 1379
        order.statusDescription = "Order Reshipped"
1380
        session.commit()
4614 rajveer 1381
    elif order.status == OrderStatus.RET_PRODUCT_UNUSABLE:
4495 rajveer 1382
        new_order = __clone_order(order, False, False)
1383
        ret_order = __create_return_order(order)
4614 rajveer 1384
        order.status = OrderStatus.RET_PRODUCT_UNUSABLE_RESHIPPED
4495 rajveer 1385
        order.statusDescription = "Order Reshipped"
1386
        session.commit()
1387
    elif order.status == OrderStatus.RET_RECEIVED_DAMAGED:
1388
        new_order = __clone_order(order, False, False)
1389
        ret_order = __create_return_order(order)
1390
        order.status = OrderStatus.RET_RESHIPPED_RCVD_DAMAGED
1391
        order.statusDescription = "Order Reshipped Received Damaged"
1392
        session.commit()
1393
    elif order.status == OrderStatus.RET_LOST_IN_TRANSIT:
1394
        new_order = __clone_order(order, False, False)
1395
        order.status = OrderStatus.RET_RESHIPPED_LOST_IN_TRANSIT
1396
        order.statusDescription = "Order Reshipped Lost In Transit"
1397
        session.commit()
2628 chandransh 1398
    else:
1399
        raise TransactionServiceException(112, "This order can't be reshipped")
1400
 
2764 chandransh 1401
    order.reship_timestamp = datetime.datetime.now()
2628 chandransh 1402
    order.new_order_id = new_order.id
1403
    session.commit()
1404
 
1405
    return new_order.id
1406
 
3226 chandransh 1407
def refund_order(order_id, refunded_by, reason):
2628 chandransh 1408
    """
4484 rajveer 1409
    If the order is in RTO_RECEIVED_PRESTINE, DOA_CERT_VALID or DOA_CERT_INVALID state, it does the following:
2628 chandransh 1410
        1. Creates a refund request for batch processing.
1411
        2. Creates a return order for the warehouse executive to return the shipped material.
4484 rajveer 1412
        3. Marks the current order as RTO_REFUNDED, DOA_VALID_REFUNDED or DOA_INVALID_REFUNDED final states.
2628 chandransh 1413
 
1414
    If the order is in SUBMITTED_FOR_PROCESSING or INVENTORY_LOW state, it does the following:
1415
        1. Creates a refund request for batch processing.
3226 chandransh 1416
        2. Cancels the reservation of the item in the warehouse.
1417
        3. Marks the current order as the REFUNDED final state.
2628 chandransh 1418
 
3226 chandransh 1419
    For all COD orders, if the order is in INIT, SUBMITTED_FOR_PROCESSING or INVENTORY_LOW state, it does the following:
1420
        1. Cancels the reservation of the item in the warehouse.
1421
        2. Marks the current order as CANCELED.
1422
 
1423
    In all cases, it updates the reason for cancellation or refund and the person who performed the action.
1424
 
1425
    Returns True if it is successful, False otherwise.
2628 chandransh 1426
 
1427
    Throws an exception if the order with the given id couldn't be found.
1428
 
1429
    Parameters:
3226 chandransh 1430
     - order_id
1431
     - refunded_by
1432
     - reason
2628 chandransh 1433
    """
3414 chandransh 1434
    logging.info("Refunding order id: " + str(order_id))
2628 chandransh 1435
    order = get_order(order_id)
3186 chandransh 1436
 
3226 chandransh 1437
    if order.cod:
3414 chandransh 1438
        logging.info("Refunding COD order with status " + str(order.status))
4662 rajveer 1439
        status_transition = { OrderStatus.LOST_IN_TRANSIT : OrderStatus.LOST_IN_TRANSIT_REFUNDED,
1440
                     OrderStatus.RTO_RECEIVED_PRESTINE : OrderStatus.RTO_REFUNDED,
4486 rajveer 1441
                     OrderStatus.RTO_RECEIVED_DAMAGED : OrderStatus.RTO_DAMAGED_REFUNDED,
1442
                     OrderStatus.RTO_LOST_IN_TRANSIT : OrderStatus.RTO_LOST_IN_TRANSIT_REFUNDED,
3366 chandransh 1443
                     OrderStatus.DOA_CERT_INVALID : OrderStatus.DOA_INVALID_REFUNDED,
1444
                     OrderStatus.DOA_CERT_VALID : OrderStatus.DOA_VALID_REFUNDED,
4479 rajveer 1445
                     OrderStatus.DOA_RECEIVED_DAMAGED : OrderStatus.DOA_REFUNDED_RCVD_DAMAGED,
1446
                     OrderStatus.DOA_LOST_IN_TRANSIT : OrderStatus.DOA_REFUNDED_LOST_IN_TRANSIT,
4495 rajveer 1447
                     OrderStatus.RET_PRODUCT_UNUSABLE : OrderStatus.RET_PRODUCT_UNUSABLE_REFUNDED,
1448
                     OrderStatus.RET_PRODUCT_USABLE : OrderStatus.RET_PRODUCT_USABLE_REFUNDED,
1449
                     OrderStatus.RET_RECEIVED_DAMAGED : OrderStatus.RET_REFUNDED_RCVD_DAMAGED,
1450
                     OrderStatus.RET_LOST_IN_TRANSIT : OrderStatus.RET_REFUNDED_LOST_IN_TRANSIT,
4682 rajveer 1451
                     OrderStatus.COD_VERIFICATION_PENDING : OrderStatus.COD_VERIFICATION_FAILED,
1452
                     OrderStatus.SUBMITTED_FOR_PROCESSING : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1453
                     OrderStatus.INVENTORY_LOW : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1454
                     OrderStatus.LOW_INV_PO_RAISED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1455
                     OrderStatus.LOW_INV_REVERSAL_IN_PROCESS : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1456
                     OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1457
                     OrderStatus.ACCEPTED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1458
                     OrderStatus.BILLED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
4247 rajveer 1459
                     OrderStatus.CANCEL_REQUEST_CONFIRMED : OrderStatus.CANCELLED_ON_CUSTOMER_REQUEST
3366 chandransh 1460
                     }
1461
        if order.status not in status_transition.keys():
1462
            raise TransactionServiceException(114, "This order can't be refunded")
1463
 
5199 mandeep.dh 1464
        if order.status in [OrderStatus.COD_VERIFICATION_PENDING, 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, OrderStatus.ACCEPTED]:
3226 chandransh 1465
            __update_inventory_reservation(order)
1466
            order.statusDescription = "Order Cancelled"
3415 chandransh 1467
        elif order.status == OrderStatus.BILLED:
3413 chandransh 1468
            __create_return_order(order)
1469
            order.statusDescription = "Order Cancelled"
4486 rajveer 1470
        elif order.status in [OrderStatus.RTO_RECEIVED_PRESTINE, OrderStatus.RTO_RECEIVED_DAMAGED, OrderStatus.RTO_LOST_IN_TRANSIT]:
3226 chandransh 1471
            __create_return_order(order)
4486 rajveer 1472
            order.statusDescription = "RTO Refunded"
4662 rajveer 1473
        elif order.status in [OrderStatus.LOST_IN_TRANSIT]:
1474
            __create_return_order(order)
1475
            order.statusDescription = "Lost in Transit Refunded"
4479 rajveer 1476
        elif order.status in [OrderStatus.DOA_CERT_INVALID, OrderStatus.DOA_CERT_VALID, OrderStatus.DOA_RECEIVED_DAMAGED, OrderStatus.DOA_LOST_IN_TRANSIT] :
4078 chandransh 1477
            __create_return_order(order)
3226 chandransh 1478
            __create_refund(order)
4495 rajveer 1479
            order.statusDescription = "DOA Refunded"
1480
        elif order.status in [OrderStatus.RET_PRODUCT_UNUSABLE, OrderStatus.RET_PRODUCT_USABLE, OrderStatus.RET_RECEIVED_DAMAGED, OrderStatus.RET_LOST_IN_TRANSIT] :
1481
            __create_return_order(order)
1482
            __create_refund(order)
1483
            order.statusDescription = "Return Refunded"
4247 rajveer 1484
        elif order.status == OrderStatus.CANCEL_REQUEST_CONFIRMED:
5199 mandeep.dh 1485
            if order.previousStatus in [OrderStatus.COD_VERIFICATION_PENDING, 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, OrderStatus.ACCEPTED]:
4247 rajveer 1486
                __update_inventory_reservation(order)
1487
                order.statusDescription = "Order Cancelled on customer request"
1488
            elif order.previousStatus == OrderStatus.BILLED:
1489
                __create_return_order(order)
1490
                order.statusDescription = "Order Cancelled on customer request"
3226 chandransh 1491
    else:
4662 rajveer 1492
        status_transition = {OrderStatus.LOST_IN_TRANSIT : OrderStatus.LOST_IN_TRANSIT_REFUNDED,
1493
                     OrderStatus.RTO_RECEIVED_PRESTINE : OrderStatus.RTO_REFUNDED,
4486 rajveer 1494
                     OrderStatus.RTO_RECEIVED_DAMAGED : OrderStatus.RTO_DAMAGED_REFUNDED,
1495
                     OrderStatus.RTO_LOST_IN_TRANSIT : OrderStatus.RTO_LOST_IN_TRANSIT_REFUNDED,
3366 chandransh 1496
                     OrderStatus.DOA_CERT_INVALID : OrderStatus.DOA_INVALID_REFUNDED,
1497
                     OrderStatus.DOA_CERT_VALID : OrderStatus.DOA_VALID_REFUNDED,
4479 rajveer 1498
                     OrderStatus.DOA_RECEIVED_DAMAGED : OrderStatus.DOA_REFUNDED_RCVD_DAMAGED,
1499
                     OrderStatus.DOA_LOST_IN_TRANSIT : OrderStatus.DOA_REFUNDED_LOST_IN_TRANSIT,
4495 rajveer 1500
                     OrderStatus.RET_PRODUCT_UNUSABLE : OrderStatus.RET_PRODUCT_UNUSABLE_REFUNDED,
1501
                     OrderStatus.RET_PRODUCT_USABLE : OrderStatus.RET_PRODUCT_USABLE_REFUNDED,
1502
                     OrderStatus.RET_RECEIVED_DAMAGED : OrderStatus.RET_REFUNDED_RCVD_DAMAGED,
1503
                     OrderStatus.RET_LOST_IN_TRANSIT : OrderStatus.RET_REFUNDED_LOST_IN_TRANSIT,
4682 rajveer 1504
                     OrderStatus.SUBMITTED_FOR_PROCESSING : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1505
                     OrderStatus.INVENTORY_LOW : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1506
                     OrderStatus.LOW_INV_PO_RAISED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1507
                     OrderStatus.LOW_INV_REVERSAL_IN_PROCESS : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1508
                     OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1509
                     OrderStatus.ACCEPTED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1510
                     OrderStatus.BILLED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
4247 rajveer 1511
                     OrderStatus.CANCEL_REQUEST_CONFIRMED : OrderStatus.CANCELLED_ON_CUSTOMER_REQUEST,
1512
                     OrderStatus.PAYMENT_FLAGGED : OrderStatus.PAYMENT_FLAGGED_DENIED
3366 chandransh 1513
                     }
1514
        if order.status not in status_transition.keys():
1515
            raise TransactionServiceException(114, "This order can't be refunded")
1516
 
4495 rajveer 1517
        if order.status in [OrderStatus.RTO_RECEIVED_PRESTINE, OrderStatus.RTO_RECEIVED_DAMAGED, OrderStatus.RTO_LOST_IN_TRANSIT] :
3226 chandransh 1518
            __create_return_order(order)
1519
            __create_refund(order)
4495 rajveer 1520
            order.statusDescription = "RTO Refunded"
4662 rajveer 1521
        elif order.status in [OrderStatus.LOST_IN_TRANSIT]:
1522
            __create_return_order(order)
1523
            __create_refund(order)
1524
            order.statusDescription = "Lost in Transit Refunded"
4495 rajveer 1525
        elif order.status in [OrderStatus.DOA_CERT_INVALID, OrderStatus.DOA_CERT_VALID, OrderStatus.DOA_RECEIVED_DAMAGED, OrderStatus.DOA_LOST_IN_TRANSIT] :
1526
            __create_return_order(order)
1527
            __create_refund(order)
1528
            order.statusDescription = "DOA Refunded"
1529
        elif order.status in [OrderStatus.RET_PRODUCT_UNUSABLE, OrderStatus.RET_PRODUCT_USABLE, OrderStatus.RET_RECEIVED_DAMAGED, OrderStatus.RET_LOST_IN_TRANSIT] :
1530
            __create_return_order(order)
1531
            __create_refund(order)
1532
            order.statusDescription = "Return Refunded"
5199 mandeep.dh 1533
        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, OrderStatus.ACCEPTED]:
3226 chandransh 1534
            __update_inventory_reservation(order)
1535
            order.statusDescription = "Order Refunded"
4247 rajveer 1536
        elif order.status == OrderStatus.CANCEL_REQUEST_CONFIRMED:
5199 mandeep.dh 1537
            if order.previousStatus 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, OrderStatus.ACCEPTED]:
4672 rajveer 1538
                if order.previousStatus == OrderStatus.ACCEPTED:
1539
                    __create_refund(order)
4247 rajveer 1540
                __update_inventory_reservation(order)
1541
                order.statusDescription = "Order Cancelled on customer request"
1542
            elif order.previousStatus == OrderStatus.BILLED:
1543
                __create_return_order(order)
1544
                __create_refund(order)
1545
                order.statusDescription = "Order Cancelled on customer request"
1546
        elif order.status == OrderStatus.PAYMENT_FLAGGED:
1547
            __update_inventory_reservation(order)
1548
            order.statusDescription = "Order Cancelled due to payment flagged"
3195 chandransh 1549
 
4873 mandeep.dh 1550
    # For orders that are cancelled after being billed, we need to scan in the scanned out
1551
    # inventory item and change availability accordingly
5110 mandeep.dh 1552
    catalogClient = CatalogClient().get_client()
1553
    warehouse = catalogClient.getWarehouse(order.warehouse_id)
1554
    if warehouse.billingType == BillingType.OURS:
4873 mandeep.dh 1555
        if order.status in [OrderStatus.BILLED, OrderStatus.SHIPPED_TO_LOGST, OrderStatus.SHIPPED_FROM_WH] or (order.status == OrderStatus.CANCEL_REQUEST_CONFIRMED and order.previousStatus in [OrderStatus.BILLED, OrderStatus.SHIPPED_TO_LOGST, OrderStatus.SHIPPED_FROM_WH]):
1556
            lineitem = order.lineitems[0]
5177 mandeep.dh 1557
            item = catalogClient.getItem(lineitem.item_id)
1558
            if ItemType.SERIALIZED == item.type:
1559
                warehouseClient = WarehouseClient().get_client()
1560
                warehouseClient.scanSerializedItemForOrder(lineitem.serial_number, ScanType.SALE_RET, order.id, order.fulfilmentWarehouseId, lineitem.quantity, order.warehouse_id)
4873 mandeep.dh 1561
 
3195 chandransh 1562
    order.status = status_transition[order.status]
1563
    order.refund_timestamp = datetime.datetime.now()
3226 chandransh 1564
    order.refunded_by = refunded_by
1565
    order.refund_reason = reason
4873 mandeep.dh 1566
 
2628 chandransh 1567
    session.commit()
1568
    return True
1569
 
3186 chandransh 1570
def __update_inventory_reservation(order):
3191 chandransh 1571
    '''
1572
    Reduce the reservation count for all line items of the given order.
1573
    '''
3186 chandransh 1574
    try:
1575
        catalog_client = CatalogClient().get_client()
1576
        for lineitem in order.lineitems:
5110 mandeep.dh 1577
            catalog_client.reduceReservationCount(lineitem.item_id, order.fulfilmentWarehouseId, lineitem.quantity);
3186 chandransh 1578
    except:
1579
        print "Unable to reduce reservation count"
1580
 
4220 rajveer 1581
def __clone_order(order, should_copy_billing_info, is_cod):
2628 chandransh 1582
    current_time = datetime.datetime.now()
1583
    new_order = Order()
1584
    new_order.customer_id = order.customer_id
1585
    new_order.customer_name = order.customer_name
1586
    new_order.customer_city = order.customer_city
1587
    new_order.customer_state = order.customer_state
1588
    new_order.customer_mobilenumber = order.customer_mobilenumber
1589
    new_order.customer_pincode = order.customer_pincode
1590
    new_order.customer_address1 = order.customer_address1
1591
    new_order.customer_address2 = order.customer_address2
1592
    new_order.customer_email = order.customer_email
1593
    new_order.total_amount = order.total_amount
1594
    new_order.total_weight = order.total_weight
1595
    new_order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
1596
    new_order.statusDescription = 'Submitted for Processing'
1597
    new_order.created_timestamp = current_time
5062 varun.gupt 1598
    new_order.originalOrderId = order.originalOrderId if order.originalOrderId is not None else order.id 
2628 chandransh 1599
 
1600
    new_order.transaction = order.transaction
4220 rajveer 1601
    new_order.cod = is_cod
2628 chandransh 1602
 
1603
    for line_item in order.lineitems:
1604
        litem = LineItem()
1605
        litem.item_id = line_item.item_id
1606
        litem.productGroup = line_item.productGroup
1607
        litem.brand = line_item.brand
1608
        if line_item.model_number:
1609
            litem.model_number = line_item.model_number
1610
        if line_item.model_name:    
1611
            litem.model_name = line_item.model_name
1612
        if line_item.color:
1613
            litem.color = line_item.color
1614
        if line_item.extra_info:
1615
            litem.extra_info = line_item.extra_info
1616
        litem.quantity = line_item.quantity
1617
        litem.unit_price = line_item.unit_price
1618
        litem.unit_weight = line_item.unit_weight
1619
        litem.total_price = line_item.total_price
1620
        litem.total_weight = line_item.total_weight
1621
        litem.transfer_price = line_item.transfer_price
4840 mandeep.dh 1622
        litem.dealText = line_item.dealText
2628 chandransh 1623
        litem.order = new_order
1624
 
1625
    logistics_client = LogisticsClient().get_client()
1626
    item_id = new_order.lineitems[0].item_id
4479 rajveer 1627
    logistics_info = logistics_client.getLogisticsInfo(new_order.customer_pincode, item_id, is_cod) #TODO: We should be able to pass another flag to suggest ignoring the inventory situation.
2628 chandransh 1628
    logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
1629
    new_order.warehouse_id = logistics_info.warehouseId
5110 mandeep.dh 1630
    new_order.fulfilmentWarehouseId = logistics_info.fulfilmentWarehouseId
2628 chandransh 1631
    new_order.logistics_provider_id = logistics_info.providerId
1632
    new_order.airwaybill_no = logistics_info.airway_billno
1633
    new_order.tracking_id = new_order.airwaybill_no
1634
    new_order.expected_delivery_time = current_time + datetime.timedelta(days=logistics_info.deliveryTime)
3986 chandransh 1635
    new_order.promised_delivery_time = new_order.expected_delivery_time
4299 rajveer 1636
 
2628 chandransh 1637
    if should_copy_billing_info:
1638
        new_order.invoice_number = order.invoice_number
1639
        new_order.billed_by = order.billed_by
1640
        new_order.warehouse_id = order.warehouse_id
5110 mandeep.dh 1641
        new_order.fulfilmentWarehouseId = order.fulfilmentWarehouseId
2628 chandransh 1642
        new_order.accepted_timestamp = current_time
1643
        new_order.billing_timestamp = current_time    
1644
        new_order.status = OrderStatus.BILLED
1645
        new_order.statusDescription = 'Order Billed'
1646
    else:       
3133 rajveer 1647
        catalog_client = CatalogClient().get_client()
5110 mandeep.dh 1648
        catalog_client.reserveItemInWarehouse(item_id, logistics_info.fulfilmentWarehouseId, new_order.lineitems[0].quantity)
2628 chandransh 1649
 
1650
    return new_order
1651
 
1652
def __create_return_order(order):
2687 chandransh 1653
    ret_order = ReturnOrder(order)
2628 chandransh 1654
    return ret_order
1655
 
1656
def __create_refund(order):
4078 chandransh 1657
    payment_client = PaymentClient().get_client()
1658
    payment_client.createRefund(order.id, order.transaction.id, order.total_amount)
2747 chandransh 1659
    return
2628 chandransh 1660
 
2536 chandransh 1661
def __get_order_address(order):
1662
    address = order.customer_name + "\n" + order.customer_address1 + "\n"
1663
    if order.customer_address2:
1664
        address = address + order.customer_address2 + "\n"
1665
    address = address + order.customer_city + "\n"
1666
    address = address + order.customer_state + "\n"
1667
    address = address + "PIN " + order.customer_pincode + "\n"
1668
    address = address + "Phone: " + order.customer_mobilenumber
1669
    return address
1670
 
4815 phani.kuma 1671
def __generate_return_advice(order, warehouse, provider, filename):
1672
    if warehouse.id == 7:
1673
        executive = 'Amit Kumar'
1674
    else:
4966 phani.kuma 1675
        executive = 'Dinesh Kumar'
2536 chandransh 1676
    pdf = Canvas(filename)
1677
    pdf.setFont('Times-Bold',16)
1678
    address_text = pdf.beginText(inch, PAGE_HEIGHT - inch)
1679
    address_text.textLine("To")
4815 phani.kuma 1680
    address_text.textLine(executive)
2536 chandransh 1681
    for line in warehouse.location.split("\n"):
1682
        address_text.textLine(line)
1683
    address_text.textLine("PIN " + warehouse.pincode)
1684
    pdf.drawText(address_text)
1685
 
1686
    pdf.setFont('Times-Roman',12)
1687
    order_text = pdf.beginText(inch, PAGE_HEIGHT - 4 * inch)
3051 chandransh 1688
    order_text.textLine("Pickup CODE: " + provider.details[DeliveryType.PREPAID].accountNo)
2536 chandransh 1689
    lineitem = order.lineitems[0] 
4234 rajveer 1690
    order_text.textLine("Content : " + lineitem.brand + " " + str(lineitem.model_number) + " " + str(lineitem.color))
2536 chandransh 1691
    order_text.textLine("Declared Value: Rs. " + str(order.total_amount))
1692
    order_text.textLine("Order ID : " + str(order.id))
1693
    pdf.drawText(order_text)
1694
    pdf.showPage()
1695
    pdf.save()
1696
    return filename
1697
 
2697 chandransh 1698
def get_return_orders(warehouse_id, from_date, to_date):
1699
    query = ReturnOrder.query.filter_by(processedStatus = False)
1700
    if warehouse_id != -1:
1701
        query = query.filter_by(warehouseId = warehouse_id)
1702
    if from_date:
4118 chandransh 1703
        query = query.filter(ReturnOrder.createdAt >from_date)
2697 chandransh 1704
    if to_date:
4118 chandransh 1705
        query = query.filter(ReturnOrder.createdAt < to_date)
2697 chandransh 1706
    return [return_order.to_thrift_object() for return_order in query.all()]
1707
 
2700 chandransh 1708
def get_return_order(id):
1709
    ret_order = ReturnOrder.get_by(orderId = id)
1710
    if ret_order is None:
1711
        raise TransactionServiceException(116, "No return order found for the given order id")
1712
    return ret_order.to_thrift_object()
1713
 
2697 chandransh 1714
def process_return(ret_order_id):
1715
    ret_order = ReturnOrder.get_by(orderId = ret_order_id)
1716
    if ret_order is None:
1717
        raise TransactionServiceException(116, "No return order found for the given order id")
1718
    ret_order.processedStatus = True
2701 chandransh 1719
    ret_order.processedAt = datetime.datetime.now()
2697 chandransh 1720
    session.commit()
1721
 
4757 mandeep.dh 1722
def update_orders_as_PORaised(itemIdQuantityMap, purchaseOrderId, warehouseId):
1723
    """
1724
    Updates orders as PO raised. Also updates purchase order id in orders. Pass a map of items mapped to
1725
    the quantities for which the PO is raised.
1726
 
1727
    Parameters:
1728
     - itemIdQuantityMap
1729
     - purchaseOrderId
1730
     - warehouseId
1731
    """
3451 chandransh 1732
    query = Order.query.with_lockmode("update").filter_by(warehouse_id=warehouseId)
4757 mandeep.dh 1733
    query = query.filter(or_(Order.status == OrderStatus.SUBMITTED_FOR_PROCESSING, Order.status == OrderStatus.INVENTORY_LOW))
2819 chandransh 1734
    query = query.filter_by(purchase_order_id=None)
1735
    query = query.order_by(Order.created_timestamp)
1736
    pending_orders = query.all()
4586 mandeep.dh 1737
 
1738
    for order in pending_orders:
4757 mandeep.dh 1739
        lineitem = order.lineitems[0]
1740
        if itemIdQuantityMap.has_key(lineitem.item_id):
1741
            if itemIdQuantityMap[lineitem.item_id] >= lineitem.quantity:
1742
                order.status = OrderStatus.LOW_INV_PO_RAISED
1743
                order.statusDescription = 'In Process'
1744
                order.purchase_order_id = purchaseOrderId
1745
                itemIdQuantityMap[lineitem.item_id] -= lineitem.quantity
4434 mandeep.dh 1746
 
2819 chandransh 1747
    session.commit()
1748
 
3451 chandransh 1749
def update_weight(order_id, weight):
3469 chandransh 1750
    '''
1751
    Update the weight of order
1752
    '''
3451 chandransh 1753
    order = get_order(order_id)
1754
    order.total_weight = weight
3469 chandransh 1755
    lineitem = order.lineitems[0]
1756
    lineitem.total_weight = weight
1757
    lineitem.unit_weight = weight
3451 chandransh 1758
 
3469 chandransh 1759
    session.commit()
1760
    return order
1761
 
1762
def change_product(order_id, item_id):
1763
    '''
1764
    Ship a product of a different color to the customer.
1765
    '''
1766
    order = get_order(order_id)
4662 rajveer 1767
    if order.status not in [OrderStatus.COD_VERIFICATION_PENDING, 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 1768
        raise TransactionServiceException(120, "This order has already been processed. Please seek help from engineering.")
1769
 
1770
    lineitem = order.lineitems[0]
3451 chandransh 1771
 
3469 chandransh 1772
    catalog_client = CatalogClient().get_client()
1773
 
1774
    old_item = catalog_client.getItem(lineitem.item_id)
1775
    item = catalog_client.getItem(item_id)
1776
    if old_item.catalogItemId != item.catalogItemId:
1777
        raise TransactionServiceException(121, "You can't ship a different item. You can only ship the same item in a different color.")
1778
 
5110 mandeep.dh 1779
    catalog_client.reserveItemInWarehouse(item_id, order.fulfilmentWarehouseId, lineitem.quantity)
1780
    __update_inventory_reservation(order)
3469 chandransh 1781
    #TODO: Check that this new item has the same price
1782
 
1783
    lineitem.item_id = item_id
1784
    lineitem.color = item.color
1785
 
3451 chandransh 1786
    session.commit()
3469 chandransh 1787
 
1788
    order = get_order(order_id)
3451 chandransh 1789
    return order
3469 chandransh 1790
 
1791
def change_warehouse(order_id, warehouse_id):
1792
    '''
1793
    Update the warehouse which will be used to fulfil this order.
1794
    '''
1795
    order = get_order(order_id)
4662 rajveer 1796
    if order.status not in [OrderStatus.COD_VERIFICATION_PENDING, 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 1797
        raise TransactionServiceException(117, "This order has already been processed. Please seek help from engineering.")
1798
 
1799
    if warehouse_id == order.warehouse_id:
1800
        raise TransactionServiceException(118, "You have selected the current warehouse again. Nothing to do")
1801
 
1802
    lineitem = order.lineitems[0]
1803
    catalog_client = CatalogClient().get_client()
1804
    try:
1805
        warehouse = catalog_client.getWarehouse(warehouse_id)
1806
    except:
1807
        raise TransactionServiceException(119, "No warehouse with id" + str(warehouse_id))
5110 mandeep.dh 1808
 
5147 mandeep.dh 1809
    if warehouse.billingWarehouseId is None:
1810
        raise TransactionServiceException(119, "Shifting of warehouse allowed to warehouse with billing support only")
5110 mandeep.dh 1811
 
5147 mandeep.dh 1812
    # If One gives a shipping location for warehouse shift, we should assign order to the GOOD warehouse
1813
    # present with this shipping location with maximum availability
1814
    if warehouse.inventoryType != InventoryType.GOOD:
1815
        warehouses = catalog_client.getWarehouses(None, InventoryType.GOOD, 0, 0, warehouse.id)
1816
        if warehouses:
1817
            itemInventory = catalog_client.getItemInventoryByItemId(lineitem.item_id)
1818
            warehouse = warehouses[0]
1819
            maxAvailability = 0
1820
            for goodWarehouse in warehouses:
1821
                if itemInventory.availability.has_key(goodWarehouse.id) and maxAvailability < itemInventory.availability[goodWarehouse.id]:
1822
                    warehouse = goodWarehouse
1823
                    maxAvailability = itemInventory.availability[goodWarehouse.id]
1824
 
1825
            # Use preferred vendor's warehouse if not available anywhere
1826
            if not maxAvailability:
1827
                item = catalog_client.getItem(lineitem.item_id)
1828
                if item.preferredVendor:
1829
                    for goodWarehouse in warehouses:
1830
                        if goodWarehouse.vendor.id == item.preferredVendor:
1831
                            warehouse = goodWarehouse
1832
        else:
1833
            raise TransactionServiceException(119, "Shifting of warehouse allowed to GOOD inventory type warehouse with billing support")
1834
 
5199 mandeep.dh 1835
    catalog_client.reserveItemInWarehouse(lineitem.item_id, warehouse.id, lineitem.quantity)
5110 mandeep.dh 1836
    __update_inventory_reservation(order)
1837
 
1838
    order.warehouse_id = warehouse.billingWarehouseId
5147 mandeep.dh 1839
    order.fulfilmentWarehouseId = warehouse.id
3469 chandransh 1840
    session.commit()
1841
    return order
3553 chandransh 1842
 
4647 rajveer 1843
def add_delay_reason(order_id, reason, further_delay, delayReasonText):
3553 chandransh 1844
    '''
3994 chandransh 1845
    Adds a delay reason to the order and updates the expected delivery time.
3553 chandransh 1846
    '''
1847
    order = get_order(order_id)
1848
    try:
3581 chandransh 1849
        order.delay_reason = DelayReason._VALUES_TO_NAMES[reason]
4647 rajveer 1850
        order.delayReasonText = delayReasonText
4009 chandransh 1851
        actual_delivery_delay = adjust_delivery_time(order.expected_delivery_time, further_delay)
1852
        order.expected_delivery_time = order.expected_delivery_time + datetime.timedelta(days=actual_delivery_delay)
4102 chandransh 1853
 
4842 rajveer 1854
        actual_shipping_delay = adjust_delivery_time(order.expected_shipping_time, further_delay)
1855
        order.expected_shipping_time = order.expected_shipping_time + datetime.timedelta(days=actual_shipping_delay)
4102 chandransh 1856
 
3553 chandransh 1857
        session.commit()
4008 mandeep.dh 1858
 
1859
        try:
1860
            transaction_requiring_extra_processing = TransactionRequiringExtraProcessing()
1861
            transaction_requiring_extra_processing.category = 'DELAYED_DELIVERY'
1862
            transaction_requiring_extra_processing.transaction_id = order.transaction_id
1863
            session.commit()
1864
        except Exception as e:
4065 mandeep.dh 1865
            print 'Could not persist transaction id: ' + str(order.transaction_id) + ' for further processing due to: ' + str(e)
4008 mandeep.dh 1866
 
3553 chandransh 1867
        return True
1868
    except:
3994 chandransh 1869
        print sys.exc_info()[0]
3553 chandransh 1870
        return False
3956 chandransh 1871
 
1872
def reconcile_cod_collection(collected_amount_map, xferBy, xferTxnId, xferDate):
1873
    unprocessed_awbs = {}
1874
    for awb, amount in collected_amount_map.iteritems():
1875
        try:
1876
            order = Order.query.filter_by(airwaybill_no=awb).one()
1877
        except NoResultFound:
1878
            unprocessed_awbs[awb] = "No order was found for the given AWB: " + awb
1879
            continue
1880
        except MultipleResultsFound:
1881
            unprocessed_awbs[awb] = "Multiple orders were found for the given AWB:" + awb
1882
            continue
1883
 
1884
        if order.cod_reconciliation_timestamp:
1885
            #This order has been processed already! This may be a re-run. Let's allow other orders to be processed.
1886
            continue
1887
 
1888
        if order.status < OrderStatus.DELIVERY_SUCCESS:
1889
            #Order has not been delivered yet. No way we can receive the payment.
1890
            unprocessed_awbs[awb] = "Payment has been received for order: " + str(order.id) + " before delivery reconciliation"
1891
            continue
1892
 
4252 rajveer 1893
        ##As per ticket #743 if amount difference less than 0.5 we should reconcile
1894
        if abs(amount - order.total_amount) > 0.5:
3956 chandransh 1895
            #Received amount is less than or more than the order amount. Mustn't let the user proceed.
1896
            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)
1897
            continue
1898
 
1899
        try:
1900
            payment_client = PaymentClient().get_client()
1901
            payment_client.partiallyCapturePayment(order.transaction.id, amount, xferBy, xferTxnId, xferDate)
1902
        except Exception:
1903
            unprocessed_awbs[awb] = "We were unable to partially capture payment for order id " + str(order.id) + ", AWB: " + awb
1904
            continue
1905
 
1906
        #Payment has been recorded now. We can update the order peacefully.
1907
        order.cod_reconciliation_timestamp = datetime.datetime.now()
1908
        session.commit()
3469 chandransh 1909
 
3956 chandransh 1910
    return unprocessed_awbs
4008 mandeep.dh 1911
 
1912
def get_transactions_requiring_extra_processing(category):
4065 mandeep.dh 1913
    """
1914
    Returns the list of transaction ids that require some extra processing and
1915
    which belong to a particular category. This is currently used by CRM
1916
    application. If no such transaction ids are present, it returns an empty list.
1917
    """
1918
    query = TransactionRequiringExtraProcessing.query
4008 mandeep.dh 1919
 
4065 mandeep.dh 1920
    if category is not None:
1921
        query = query.filter_by(category = ExtraTransactionProcessingType._VALUES_TO_NAMES.get(category))
4008 mandeep.dh 1922
 
4065 mandeep.dh 1923
    return [a.transaction_id for a in query.all()]
4008 mandeep.dh 1924
 
1925
def mark_transaction_as_processed(transactionId, category):
4065 mandeep.dh 1926
    """
1927
    Marks a particular transaction as processed for a particular cateogory.
1928
    It essentially deletes the transaction id record for a particular
1929
    processing type category (if present) from DB.
1930
    This is currently used by CRM application.
1931
    """
4008 mandeep.dh 1932
    TransactionRequiringExtraProcessing.query.filter_by(transaction_id = transactionId).filter_by(category = ExtraTransactionProcessingType._VALUES_TO_NAMES.get(category)).delete()
1933
    session.commit()
1934
 
4018 chandransh 1935
def get_item_wise_risky_orders_count():
1936
    """
1937
    Returns a map containing the number of risky orders keyed by item id. A risky order
1938
    is defined as one whose shipping date is about to expire.
1939
    """
1940
    item_wise_risky_orders_count = {}
4019 chandransh 1941
    shipping_cutoff_time = (datetime.datetime.now() + datetime.timedelta(days = 1)).replace(hour=PREPAID_SHIPPING_CUTOFF_TIME, minute=0, second=0)
4018 chandransh 1942
    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()
1943
    for order in orders:
1944
        for lineitem in order.lineitems:
1945
            quantity = lineitem.quantity
1946
            if item_wise_risky_orders_count.has_key(lineitem.item_id):
1947
                quantity = quantity + item_wise_risky_orders_count[lineitem.item_id]
1948
 
1949
            item_wise_risky_orders_count[lineitem.item_id] = quantity
1950
    return item_wise_risky_orders_count
1951
 
4324 mandeep.dh 1952
def update_shipment_address(order_id, address_id):
1953
    """
1954
    Updates shipment address of an order. Delivery and shipping date estimates
1955
    etc. are also updated here.
1956
 
1957
    Throws TransactionServiceException in case address change is not
1958
    possible due to certain reasons such as new pincode in address is
1959
    not serviceable etc.
1960
 
1961
    Parameters:
1962
     - orderId
1963
     - addressId
1964
    """
1965
    user_client = UserClient().get_client()
1966
    address     = user_client.getAddressById(address_id)
1967
    order       = get_order(order_id)
1968
 
4630 mandeep.dh 1969
    type = DeliveryType.PREPAID
1970
    if order.cod:
1971
        type = DeliveryType.COD
1972
 
4324 mandeep.dh 1973
    logistics_client = LogisticsClient().get_client()
4630 mandeep.dh 1974
    logistics_info = logistics_client.getLogisticsEstimation(order.lineitems[0].item_id, address.pin, type)
4324 mandeep.dh 1975
 
1976
    # Check for new estimate. Raise exception if new address is not serviceable
1977
    if logistics_info.deliveryTime == -1:
1978
        raise TransactionServiceException(1, 'Location not serviceable')
1979
 
1980
    # COD services are not available everywhere
1981
    if order.cod:
4868 rajveer 1982
        if not logistics_info.codAllowed:
4324 mandeep.dh 1983
            raise TransactionServiceException(2, 'COD service not available')
1984
 
1985
    current_time = datetime.datetime.now()
1986
    logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
1987
    logistics_info.shippingTime = adjust_delivery_time(current_time, logistics_info.shippingTime)
1988
 
1989
    order.customer_name         = address.name
1990
    order.customer_pincode      = address.pin
1991
    order.customer_address1     = address.line1
1992
    order.customer_address2     = address.line2
1993
    order.customer_city         = address.city
1994
    order.customer_state        = address.state
1995
    order.customer_mobilenumber = address.phone
1996
 
1997
    if order.cod:
1998
        order.expected_shipping_time = (current_time + datetime.timedelta(days=logistics_info.shippingTime)).replace(hour=COD_SHIPPING_CUTOFF_TIME, minute=0, second=0)
1999
    else:
2000
        order.expected_shipping_time = (current_time + datetime.timedelta(days=logistics_info.shippingTime)).replace(hour=PREPAID_SHIPPING_CUTOFF_TIME, minute=0, second=0)
2001
 
2002
    order.expected_delivery_time = current_time + datetime.timedelta(days=logistics_info.deliveryTime)
2003
    order.promised_shipping_time = order.expected_shipping_time
2004
    order.promised_delivery_time = order.expected_delivery_time 
2005
 
2006
    session.commit()
2007
 
4247 rajveer 2008
def mark_order_cancellation_request_received(orderId):
2009
    """
2010
    Mark order as cancellation request received. If customer sends request of cancellation of
2011
    a particular order, this method will be called. It will just change status of the order
2012
    depending on its current status. It also records the previous status, so that we can move
2013
    back to that status if cancellation request is denied.
2014
 
2015
    Parameters:
2016
     - orderId
2017
    """
4662 rajveer 2018
    status_transition = {OrderStatus.COD_VERIFICATION_PENDING : OrderStatus.CANCEL_REQUEST_RECEIVED,
4247 rajveer 2019
             OrderStatus.SUBMITTED_FOR_PROCESSING : OrderStatus.CANCEL_REQUEST_RECEIVED,
2020
             OrderStatus.INVENTORY_LOW : OrderStatus.CANCEL_REQUEST_RECEIVED,
4306 rajveer 2021
             OrderStatus.LOW_INV_PO_RAISED : OrderStatus.CANCEL_REQUEST_RECEIVED,
2022
             OrderStatus.LOW_INV_REVERSAL_IN_PROCESS : OrderStatus.CANCEL_REQUEST_RECEIVED,
2023
             OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT : OrderStatus.CANCEL_REQUEST_RECEIVED,
4247 rajveer 2024
             OrderStatus.ACCEPTED : OrderStatus.CANCEL_REQUEST_RECEIVED,
2025
             OrderStatus.BILLED : OrderStatus.CANCEL_REQUEST_RECEIVED,
2026
             OrderStatus.PAYMENT_FLAGGED : OrderStatus.CANCEL_REQUEST_RECEIVED
2027
             }
4662 rajveer 2028
 
2029
    order = get_order(orderId)
4247 rajveer 2030
    if order.status not in status_transition.keys():
2031
        raise TransactionServiceException(114, "This order can't be considered for cancellation")
2032
 
4662 rajveer 2033
 
4247 rajveer 2034
    order.previousStatus = order.status
2035
    order.status = OrderStatus.CANCEL_REQUEST_RECEIVED
2036
    order.statusDescription = "Cancellation request received from user"
2037
    session.commit()
2038
 
4662 rajveer 2039
def mark_order_as_lost_in_transit(orderId):
2040
    """
2041
    Parameters:
2042
     - orderId
2043
    """
2044
    order = get_order(orderId)
4910 phani.kuma 2045
    if order.status not in [OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST, OrderStatus.SHIPPED_TO_DESTINATION_CITY, OrderStatus.REACHED_DESTINATION_CITY, OrderStatus.FIRST_DELIVERY_ATTEMPT_MADE]:
4662 rajveer 2046
        raise TransactionServiceException(115, "This order can't be marked as lost in transit")
2047
    order.status = OrderStatus.LOST_IN_TRANSIT
2048
    order.statusDescription = "Lost in Transit"
2049
    session.commit()
2050
 
4258 rajveer 2051
def mark_transaction_as_payment_flag_removed(transactionId):
4247 rajveer 2052
    """
4258 rajveer 2053
    If we and/or payment gateway has decided to accept the payment, this method needs to be called.
2054
    Changed transaction and all orders status to payment accepted.
4247 rajveer 2055
 
2056
    Parameters:
4258 rajveer 2057
     - transactionId
4247 rajveer 2058
    """
4258 rajveer 2059
    transaction = get_transaction(transactionId)
2060
    transaction.status = TransactionStatus.AUTHORIZED
2061
    for order in transaction.orders:
2062
        order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
2063
        order.statusDescription = "Submitted to warehouse"
4247 rajveer 2064
    session.commit()
2065
 
4259 anupam.sin 2066
def refund_transaction(transactionId, refundedBy, reason):
2067
    """
2068
    This method is called when a flagged payment is deemed unserviceable and the corresponding orders
2069
    need to be cancelled
2070
 
2071
    Parameters:
2072
     - transactionId
2073
    """
2074
    transaction = get_transaction(transactionId)
2075
    transaction.status = TransactionStatus.FAILED
2076
    for order in transaction.orders:
2077
        refund_order(order.id, refundedBy, reason)
2078
    session.commit()
2079
 
4247 rajveer 2080
def mark_order_cancellation_request_denied(orderId):
2081
    """
4283 anupam.sin 2082
    If we decide to not to cancel order, we will move the order to previous status.
4247 rajveer 2083
 
2084
    Parameters:
2085
     - orderId
2086
    """
2087
    order = get_order(orderId)
2088
    order.status = order.previousStatus
2089
    order.previousStatus = None
2090
    order.statusDescription = "Cancellation request denied"
2091
    session.commit()
2092
 
2093
def mark_order_cancellation_request_confirmed(orderId):
2094
    """
2095
    If we decide to to cancel order, CRM will call this method to move the status of order to
2096
    cancellation request confirmed. After this OM will be able to cancel the order.
2097
 
2098
    Parameters:
2099
     - orderId
2100
    """
2101
    order = get_order(orderId)
2102
    order.status = OrderStatus.CANCEL_REQUEST_CONFIRMED
2103
    order.statusDescription = "Cancellation request confirmed"
2104
    session.commit()
2105
 
4285 rajveer 2106
def accept_orders_for_item_id(itemId, inventory):
2107
    """
2108
    Marks the orders as ACCEPTED for the given itemId and inventory. It also updates the accepted timestamp. If the
2109
    given order is not a COD order, it also captures the payment if the same has not been captured.
2110
 
2111
    Parameters:
2112
     - itemId
2113
     - inventory
2114
    """
4938 rajveer 2115
    orders = Order.query.filter(Order.warehouse_id == 5).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 2116
    for order in orders:
4301 rajveer 2117
        if inventory > 0:
2118
            lineitem = order.lineitems[0]
2119
            if itemId == lineitem.item_id:
2120
                try:
2121
                    accept_order(order.id)
2122
                    inventory = inventory - lineitem.quantity
2123
                except:
2124
                    logging.info("Unable to accept the order")
2125
        else:
2126
            order_outofstock(order.id)
4285 rajveer 2127
    return
2128
 
4607 rajveer 2129
def get_slipped_sipping_date_orders():
4662 rajveer 2130
    return Order.query.filter(Order.status.in_(tuple([OrderStatus.COD_VERIFICATION_PENDING, OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW, OrderStatus.LOW_INV_PO_RAISED, OrderStatus.LOW_INV_REVERSAL_IN_PROCESS, OrderStatus.ACCEPTED, OrderStatus.BILLED]))).filter(Order.promised_shipping_time <= datetime.datetime.now()).order_by(Order.promised_shipping_time).all()
4709 rajveer 2131
 
2132
def get_cancelled_orders(cancelDateFrom, cancelDateTo):
2133
    return Order.query.filter(Order.status == OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY).filter(Order.refund_timestamp >= cancelDateFrom).filter(Order.refund_timestamp <= cancelDateTo).all()
4607 rajveer 2134
 
4369 rajveer 2135
def mark_orders_as_po_raised(vendorId, itemId, quantity, estimate, isReminder):
2136
    if isReminder:
2137
        statuses = tuple([OrderStatus.LOW_INV_PO_RAISED_TIMEOUT, OrderStatus.LOW_INV_REVERSAL_TIMEOUT])
2138
    else:
2139
        statuses = tuple([OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW])
2140
 
2141
    orders = Order.query.filter(Order.status.in_(statuses)).order_by(Order.expected_shipping_time).all()
4303 rajveer 2142
    for order in orders:
2143
        lineitem = order.lineitems[0]
2144
        if quantity >= lineitem.quantity and itemId == lineitem.item_id:
2145
            if estimate > 0:
2146
                add_delay_reason(order.id, DelayReason.OTHERS, estimate)
2147
            order.status = OrderStatus.LOW_INV_PO_RAISED
4362 rajveer 2148
            order.statusDescription = "PO Raised"
4303 rajveer 2149
            quantity = quantity - lineitem.quantity
2150
            store_inventory_action(order, itemId, HotspotAction.PO_RAISED, estimate, lineitem.quantity)
2151
            session.commit()
2152
 
4369 rajveer 2153
def mark_orders_as_reversal_initiated(vendorId, itemId, quantity, estimate, isReminder):
2154
    if isReminder:
2155
        statuses = tuple([OrderStatus.LOW_INV_PO_RAISED_TIMEOUT, OrderStatus.LOW_INV_REVERSAL_TIMEOUT])
2156
    else:
2157
        statuses = tuple([OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW])
2158
    orders = Order.query.filter(Order.status.in_(statuses)).order_by(Order.expected_shipping_time).all()
4303 rajveer 2159
    for order in orders:
2160
        lineitem = order.lineitems[0]
2161
        if quantity >= lineitem.quantity and itemId == lineitem.item_id:
2162
            if estimate > 0:
2163
                add_delay_reason(order.id, DelayReason.OTHERS, estimate)
2164
            order.status = OrderStatus.LOW_INV_REVERSAL_IN_PROCESS
4362 rajveer 2165
            order.statusDescription = "Reversal Initiated"
4303 rajveer 2166
            quantity = quantity - lineitem.quantity
2167
            store_inventory_action(order, itemId, HotspotAction.REVERSAL_INITIATED, estimate, lineitem.quantity)
2168
            session.commit()
2169
 
4369 rajveer 2170
def mark_orders_as_not_available(vendorId, itemId, quantity, estimate, isReminder):
2171
    if isReminder:
2172
        statuses = tuple([OrderStatus.LOW_INV_PO_RAISED_TIMEOUT, OrderStatus.LOW_INV_REVERSAL_TIMEOUT])
2173
    else:
2174
        statuses = tuple([OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW])
2175
 
2176
    orders = Order.query.filter(Order.status.in_(statuses)).order_by(Order.expected_shipping_time).all()
4303 rajveer 2177
    for order in orders:
2178
        lineitem = order.lineitems[0]
2179
        if quantity >= lineitem.quantity and itemId == lineitem.item_id:
2180
            order.status = OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT
4362 rajveer 2181
            order.statusDescription = "Not Available"
4303 rajveer 2182
            quantity = quantity - lineitem.quantity
2183
            store_inventory_action(order, itemId, HotspotAction.NOT_AVAILABLE, estimate, lineitem.quantity)
2184
            session.commit()
2185
 
2186
def store_inventory_action(order, itemId, hotspotAction, estimate, quantity):
4369 rajveer 2187
    orderInv = OrderInventory.get_by(order_id=order.id)
2188
    if not orderInv:
2189
        orderInv = OrderInventory()
2190
        orderInv.order = order
4303 rajveer 2191
    orderInv.hotspotAction = hotspotAction  
2192
    orderInv.estimate = estimate
2193
    orderInv.itemId = itemId
2194
    orderInv.timestamp = datetime.datetime.now()
2195
    orderInv.quantity = quantity
2196
 
4556 mandeep.dh 2197
'''    
4369 rajveer 2198
def mark_orders_as_timeout(vendorId):
2199
    ret_timeouts = {}
2200
    orderInvs = OrderInventory.query.all()
2201
    for orderInv in orderInvs:
2202
        if orderInv.timestamp +  timedelta(days=orderInv.estimate) < datetime.datetime.now():
2203
            if not ret_timeouts.has_key(orderInv.itemId):
2204
                timeout = TimeoutSummary()
2205
                ret_timeouts[orderInv.itemId] = timeout
2206
            else:
2207
                timeout = ret_timeouts.get(orderInv.itemId)
2208
            if orderInv.hotspotAction == HotspotAction.PO_RAISED and orderInv.order.status == OrderStatus.LOW_INV_PO_RAISED:
2209
                if timeout.poRaised:
2210
                    timeout.poRaised += 1
2211
                else:
2212
                    timeout.poRaised = 1
2213
 
2214
                if timeout.poEstimate:
2215
                    timeout.poEstimate += orderInv.estimate
2216
                else:
2217
                    timeout.poEstimate = orderInv.estimate
2218
                orderInv.order.status = OrderStatus.LOW_INV_PO_RAISED_TIMEOUT
2219
                orderInv.order.statusDescription = "PO Raised Timeout"
2220
            elif orderInv.hotspotAction == HotspotAction.REVERSAL_INITIATED and orderInv.order.status == OrderStatus.LOW_INV_REVERSAL_IN_PROCESS:
2221
                if timeout.reversalInitiated:
2222
                    timeout.reversalInitiated += 1
2223
                else:
2224
                    timeout.reversalInitiated = 1
2225
 
2226
                if timeout.reversalEstimate:
2227
                    timeout.reversalEstimate += orderInv.estimate
2228
                else:
2229
                    timeout.reversalEstimate = orderInv.estimate
2230
                orderInv.order.status = OrderStatus.LOW_INV_REVERSAL_TIMEOUT
2231
                orderInv.order.statusDescription = "Reversal Initiated Timeout"
2232
            else:
2233
                orderInv.delete()
2234
    session.commit()
2235
    return ret_timeouts
4556 mandeep.dh 2236
'''
2237
 
2238
 
2239
def mark_orders_as_timeout(vendorId):
2240
    ret_timeouts = {}
2241
    orderInvs = OrderInventory.query.all()
2242
    for orderInv in orderInvs:
2243
        if not ret_timeouts.has_key(orderInv.itemId):
2244
            timeout = TimeoutSummary()
2245
            ret_timeouts[orderInv.itemId] = timeout
2246
        else:
2247
            timeout = ret_timeouts.get(orderInv.itemId)
2248
        if orderInv.hotspotAction == HotspotAction.PO_RAISED and orderInv.order.status == OrderStatus.LOW_INV_PO_RAISED:
2249
            if timeout.poRaised:
2250
                timeout.poRaised += 1
2251
            else:
2252
                timeout.poRaised = 1
2253
 
2254
            if timeout.poEstimate:
2255
                timeout.poEstimate = max(orderInv.estimate, timeout.poEstimate)
2256
            else:
2257
                timeout.poEstimate = orderInv.estimate
2258
        elif orderInv.hotspotAction == HotspotAction.REVERSAL_INITIATED and orderInv.order.status == OrderStatus.LOW_INV_REVERSAL_IN_PROCESS:
2259
            if timeout.reversalInitiated:
2260
                timeout.reversalInitiated += 1
2261
            else:
2262
                timeout.reversalInitiated = 1
2263
 
2264
            if timeout.reversalEstimate:
2265
                timeout.reversalEstimate = max(orderInv.estimate, timeout.reversalEstimate)
2266
            else:
2267
                timeout.reversalEstimate = orderInv.estimate
2268
        orderInv.order.status = OrderStatus.INVENTORY_LOW
2269
        orderInv.order.statusDescription = "Low Inventory"
2270
        orderInv.delete()
2271
    session.commit()
2272
    return ret_timeouts
2273
 
4386 anupam.sin 2274
def get_order_for_awb(awb):
2275
    order = Order.get_by(airwaybill_no=awb)
2276
    if not order:
2277
        raise TransactionServiceException(108, "no such order")
2278
 
2279
    return order
4369 rajveer 2280
 
4910 phani.kuma 2281
def get_orders_for_provider_for_status(provider_id, order_status_list):
2282
    if not provider_id or not order_status_list:
4506 phani.kuma 2283
        raise TransactionServiceException(101, "bad provider id or order status")
4910 phani.kuma 2284
    doa_provider = False
2285
    for order_status in order_status_list:
2286
        if order_status in [OrderStatus.DOA_PICKUP_CONFIRMED, OrderStatus.RET_PICKUP_CONFIRMED]:
2287
            doa_provider = True
2288
    if doa_provider:
2289
        query = Order.query.filter_by(doa_logistics_provider_id = provider_id).filter(Order.status.in_(order_status_list))
4815 phani.kuma 2290
    else:
4910 phani.kuma 2291
        query = Order.query.filter_by(logistics_provider_id = provider_id).filter(Order.status.in_(order_status_list))
4506 phani.kuma 2292
    return query.all()
4386 anupam.sin 2293
 
4600 varun.gupt 2294
def get_billed_orders_for_vendor(vendor_id, billing_date_from, billing_date_to):
2295
    query = Order.query.filter_by(vendorId = vendor_id)
2296
    query = query.filter(Order.status != OrderStatus.PAYMENT_PENDING)
2297
    if billing_date_from:
2298
        query = query.filter(Order.billing_timestamp >= billing_date_from)
2299
 
2300
    if billing_date_to:
2301
        query = query.filter(Order.billing_timestamp <= billing_date_to)
2302
 
2303
    return query.all()
2304
 
4875 varun.gupt 2305
def get_orders_where_vendor_not_paid(vendor_id):
4885 varun.gupt 2306
    query = Order.query.filter_by(vendorId = vendor_id)
2307
    query = query.filter(Order.billing_timestamp != None)
5139 varun.gupt 2308
    query = query.filter(Order.vendor_paid != True)
5189 varun.gupt 2309
    orderStatusGroup = OrderStatusGroups()
2310
    query = query.filter(not_(Order.status.in_(orderStatusGroup.refundedOrders)))
5208 varun.gupt 2311
    #query = query.filter(not_(Order.status.in_([15,31,32,33,34,48,50,54,56,70,72,76,74,79])))
2312
    #(15,31,32,33,34,48,54,70,72,74)
4885 varun.gupt 2313
    return query.all()
4875 varun.gupt 2314
 
4600 varun.gupt 2315
def save_bluedart_settlements(map_awb_and_amount):
2316
    payment_client = PaymentClient().get_client()
2317
 
2318
    for awb, amount in map_awb_and_amount.iteritems():
2319
        order = Order.get_by(airwaybill_no = awb)
2320
 
2321
        payment = payment_client.getSuccessfulPaymentForTxnId(order.transaction_id)
2322
        settlement = PaymentSettlement()
2323
        settlement.paymentId = payment.paymentId
2324
        settlement.paymentGatewayId = payment.gatewayId
2325
        settlement.netCollection = amount
2326
        session.commit()
2327
 
4905 varun.gupt 2328
def save_payment_settlements(settlementDate, paymentGatewayId, referenceId, serviceTax, otherCharges, netCollection):
4600 varun.gupt 2329
 
2330
    settlement = PaymentSettlement()
2331
    settlement.settlementDate = settlementDate
2332
    settlement.paymentGatewayId = paymentGatewayId
4905 varun.gupt 2333
    settlement.referenceId = referenceId
4600 varun.gupt 2334
    settlement.serviceTax = serviceTax
2335
    settlement.otherCharges = otherCharges
2336
    settlement.netCollection = netCollection
2337
    session.commit()
2338
 
5189 varun.gupt 2339
def get_settlement_for_referenceId(reference_id, is_refund = False):
2340
    query = PaymentSettlement.query.filter_by(referenceId = reference_id)
4600 varun.gupt 2341
 
5189 varun.gupt 2342
    if is_refund:
2343
        query = query.filter(PaymentSettlement.netCollection < 0)
2344
    else:
2345
        query = query.filter(PaymentSettlement.netCollection > 0)
2346
 
2347
    return query.first()
4600 varun.gupt 2348
 
2349
def save_ebs_settlement_summary(settlement_id, settlement_date, transaction_date_from, transaction_date_to, amount):
2350
    summary = EBSSettlementSummary()
2351
    summary.settlementId = settlement_id
2352
    summary.settlementDate = settlement_date
2353
    summary.transactionDateFrom = transaction_date_from
2354
    summary.transactionDateTo = transaction_date_to
2355
    summary.amount = amount
2356
    summary.detailsUploaded = False
2357
    session.commit()
2358
 
2359
def get_ebs_settlement_summaries():
2360
    summaries = EBSSettlementSummary.query.filter_by(detailsUploaded = False).order_by(EBSSettlementSummary.transactionDateFrom).all()
2361
    summary_map = {}
2362
 
2363
    for summary in summaries:
2364
        transactionDateFrom = str(summary.transactionDateFrom.year) + '-' + str(summary.transactionDateFrom.month) + '-' + str(summary.transactionDateFrom.day)
2365
        transactionDateTo = str(summary.transactionDateTo.year) + '-' + str(summary.transactionDateTo.month) + '-' + str(summary.transactionDateTo.day)
2366
 
2367
        summary_map[summary.settlementId] = "%s to %s" %(transactionDateFrom, transactionDateTo)
2368
 
2369
    return summary_map
2370
 
2371
def get_ebs_settlement_date(settlement_id):
2372
    summary = EBSSettlementSummary.get_by(settlementId = settlement_id)
2373
 
2374
    if summary:
2375
        return summary.settlementDate
2376
 
2377
def mark_ebs_settlement_uploaded(settlement_id):
2378
    summary = EBSSettlementSummary.get_by(settlementId = settlement_id)
2379
 
2380
    if summary:
2381
        summary.detailsUploaded = True
2382
        session.commit()
4715 varun.gupt 2383
 
2384
def get_settlements_by_date(settlement_date_from, settlement_date_to, is_refund):
2385
    query = PaymentSettlement.query
4600 varun.gupt 2386
 
4715 varun.gupt 2387
    if settlement_date_from:
2388
        query = query.filter(PaymentSettlement.settlementDate >= settlement_date_from)
2389
 
2390
    if settlement_date_to:
2391
        query = query.filter(PaymentSettlement.settlementDate <= settlement_date_to)
2392
 
4749 varun.gupt 2393
    if is_refund is True:
2394
        query = query.filter(PaymentSettlement.netCollection < 0.0)
2395
    else:
2396
        query = query.filter(PaymentSettlement.netCollection > 0.0)
4715 varun.gupt 2397
 
4749 varun.gupt 2398
    return query.all()
4715 varun.gupt 2399
 
2400
def get_reshipped_order_ids(order_ids):
2401
    reshipped_order_ids = []
2402
    return [order.new_order_id for order in Order.query.filter(Order.new_order_id.in_(order_ids)).all()]
2403
 
4749 varun.gupt 2404
def get_shipping_confirmation_email_body(order):
2405
 
2406
    html = """
2407
<html>
2408
<body>
2409
<div>
2410
    <p>Dear Customer,</p>
2411
    <p>
4885 varun.gupt 2412
        We are pleased to inform that we have shipped the order: $order_id for your product $product_name on $shipping_datetime. 
5139 varun.gupt 2413
        The shipment will be delivered to you via $courier_name Courier Service vide AWB# $awb.
4749 varun.gupt 2414
    </p>
2415
    <p>
2416
        Expected delivery date for your order is $expected_delivery_date. 
2417
        The product can be delivered to you between business hours of 10am to 6pm. 
2418
        You can login to your account on our site and under "Open Orders", please click the AWB and check the current shipment updates for your product.
2419
    </p>
2420
    <p>
2421
        For scheduling the delivery of your product at some specific timings, we recommend you to contact the helpline for Bluedart/Aramex with your complete AWB#.
2422
    </p>
5139 varun.gupt 2423
    <p>$courier_name: $courier_phone</p>
4749 varun.gupt 2424
    <p>
2425
        Warm Regards,<br />
2426
        Saholic Team
2427
    </p>
4750 varun.gupt 2428
</div>
4749 varun.gupt 2429
</body>
2430
</html>
2431
    """
5139 varun.gupt 2432
    logistics_providers = {1: {'name': 'BlueDart', 'phone': '011-66111234'}, 2: {'name': 'Aramex', 'phone': '0124- 39419900'}}
2433
    provider_name = logistics_providers[order.logistics_provider_id]['name']
2434
    provider_phone = logistics_providers[order.logistics_provider_id]['phone']
2435
 
4749 varun.gupt 2436
    dt = datetime.datetime.strptime(str(order.shipping_timestamp), "%Y-%m-%d %H:%M:%S")
4885 varun.gupt 2437
    shipping_date = dt.strftime("%A, %d %B %Y %I:%M%p")
4749 varun.gupt 2438
    product = "%s %s %s" % (order.lineitems[0].brand, order.lineitems[0].model_name, order.lineitems[0].model_number)
4885 varun.gupt 2439
    new_expected_delivery_timestamp = datetime.datetime.now() + timedelta(adjust_delivery_time(datetime.datetime.now(), (order.promised_delivery_time - order.promised_shipping_time).days))
2440
    new_expected_delivery_date = new_expected_delivery_timestamp.strftime("%A, %d %B %Y")
5139 varun.gupt 2441
    info = dict(order_id = order.id, product_name = product, shipping_datetime = shipping_date, awb = order.airwaybill_no, expected_delivery_date = new_expected_delivery_date, courier_name = provider_name, courier_phone = provider_phone)
4885 varun.gupt 2442
    return Template(html).substitute(info)
4749 varun.gupt 2443
 
2444
def enqueue_shipping_confirmation_email(orders):
4915 varun.gupt 2445
    # Calling helper service on production
2446
    helperClient = HelperClient(host_key = "helper_service_server_host_prod").get_client()
5139 varun.gupt 2447
 
4749 varun.gupt 2448
    for order in orders:
2449
        try:
2450
            emailSubject = 'Shipping Details for Order ID: ' + str(order.id)
2451
            emailBody = get_shipping_confirmation_email_body(order)
4885 varun.gupt 2452
            helperClient.saveUserEmailForSending(order.customer_email, None, emailSubject, emailBody, '', 'ShippingConfirmation')
4749 varun.gupt 2453
        except Exception as e:
2454
            print e
2455
 
4915 varun.gupt 2456
def get_order_distribution_by_status(start_date, end_date):
5067 varun.gupt 2457
    query = session.query(Order.status, func.count(Order.id)).group_by(Order.status)
2458
    query = query.filter(Order.created_timestamp >= start_date)
2459
    query = query.filter(Order.created_timestamp <= end_date)
2460
    return query.all()
4915 varun.gupt 2461
 
5067 varun.gupt 2462
def get_order_ids_for_status(status, start_datetime, end_datetime):
2463
    query = Order.query.filter(Order.status == status)
2464
    query = query.filter(Order.created_timestamp >= start_datetime)
2465
    query = query.filter(Order.created_timestamp <= end_datetime)
2466
    return query.all()
2467
 
5099 varun.gupt 2468
def update_orders_as_paid_to_vendor(order_id):
5139 varun.gupt 2469
    paid_order = Order.get_by(id = order_id)
5099 varun.gupt 2470
 
5139 varun.gupt 2471
    if paid_order.originalOrderId is None:
2472
        paid_order.vendor_paid = True
5099 varun.gupt 2473
        session.commit()
5139 varun.gupt 2474
 
2475
        for order in Order.query.filter(Order.originalOrderId == order_id).all():
2476
            order.vendor_paid = True
2477
            session.commit()
2478
    else:
5208 varun.gupt 2479
        original_order_id = paid_order.originalOrderId
5139 varun.gupt 2480
 
5208 varun.gupt 2481
        for order in Order.query.filter(Order.originalOrderId == original_order_id).all():
5139 varun.gupt 2482
            order.vendor_paid = True
2483
            session.commit()
2484
            original_order_id = order.originalOrderId
2485
 
2486
        original_order = Order.get_by(id = original_order_id)
2487
        if original_order:  original_order.vendor_paid = True
2488
        session.commit()
5099 varun.gupt 2489
 
5208 varun.gupt 2490
def get_refunded_orders_marked_paid():
2491
    orderStatusGroup = OrderStatusGroups()
2492
    return Order.query.filter(Order.vendor_paid == 1).filter(Order.status.in_(orderStatusGroup.refundedOrders)).all()
2493
 
766 rajveer 2494
def close_session():
2495
    if session.is_active:
2496
        print "session is active. closing it."
2783 chandransh 2497
        session.close()
3376 rajveer 2498
 
2499
def is_alive():
2500
    try:
2501
        session.query(Transaction.id).limit(1).one()
2502
        return True
2503
    except:
4343 varun.gupt 2504
        return False