Subversion Repositories SmartDukaan

Rev

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