Subversion Repositories SmartDukaan

Rev

Rev 5368 | Rev 5386 | 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:
5361 mandeep.dh 671
            try:
672
                warehouse_client = WarehouseClient().get_client()
673
                if ItemType.SERIALIZED == item.type:
4773 mandeep.dh 674
                    inventoryItem = warehouse_client.getInventoryItem(serialNumber)
5361 mandeep.dh 675
                else:
676
                    inventoryItem = warehouse_client.getNonSeralizedInventoryItem(item_id, order.fulfilmentWarehouseId)
677
 
678
                if (inventoryItem.itemId != item_id):
679
                    catalog_client = CatalogClient().get_client()
680
                    item = catalog_client.getItem(inventoryItem.itemId)
681
                    scanItemString = " ".join([str(item.brand), str(item.modelName), str(item.modelNumber), str(item.color)])
682
                    lineItemString = " ".join([str(lineitem.brand), str(lineitem.model_name), str(lineitem.model_number), str(lineitem.color)])
683
                    raise TransactionServiceException(110, 'Trying to scan ' + scanItemString + ' instead of ' + lineItemString)
684
 
685
                if ItemType.SERIALIZED == item.type:
5110 mandeep.dh 686
                    inventoryItem = warehouse_client.scanSerializedItemForOrder(serialNumber, ScanType.SALE, orderId, order.fulfilmentWarehouseId, lineitem.quantity, order.warehouse_id)
5361 mandeep.dh 687
                else:
688
                    inventoryItem = warehouse_client.scanForOrder(inventoryItem, ScanType.SALE, lineitem.quantity, order.id, order.fulfilmentWarehouseId, order.warehouse_id)
689
 
690
                lineitem.transfer_price = inventoryItem.unitPrice
691
                order.vendorId = inventoryItem.supplierId
692
                catalog_client = CatalogClient().get_client()
693
                warehouse = catalog_client.getWarehouse(order.fulfilmentWarehouseId)
694
                # Fetching GOOD w/h corresponding to the virtual one here
695
                if warehouse.billingWarehouseId is None:
696
                    warehouse = catalog_client.getWarehouses(None, InventoryType.GOOD, warehouse.vendor.id, order.warehouse_id, 0)[0]
697
                    order.fulfilmentWarehouseId = warehouse.id
698
            except WarehouseServiceException as e:
699
                print sys.exc_info()[0]
700
                print 'Could not scan out orders due to: ' + e.message
701
                raise TransactionServiceException(110, e.message)
5123 mandeep.dh 702
        else:
703
            if not warehouse.isAvailabilityMonitored:
704
                catalog_client = CatalogClient().get_client()
705
                catalog_client.addInventory(item.id, warehouse.id, -1 * lineitem.quantity)
4365 mandeep.dh 706
 
5110 mandeep.dh 707
        __update_inventory_reservation(order)
4541 mandeep.dh 708
        session.commit()
4283 anupam.sin 709
        return True
710
    else:
711
        return False
1149 chandransh 712
 
4763 rajveer 713
def add_invoice_number(orderId, invoiceNumber, color):
4579 rajveer 714
    order = Order.get_by(id=orderId)
715
    if not order:
716
        raise TransactionServiceException(101, "No order found for the given order id" + str(orderId))
717
 
718
    if order.status == OrderStatus.ACCEPTED:
719
        order.invoice_number = invoiceNumber
4767 rajveer 720
        if color:
721
            billedOrdersColorMap[orderId] = color;
4579 rajveer 722
    session.commit()
723
 
1220 chandransh 724
def batch_orders(warehouseId):
725
    if not warehouseId:
726
        raise TransactionServiceException(101, "bad warehouse id")
1225 chandransh 727
 
728
    batchno_generator = BatchNoGenerator()
729
    session.commit()
1220 chandransh 730
    query = Order.query.filter_by(warehouse_id=warehouseId)
4592 mandeep.dh 731
    query = query.filter(Order.status == OrderStatus.LOW_INV_PO_RAISED)
1220 chandransh 732
    query = query.order_by(Order.created_timestamp)
733
    pending_orders = query.all()
1225 chandransh 734
 
1220 chandransh 735
    serial_no = 1
736
    for order in pending_orders:
1276 chandransh 737
        order.batchNo = batchno_generator.id
1220 chandransh 738
        order.serialNo = serial_no
739
        serial_no += 1
740
    session.commit() 
741
    pending_orders = query.all()
742
    return pending_orders
743
 
744
def order_outofstock(orderId):
1911 chandransh 745
    '''
746
    Mark order as out of stock
747
    '''
1220 chandransh 748
    order = get_order(orderId)
749
    order.status = OrderStatus.INVENTORY_LOW
750
    order.statusDescription = "Low Inventory"
751
    order.outofstock_timestamp = datetime.datetime.now()
752
    session.commit()
753
    return True
754
 
4789 rajveer 755
def mark_orders_as_shipped_from_warehouse(warehouseId, providerId, cod, orderIds):
4410 rajveer 756
    try:
757
        current_timestamp = datetime.datetime.now()
4789 rajveer 758
        orders = Order.query.filter_by(warehouse_id = warehouseId, logistics_provider_id = providerId, status = OrderStatus.BILLED, cod = cod).all()
4410 rajveer 759
        for order in orders:
4789 rajveer 760
            if order.id in orderIds:
761
                order.status = OrderStatus.SHIPPED_FROM_WH
762
                order.statusDescription = "Order shipped from warehouse"
763
                order.shipping_timestamp = current_timestamp
759 chandransh 764
        session.commit()
4749 varun.gupt 765
 
766
        try:
767
            enqueue_shipping_confirmation_email(orders)
768
        except Exception as e:
769
            print e
770
 
759 chandransh 771
        return True
772
    except:
773
        return False
4410 rajveer 774
 
1113 chandransh 775
def mark_orders_as_picked_up(provider_id, pickup_details):
776
    for awb, pickup_timestamp in pickup_details.iteritems():
1135 chandransh 777
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
2684 chandransh 778
        if order == None or order.status != OrderStatus.SHIPPED_FROM_WH:
2220 chandransh 779
            #raise TransactionServiceException(102, "No order found for the awb: " + awb)
780
            continue
1113 chandransh 781
        order.status = OrderStatus.SHIPPED_TO_LOGST
782
        order.statusDescription = "Order picked up by Courier Company"
1246 chandransh 783
        order.pickup_timestamp = pickup_timestamp
1113 chandransh 784
    session.commit()
1217 chandransh 785
 
4910 phani.kuma 786
def get_orders_not_picked_up(provider_id):
1132 chandransh 787
    current_time = datetime.datetime.now()
788
    to_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
4741 phani.kuma 789
    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 790
    return orders_not_picked_up
791
 
1132 chandransh 792
def mark_orders_as_delivered(provider_id, delivered_orders):
793
    for awb, detail in delivered_orders.iteritems():
1135 chandransh 794
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
4910 phani.kuma 795
        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 796
            continue
797
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
1132 chandransh 798
        order.status = OrderStatus.DELIVERY_SUCCESS
799
        order.statusDescription = "Order delivered"
4910 phani.kuma 800
        timestamp, receiver = detail.split('|')
801
        if order.first_dlvyatmp_timestamp is None:
802
            order.first_dlvyatmp_timestamp = timestamp
803
        order.delivery_timestamp = timestamp
804
        order.receiver = receiver
3578 mandeep.dh 805
        update_trust_level(order)
1132 chandransh 806
    session.commit()
807
 
4712 rajveer 808
def mark_order_as_delivered(orderId, deliveryTimestamp, receiver):
809
    order = Order.get_by(id=orderId)
4982 rajveer 810
    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 811
        raise TransactionServiceException(101, "Either wrond order id or invalid state " + str(orderId))
812
 
4910 phani.kuma 813
    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 814
        order.delivery_timestamp = deliveryTimestamp
815
        order.receiver = receiver
816
    order.status = OrderStatus.DELIVERY_SUCCESS
817
    order.statusDescription = "Order delivered"
818
    update_trust_level(order)
819
    session.commit()
820
 
4910 phani.kuma 821
def mark_orders_as_rto(provider_id, returned_orders):
1135 chandransh 822
    for awb, detail in returned_orders.iteritems():
823
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
4910 phani.kuma 824
        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 825
            continue
826
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
4484 rajveer 827
        order.status = OrderStatus.RTO_IN_TRANSIT
1135 chandransh 828
        order.delivery_timestamp, reason = detail.split('|')
829
        order.statusDescription = "Order Returned to Origin:" + reason
3578 mandeep.dh 830
        update_trust_level(order)
1911 chandransh 831
    session.commit()
1135 chandransh 832
 
4910 phani.kuma 833
def get_rto_orders(provider_id):
834
    current_time = datetime.datetime.now()
835
    to_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
836
    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()
837
    return rto_orders
838
 
1246 chandransh 839
def update_non_delivery_reason(provider_id, undelivered_orders):
840
    for awb, reason in undelivered_orders.iteritems():
841
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
4920 phani.kuma 842
        if order == None or order.status == OrderStatus.FIRST_DELIVERY_ATTEMPT_MADE:
2684 chandransh 843
            continue
844
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
1246 chandransh 845
        order.statusDescription = reason
846
    session.commit()
4910 phani.kuma 847
 
848
def get_non_delivered_orders_by_courier(provider_id):
4581 phani.kuma 849
    current_time = datetime.datetime.now()
850
    today_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
851
    upto_datetime = today_datetime - datetime.timedelta(4)
4910 phani.kuma 852
    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 853
    return orders_not_delivered
1246 chandransh 854
 
4910 phani.kuma 855
def mark_orders_as_local_connected(provider_id, local_connected_orders):
856
    for awb, timestamp in local_connected_orders.iteritems():
857
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
858
        if order == None or order.status not in [OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST]:
859
            #raise TransactionServiceException(102, "No order found for the awb: " + awb)
860
            continue
861
        order.status = OrderStatus.SHIPPED_TO_DESTINATION_CITY
862
        order.statusDescription = "Left Out of Origin City"
863
        order.local_connected_timestamp = timestamp
864
    session.commit()
865
 
866
def get_orders_not_local_connected(provider_id):
867
    current_time = datetime.datetime.now()
868
    to_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
869
    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()
870
    return orders_pending_local_connection
871
 
872
def mark_orders_as_destinationCityReached(provider_id, destination_city_reached_orders):
873
    for awb, timestamp in destination_city_reached_orders.iteritems():
874
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
875
        if order == None or order.status not in [OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST, OrderStatus.SHIPPED_TO_DESTINATION_CITY]:
876
            continue
877
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
878
        order.status = OrderStatus.REACHED_DESTINATION_CITY
879
        order.statusDescription = "Reached Destination City"
880
        order.reached_destination_timestamp = timestamp
881
    session.commit()
882
 
883
def mark_orders_as_firstDeliveryAttempted(provider_id, first_atdl_orders):
884
    for awb, detail in first_atdl_orders.iteritems():
885
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
886
        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]:
887
            continue
888
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
889
        order.status = OrderStatus.FIRST_DELIVERY_ATTEMPT_MADE
890
        order.first_dlvyatmp_timestamp, reason = detail.split('|')
891
        order.statusDescription = reason
892
    session.commit()
893
 
4783 phani.kuma 894
def get_orders_not_met_expected_delivery_date():
895
    current_time = datetime.datetime.now()
896
    today_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
4910 phani.kuma 897
    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 898
    return orders_not_delivered
899
 
4444 rajveer 900
def get_alerts(type, warehouseId, status, timestamp):
901
    query = Alert.query.filter(Alert.warehouseId == warehouseId)
902
    if type != -1 :
903
        query = query.filter(Alert.type == type)
904
    if status != -1 :
905
        query = query.filter(Alert.status == status)
4394 rajveer 906
    if timestamp:
907
        query = query.filter(Alert.timestamp >= to_py_date(timestamp))
4412 rajveer 908
    query = query.order_by(desc(Alert.timestamp))
483 rajveer 909
    return query.all()
910
 
4447 rajveer 911
def add_alert(type, warehouseId, description):
4394 rajveer 912
    alert = Alert()
913
    alert.type = type
914
    alert.status = 1
915
    alert.description = description
916
    alert.timestamp = datetime.datetime.now()
4447 rajveer 917
    alert.warehouseId = warehouseId
4444 rajveer 918
    session.commit()
766 rajveer 919
 
4444 rajveer 920
def mark_alerts_as_seen(warehouseId):
921
    query = Alert.query.filter(Alert.warehouseId == warehouseId).filter(Alert.status == 1)
922
    alerts = query.all()
923
    for alert in alerts:
924
        alert.status = 0    
925
    session.commit()
926
 
1596 ankur.sing 927
def get_valid_order_count():
2851 chandransh 928
    '''
929
    Returns the number of orders which we processed. The reshipped orders are not
930
    counted since there'll always be a new compensating order present.
931
    '''
4682 rajveer 932
    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 933
 
1627 ankur.sing 934
def get_cust_count_with_successful_txn():
2851 chandransh 935
    '''
936
    Returns the number of distinct customers who have done successful transactions.
937
    It uses the sqlalchemy func module to construct an efficient query.
938
    '''
939
    return session.query(func.count(distinct(Order.customer_id))).filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING).scalar()
1627 ankur.sing 940
 
1730 ankur.sing 941
def get_valid_orders_amount_range():
2851 chandransh 942
    '''
943
    Returns a list containing the minimum and maximum amount across all
944
    orders placed with us. No need to consider reshippped orders for min/max
945
    amount of orders.
946
    '''
947
    return session.query(func.min(Order.total_amount), func.max(Order.total_amount)).filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING).one()
1627 ankur.sing 948
 
1886 ankur.sing 949
def get_valid_orders(limit):
2851 chandransh 950
    '''
951
    Returns the last limit number of valid orders placed with us. Ignored the
952
    limit if it's passed as 0. Raises an excpetion if the supplied limit is 
953
    less than 0. 
954
    '''
955
    if limit < 0:
956
        raise TransactionServiceException(101, "Invalid argument limit " + limit)
4662 rajveer 957
    query = Order.query.filter(Order.status >= OrderStatus.COD_VERIFICATION_PENDING)
1886 ankur.sing 958
    query = query.order_by(desc(Order.created_timestamp))
2851 chandransh 959
    if limit != 0:
1886 ankur.sing 960
        query = query.limit(limit)
961
    return query.all()
962
 
2783 chandransh 963
def get_next_invoice_number():
964
    entity_id = InvoiceIDGenerator.query.with_lockmode("update").one()
965
    invoice_number = entity_id.id + 1
966
    entity_id.id = invoice_number
967
    return invoice_number
968
 
2536 chandransh 969
def toggle_doa_flag(order_id):
970
    order = get_order(order_id)
971
    if(order.doaFlag):
972
        order.doaFlag = False
973
    else:
974
        order.doaFlag = True
975
    session.commit()
976
    return order.doaFlag
977
 
4454 rajveer 978
def mark_order_doa_request_received(orderId):
979
    order = get_order(orderId)
980
    if order.status != OrderStatus.DELIVERY_SUCCESS:
981
        return False
982
    order.status = OrderStatus.DOA_REQUEST_RECEIVED
4459 rajveer 983
    order.statusDescription = "DOA Request Received"
4454 rajveer 984
    session.commit()
985
    return True
986
 
987
def mark_order_doa_request_authorized(orderId, isAuthorized):
988
    order = get_order(orderId)
989
    if order.status != OrderStatus.DOA_REQUEST_RECEIVED:
990
        return False
991
    if isAuthorized:
992
        order.status = OrderStatus.DOA_REQUEST_AUTHORIZED
4459 rajveer 993
        order.statusDescription = "DOA Request Authorized"
4454 rajveer 994
    else:
995
        order.status = OrderStatus.DELIVERY_SUCCESS
4459 rajveer 996
        order.statusDescription = "Order delivered"
4454 rajveer 997
    session.commit()
998
    return True
999
 
4488 rajveer 1000
def mark_order_return_request_received(orderId):
1001
    order = get_order(orderId)
1002
    if order.status != OrderStatus.DELIVERY_SUCCESS:
1003
        return False
1004
    order.status = OrderStatus.RET_REQUEST_RECEIVED
1005
    order.statusDescription = "Return Request Received"
1006
    session.commit()
1007
    return True
1008
 
1009
def mark_order_return_request_authorized(orderId, isAuthorized):
1010
    order = get_order(orderId)
1011
    if order.status != OrderStatus.RET_REQUEST_RECEIVED:
1012
        return False
1013
    if isAuthorized:
1014
        order.status = OrderStatus.RET_REQUEST_AUTHORIZED
1015
        order.statusDescription = "Return Request Authorized"
1016
    else:
1017
        order.status = OrderStatus.DELIVERY_SUCCESS
1018
        order.statusDescription = "Order delivered"
1019
    session.commit()
1020
    return True
1021
 
4579 rajveer 1022
def request_pickup_number(order_id, providerId):
2536 chandransh 1023
    order = get_order(order_id)
4495 rajveer 1024
    if order.status != OrderStatus.DELIVERY_SUCCESS and order.status != OrderStatus.DOA_REQUEST_AUTHORIZED and order.status != OrderStatus.RET_REQUEST_AUTHORIZED:
2536 chandransh 1025
        return False
1026
    from_user = 'cnc.center@shop2020.in'
1027
    from_pwd = '5h0p2o2o'
1028
 
4227 rajveer 1029
    subject = "Pickup request from " + order.customer_city
2536 chandransh 1030
    try:
3133 rajveer 1031
        catalog_client = CatalogClient().get_client()
2536 chandransh 1032
        warehouse = catalog_client.getWarehouse(order.warehouse_id)
1033
 
1034
        logistics_client = LogisticsClient().get_client()
4579 rajveer 1035
        provider = logistics_client.getProvider(providerId)
3051 chandransh 1036
        to_addr = provider.details[DeliveryType.PREPAID].email
2536 chandransh 1037
        raw_message = '''
1038
        Dear Sir/Madam,
1039
 
2559 chandransh 1040
        Kindly arrange a pickup today from %(customer_city)s. Pickup and delivery addresses are mentioned below.
2536 chandransh 1041
 
1042
        Pickup CODE: %(provider_code)s
1043
        Total Weight: %(order_weight)s kg
1044
 
2559 chandransh 1045
        Pickup Address:
2536 chandransh 1046
 
1047
        %(customer_address)s
1048
 
1049
        Delivery Address:
1050
 
1051
        %(warehouse_executive)s
1052
        %(warehouse_address)s
1053
        PIN %(warehouse_pin)s
1054
 
1055
        Thanks and Regards
4227 rajveer 1056
        Sandeep Sachdeva
2536 chandransh 1057
        '''
4579 rajveer 1058
 
1059
        if warehouse.id == 7:
1060
            executive = 'Amit Kumar'
1061
        else:
4966 phani.kuma 1062
            executive = 'Dinesh Kumar'
4579 rajveer 1063
 
2559 chandransh 1064
        message = dedent(raw_message) % { 'customer_city' : order.customer_city,
3051 chandransh 1065
                                          'provider_code' : provider.details[DeliveryType.PREPAID].accountNo,
2536 chandransh 1066
                                          'order_weight' : str(order.total_weight),
1067
                                          'customer_address' : __get_order_address(order),
4579 rajveer 1068
                                          'warehouse_executive' : executive,
2536 chandransh 1069
                                          'warehouse_address' : warehouse.location,
4966 phani.kuma 1070
                                          'warehouse_pin' : warehouse.pincode}
5256 rajveer 1071
        to_addresses = [to_addr, 'zaffar.kar@shop2020.in', 'suraj.sharma@shop2020.in']
4966 phani.kuma 1072
 
4606 rajveer 1073
        mail(from_user, from_pwd, to_addresses, subject, message)
4495 rajveer 1074
        if order.status == OrderStatus.RET_REQUEST_AUTHORIZED:
1075
            order.status = OrderStatus.RET_PICKUP_REQUEST_RAISED
1076
            order.statusDescription = "Pick up requested for RETURN"
1077
        else:
1078
            order.status = OrderStatus.DOA_PICKUP_REQUEST_RAISED
1079
            order.statusDescription = "Pick up requested for DOA"
4815 phani.kuma 1080
        order.doa_logistics_provider_id = providerId
2536 chandransh 1081
        session.commit()
1082
        return True
1083
    except Exception as e:
1084
        print sys.exc_info()[0]
1085
        return False
1086
 
4602 rajveer 1087
def authorize_pickup(order_id, pickup_number, providerId):
2536 chandransh 1088
    order = get_order(order_id)
4495 rajveer 1089
    if order.status not in [OrderStatus.DOA_PICKUP_REQUEST_RAISED, OrderStatus.RET_PICKUP_REQUEST_RAISED]:
2536 chandransh 1090
        return False
4815 phani.kuma 1091
    if order.doa_logistics_provider_id is not None:
1092
        providerId = order.doa_logistics_provider_id    #previously we are not storing this so data is taken from omdashboarduser
2536 chandransh 1093
    from_user = 'help@shop2020.in'
1094
    from_pwd = '5h0p2o2o'
1095
    subject = 'Pickup details'
1096
    filename = "/tmp/" +  str(order.id) +".pdf" 
1097
    try:
3133 rajveer 1098
        catalog_client = CatalogClient().get_client()
2536 chandransh 1099
        warehouse = catalog_client.getWarehouse(order.warehouse_id)
1100
 
1101
        logistics_client = LogisticsClient().get_client()
4602 rajveer 1102
        provider = logistics_client.getProvider(providerId)
2536 chandransh 1103
        provider_name = provider.name
1104
 
1105
        to_addr = order.customer_email
1106
        today = date.today().strftime("%d-%B-%Y (%A)")
1107
 
1108
        raw_message = '''
1109
        Dear Mr. %(customer_name)s,
1110
 
4815 phani.kuma 1111
        In reference to the return of order ID %(order_id)d, ''' + __generate_mail_body_for_authorize_pickup(order)
1112
        raw_message = raw_message + '''
2536 chandransh 1113
        Take a printout of the attachment in this mail which contains the delivery address and paste it on the packed parcel.
1114
        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.
1115
 
1116
        Pickup will happen from the below mentioned address:-
1117
 
1118
        %(customer_address)s
1119
 
1120
        Do let us know in case of any concerns
1121
 
1122
        Thanks & Regards
1123
        Saholic Team
1124
        '''
1125
        message = dedent(raw_message) % {'customer_name' : order.customer_name,
1126
                                         'order_id' : order_id,
1127
                                         'provider_name' : provider_name,
1128
                                         'date': today,
1129
                                         'pickup_request_no' : pickup_number,
1130
                                         'customer_address' : __get_order_address(order)}
1131
        print message
1132
        __generate_return_advice(order, warehouse, provider, filename)
3527 chandransh 1133
        mail(from_user, from_pwd, [to_addr], subject, message, [get_attachment_part(filename)])
2536 chandransh 1134
        order.pickupRequestNo = pickup_number
4495 rajveer 1135
        if order.status == OrderStatus.RET_PICKUP_REQUEST_RAISED:
1136
            order.status = OrderStatus.RET_PICKUP_CONFIRMED
1137
            order.statusDescription = "RETURN pick up confirmed"
1138
        else:
1139
            order.status = OrderStatus.DOA_PICKUP_CONFIRMED
1140
            order.statusDescription = "DOA pick up confirmed"
2764 chandransh 1141
        order.doa_auth_timestamp = datetime.datetime.now()
2536 chandransh 1142
        session.commit()
1143
        return True
1144
    except Exception as e:
4234 rajveer 1145
        print sys.exc_info()
4506 phani.kuma 1146
        traceback.print_tb(sys.exc_info()[2])
2536 chandransh 1147
        return False
1148
    finally:
1149
        if os.path.exists(filename):
1150
            os.remove(filename)
1151
 
4815 phani.kuma 1152
def __generate_mail_body_for_authorize_pickup(order):
1153
    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.',
1154
                         '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.',
1155
                         '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.',
1156
                         'Sony Ericsson' : 'we request you to kindly pack the original DOA certificate and the invoice.',
1157
                         '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.',
1158
                         '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.',
1159
                         'Accessories' : 'we request you to kindly pack the box properly with bubble wrap, and send it along with the original product and the invoice.'}
1160
    categories = ["Handsets", "Tablets", "Laptops"]
1161
    lineitem = order.lineitems[0]
1162
    brand = lineitem.brand
1163
    productGroup = lineitem.productGroup
1164
    searchkey = None
1165
    if productGroup not in categories:
1166
        searchkey = 'Accessories'
1167
    elif order.status == OrderStatus.RET_PICKUP_REQUEST_RAISED:
1168
        searchkey = 'Handsets Return'
1169
    elif brand == 'Nokia':
1170
        searchkey = 'Nokia'
1171
    elif brand == 'Micromax':
1172
        searchkey = 'Micromax'
1173
    elif brand == 'Karbonn':
1174
        searchkey = 'Karbonn'
1175
    elif brand == 'Sony Ericsson':
1176
        searchkey = 'Sony Ericsson'
1177
    else:
1178
        searchkey = 'Others Handsets'
1179
    return brand_msgbody_map.get(searchkey)
1180
 
2764 chandransh 1181
def mark_doas_as_picked_up(provider_id, pickup_details):
1182
    for pickupNo, doa_pickup_timestamp in pickup_details.iteritems():
4815 phani.kuma 1183
        order = Order.query.filter_by(pickupRequestNo=pickupNo, doa_logistics_provider_id = provider_id).first()
4452 rajveer 1184
        if order == None or order.status != OrderStatus.DOA_PICKUP_CONFIRMED:
2764 chandransh 1185
            #raise TransactionServiceException(102, "No order found for the awb: " + awb)
1186
            continue
1187
        order.status = OrderStatus.DOA_RETURN_IN_TRANSIT
1188
        order.statusDescription = "DOA picked up by Courier Company"
1189
        order.doa_pickup_timestamp = doa_pickup_timestamp
1190
    session.commit()
1191
 
4910 phani.kuma 1192
def get_doas_not_picked_up(provider_id):
2764 chandransh 1193
    current_time = datetime.datetime.now()
1194
    to_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
4815 phani.kuma 1195
    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 1196
    return orders_not_picked_up
1197
 
4741 phani.kuma 1198
def mark_return_orders_as_picked_up(provider_id, pickup_details):
1199
    for pickupNo, return_order_pickup_timestamp in pickup_details.iteritems():
4815 phani.kuma 1200
        order = Order.query.filter_by(pickupRequestNo=pickupNo, doa_logistics_provider_id = provider_id).first()
4741 phani.kuma 1201
        if order == None or order.status != OrderStatus.RET_PICKUP_CONFIRMED:
1202
            #raise TransactionServiceException(102, "No order found for the awb: " + awb)
1203
            continue
1204
        order.status = OrderStatus.RET_RETURN_IN_TRANSIT
1205
        order.statusDescription = "Return order picked up by Courier Company"
1206
        order.doa_pickup_timestamp = return_order_pickup_timestamp
1207
    session.commit()
1208
 
4910 phani.kuma 1209
def get_return_orders_not_picked_up(provider_id):
4741 phani.kuma 1210
    current_time = datetime.datetime.now()
1211
    to_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
4815 phani.kuma 1212
    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 1213
    return orders_not_picked_up
1214
 
4479 rajveer 1215
def receive_return(order_id, receiveCondition):
2591 chandransh 1216
    order = get_order(order_id)
4365 mandeep.dh 1217
 
4452 rajveer 1218
    if order.status in [OrderStatus.DOA_PICKUP_CONFIRMED, OrderStatus.DOA_RETURN_IN_TRANSIT]:
4479 rajveer 1219
        if receiveCondition == 0:
1220
            order.status = OrderStatus.DOA_RECEIVED_PRESTINE
1221
            order.statusDescription = "DOA package received"
1222
        elif receiveCondition == 1:
1223
            order.status = OrderStatus.DOA_RECEIVED_DAMAGED
1224
            order.statusDescription = "DOA received damaged"
1225
        elif receiveCondition == 2:
1226
            order.status = OrderStatus.DOA_LOST_IN_TRANSIT
1227
            order.statusDescription = "DOA lost in transit"
2764 chandransh 1228
        order.received_return_timestamp = datetime.datetime.now()
2616 chandransh 1229
        session.commit()
4495 rajveer 1230
    elif order.status in [OrderStatus.RET_PICKUP_CONFIRMED, OrderStatus.RET_RETURN_IN_TRANSIT]:
1231
        if receiveCondition == 0:
1232
            order.status = OrderStatus.RET_RECEIVED_PRESTINE
1233
            order.statusDescription = "RETURN package received"
1234
        elif receiveCondition == 1:
1235
            order.status = OrderStatus.RET_RECEIVED_DAMAGED
1236
            order.statusDescription = "RETURN received damaged"
1237
        elif receiveCondition == 2:
1238
            order.status = OrderStatus.RET_LOST_IN_TRANSIT
1239
            order.statusDescription = "RETURN lost in transit"
1240
        order.received_return_timestamp = datetime.datetime.now()
1241
        session.commit()
4484 rajveer 1242
    elif order.status == OrderStatus.RTO_IN_TRANSIT :
4486 rajveer 1243
        if receiveCondition == 0:
1244
            order.status = OrderStatus.RTO_RECEIVED_PRESTINE
4515 mandeep.dh 1245
            order.statusDescription = "Returned to origin"
4486 rajveer 1246
        elif receiveCondition == 1:
1247
            order.status = OrderStatus.RTO_RECEIVED_DAMAGED
1248
            order.statusDescription = "RTO received damaged"
1249
        elif receiveCondition == 2:
1250
            order.status = OrderStatus.RTO_LOST_IN_TRANSIT
1251
            order.statusDescription = "RTO lost in transit"
2764 chandransh 1252
        order.received_return_timestamp = datetime.datetime.now()
2616 chandransh 1253
        session.commit()
1254
    else:
2591 chandransh 1255
        return False
5110 mandeep.dh 1256
 
1257
    # For OUR warehouses, we need to scan in items for every return
1258
    catalogClient = CatalogClient().get_client()
1259
    warehouse = catalogClient.getWarehouse(order.warehouse_id)
1260
    if warehouse.billingType == BillingType.OURS:
5361 mandeep.dh 1261
        scanMap = {
1262
            OrderStatus.RTO_RECEIVED_PRESTINE : ScanType.SALE_RET,
1263
            OrderStatus.RTO_RECEIVED_DAMAGED  : ScanType.SALE_RET_UNUSABLE,
1264
            OrderStatus.RTO_LOST_IN_TRANSIT   : ScanType.LOST_IN_TRANSIT,
1265
            OrderStatus.DOA_RECEIVED_PRESTINE : ScanType.DOA_IN,
1266
            OrderStatus.DOA_RECEIVED_DAMAGED  : ScanType.DOA_IN,
1267
            OrderStatus.DOA_LOST_IN_TRANSIT   : ScanType.LOST_IN_TRANSIT
1268
        }
5110 mandeep.dh 1269
 
5361 mandeep.dh 1270
        scanType = scanMap[order.status]
1271
        if scanType:
1272
            lineitem = order.lineitems[0]
1273
            item = catalogClient.getItem(lineitem.item_id)
1274
            warehouseClient = WarehouseClient().get_client()
1275
            if item.type == ItemType.SERIALIZED:
5110 mandeep.dh 1276
                warehouseClient.scanSerializedItemForOrder(lineitem.serial_number, scanType, order.id, order.fulfilmentWarehouseId, lineitem.quantity, order.warehouse_id)
5361 mandeep.dh 1277
            else:
1278
                warehouseClient.scanForOrder(None, scanType, lineitem.quantity, order.id, order.fulfilmentWarehouseId, order.warehouse_id)
5110 mandeep.dh 1279
 
2591 chandransh 1280
    return True
1281
 
1282
def validate_doa(order_id, is_valid):
1283
    order = get_order(order_id)
4452 rajveer 1284
    if order.status != OrderStatus.DOA_RECEIVED_PRESTINE:
2591 chandransh 1285
        return False
1286
    if is_valid:
2609 chandransh 1287
        order.status = OrderStatus.DOA_CERT_VALID
1288
        order.statusDescription = "DOA Certificate Valid"
2591 chandransh 1289
    else:
1290
        order.status = OrderStatus.DOA_CERT_INVALID
1291
        order.statusDescription = "DOA Certificate Invalid"
3578 mandeep.dh 1292
        update_trust_level(order)
2591 chandransh 1293
    session.commit()
1294
    return True
1295
 
4495 rajveer 1296
def validate_return_product(order_id, is_usable):
1297
    order = get_order(order_id)
1298
    if order.status != OrderStatus.RET_RECEIVED_PRESTINE:
1299
        return False
5110 mandeep.dh 1300
 
1301
    scanType = ScanType.SALE_RET_UNUSABLE
4495 rajveer 1302
    if is_usable:
1303
        order.status = OrderStatus.RET_PRODUCT_USABLE
1304
        order.statusDescription = "Return product usable"
5110 mandeep.dh 1305
        scanType = ScanType.SALE_RET
4495 rajveer 1306
    else:
1307
        order.status = OrderStatus.RET_PRODUCT_UNUSABLE
1308
        order.statusDescription = "Return product unusable"
1309
        update_trust_level(order)
1310
    session.commit()
5110 mandeep.dh 1311
 
1312
    # For OUR warehouses, we need to scan in items for every return
1313
    catalogClient = CatalogClient().get_client()
1314
    warehouse = catalogClient.getWarehouse(order.warehouse_id)
1315
    if warehouse.billingType == BillingType.OURS:
1316
        lineitem = order.lineitems[0]
5361 mandeep.dh 1317
        item = catalogClient.getItem(lineitem.item_id)
5110 mandeep.dh 1318
        warehouse_client = WarehouseClient().get_client()
5361 mandeep.dh 1319
        if item.type == ItemType.SERIALIZED:
1320
            warehouse_client.scanSerializedItemForOrder(lineitem.serial_number, scanType, order.id, order.fulfilmentWarehouseId, lineitem.quantity, order.warehouse_id)
1321
        else:
1322
            warehouse_client.scanForOrder(None, scanType, lineitem.quantity, order.id, order.fulfilmentWarehouseId, order.warehouse_id)
4495 rajveer 1323
    return True
1324
 
2628 chandransh 1325
def reship_order(order_id):
1326
    """
4484 rajveer 1327
    If the order is in RTO_RECEIVED_PRESTINE or DOA_CERT_INVALID state, it does the following:
2628 chandransh 1328
        1. Creates a new order for processing in the BILLED state. All billing information is saved.
4484 rajveer 1329
        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 1330
 
1331
    If the order is in DOA_CERT_VALID state, it does the following:
1332
        1. Creates a new order for processing in the SUBMITTED_FOR_PROCESSING state.
1333
        2. Creates a return order for the warehouse executive to return the DOA material.
4452 rajveer 1334
        3. Marks the current order as the final DOA_VALID_RESHIPPED state.
2628 chandransh 1335
 
1336
    Returns the id of the newly created order.
1337
 
1338
    Throws an exception if the order with the given id couldn't be found.
1339
 
1340
    Parameters:
1341
     - orderId
1342
    """
1343
    order = get_order(order_id)
4484 rajveer 1344
    if order.status == OrderStatus.RTO_RECEIVED_PRESTINE:
4220 rajveer 1345
        new_order = __clone_order(order, True, order.cod)
4484 rajveer 1346
        order.status = OrderStatus.RTO_RESHIPPED
2628 chandransh 1347
        order.statusDescription = "Order Reshipped"
1348
        session.commit()
3578 mandeep.dh 1349
        update_trust_level(order)
4486 rajveer 1350
    elif order.status == OrderStatus.RTO_RECEIVED_DAMAGED:
1351
        new_order = __clone_order(order, False, order.cod)
1352
        ret_order = __create_return_order(order)
1353
        order.status = OrderStatus.RTO_DAMAGED_RESHIPPED
1354
        order.statusDescription = "Order Reshipped Received Damaged"
1355
        session.commit()
1356
    elif order.status == OrderStatus.RTO_LOST_IN_TRANSIT:
1357
        new_order = __clone_order(order, False, order.cod)
1358
        order.status = OrderStatus.RTO_LOST_IN_TRANSIT_RESHIPPED
1359
        order.statusDescription = "Order Reshipped Lost In Transit"
1360
        session.commit()
4662 rajveer 1361
    elif order.status == OrderStatus.LOST_IN_TRANSIT:
1362
        new_order = __clone_order(order, False, order.cod)
1363
        order.status = OrderStatus.LOST_IN_TRANSIT_RESHIPPED
1364
        order.statusDescription = "Order Reshipped Lost In Transit"
1365
        session.commit()
2628 chandransh 1366
    elif order.status == OrderStatus.DOA_CERT_INVALID:
4220 rajveer 1367
        new_order = __clone_order(order, True, False)
2628 chandransh 1368
        order.status = OrderStatus.DOA_INVALID_RESHIPPED
1369
        order.statusDescription = "Order Reshipped"
1370
        session.commit()
1371
    elif order.status == OrderStatus.DOA_CERT_VALID:
4220 rajveer 1372
        new_order = __clone_order(order, False, False)
2628 chandransh 1373
        ret_order = __create_return_order(order)
4452 rajveer 1374
        order.status = OrderStatus.DOA_VALID_RESHIPPED
2628 chandransh 1375
        order.statusDescription = "Order Reshipped"
1376
        session.commit()
4479 rajveer 1377
    elif order.status == OrderStatus.DOA_RECEIVED_DAMAGED:
1378
        new_order = __clone_order(order, False, False)
1379
        ret_order = __create_return_order(order)
1380
        order.status = OrderStatus.DOA_RESHIPPED_RCVD_DAMAGED
1381
        order.statusDescription = "Order Reshipped Received Damaged"
1382
        session.commit()
1383
    elif order.status == OrderStatus.DOA_LOST_IN_TRANSIT:
1384
        new_order = __clone_order(order, False, False)
1385
        order.status = OrderStatus.DOA_RESHIPPED_LOST_IN_TRANSIT
1386
        order.statusDescription = "Order Reshipped Lost In Transit"
1387
        session.commit()
4614 rajveer 1388
    elif order.status == OrderStatus.RET_PRODUCT_USABLE:
4495 rajveer 1389
        new_order = __clone_order(order, True, False)
4614 rajveer 1390
        order.status = OrderStatus.RET_PRODUCT_USABLE_RESHIPPED
4495 rajveer 1391
        order.statusDescription = "Order Reshipped"
1392
        session.commit()
4614 rajveer 1393
    elif order.status == OrderStatus.RET_PRODUCT_UNUSABLE:
4495 rajveer 1394
        new_order = __clone_order(order, False, False)
1395
        ret_order = __create_return_order(order)
4614 rajveer 1396
        order.status = OrderStatus.RET_PRODUCT_UNUSABLE_RESHIPPED
4495 rajveer 1397
        order.statusDescription = "Order Reshipped"
1398
        session.commit()
1399
    elif order.status == OrderStatus.RET_RECEIVED_DAMAGED:
1400
        new_order = __clone_order(order, False, False)
1401
        ret_order = __create_return_order(order)
1402
        order.status = OrderStatus.RET_RESHIPPED_RCVD_DAMAGED
1403
        order.statusDescription = "Order Reshipped Received Damaged"
1404
        session.commit()
1405
    elif order.status == OrderStatus.RET_LOST_IN_TRANSIT:
1406
        new_order = __clone_order(order, False, False)
1407
        order.status = OrderStatus.RET_RESHIPPED_LOST_IN_TRANSIT
1408
        order.statusDescription = "Order Reshipped Lost In Transit"
1409
        session.commit()
2628 chandransh 1410
    else:
1411
        raise TransactionServiceException(112, "This order can't be reshipped")
1412
 
2764 chandransh 1413
    order.reship_timestamp = datetime.datetime.now()
2628 chandransh 1414
    order.new_order_id = new_order.id
1415
    session.commit()
1416
 
1417
    return new_order.id
1418
 
3226 chandransh 1419
def refund_order(order_id, refunded_by, reason):
2628 chandransh 1420
    """
4484 rajveer 1421
    If the order is in RTO_RECEIVED_PRESTINE, DOA_CERT_VALID or DOA_CERT_INVALID state, it does the following:
2628 chandransh 1422
        1. Creates a refund request for batch processing.
1423
        2. Creates a return order for the warehouse executive to return the shipped material.
4484 rajveer 1424
        3. Marks the current order as RTO_REFUNDED, DOA_VALID_REFUNDED or DOA_INVALID_REFUNDED final states.
2628 chandransh 1425
 
1426
    If the order is in SUBMITTED_FOR_PROCESSING or INVENTORY_LOW state, it does the following:
1427
        1. Creates a refund request for batch processing.
3226 chandransh 1428
        2. Cancels the reservation of the item in the warehouse.
1429
        3. Marks the current order as the REFUNDED final state.
2628 chandransh 1430
 
3226 chandransh 1431
    For all COD orders, if the order is in INIT, SUBMITTED_FOR_PROCESSING or INVENTORY_LOW state, it does the following:
1432
        1. Cancels the reservation of the item in the warehouse.
1433
        2. Marks the current order as CANCELED.
1434
 
1435
    In all cases, it updates the reason for cancellation or refund and the person who performed the action.
1436
 
1437
    Returns True if it is successful, False otherwise.
2628 chandransh 1438
 
1439
    Throws an exception if the order with the given id couldn't be found.
1440
 
1441
    Parameters:
3226 chandransh 1442
     - order_id
1443
     - refunded_by
1444
     - reason
2628 chandransh 1445
    """
3414 chandransh 1446
    logging.info("Refunding order id: " + str(order_id))
2628 chandransh 1447
    order = get_order(order_id)
3186 chandransh 1448
 
3226 chandransh 1449
    if order.cod:
3414 chandransh 1450
        logging.info("Refunding COD order with status " + str(order.status))
4662 rajveer 1451
        status_transition = { OrderStatus.LOST_IN_TRANSIT : OrderStatus.LOST_IN_TRANSIT_REFUNDED,
1452
                     OrderStatus.RTO_RECEIVED_PRESTINE : OrderStatus.RTO_REFUNDED,
4486 rajveer 1453
                     OrderStatus.RTO_RECEIVED_DAMAGED : OrderStatus.RTO_DAMAGED_REFUNDED,
1454
                     OrderStatus.RTO_LOST_IN_TRANSIT : OrderStatus.RTO_LOST_IN_TRANSIT_REFUNDED,
3366 chandransh 1455
                     OrderStatus.DOA_CERT_INVALID : OrderStatus.DOA_INVALID_REFUNDED,
1456
                     OrderStatus.DOA_CERT_VALID : OrderStatus.DOA_VALID_REFUNDED,
4479 rajveer 1457
                     OrderStatus.DOA_RECEIVED_DAMAGED : OrderStatus.DOA_REFUNDED_RCVD_DAMAGED,
1458
                     OrderStatus.DOA_LOST_IN_TRANSIT : OrderStatus.DOA_REFUNDED_LOST_IN_TRANSIT,
4495 rajveer 1459
                     OrderStatus.RET_PRODUCT_UNUSABLE : OrderStatus.RET_PRODUCT_UNUSABLE_REFUNDED,
1460
                     OrderStatus.RET_PRODUCT_USABLE : OrderStatus.RET_PRODUCT_USABLE_REFUNDED,
1461
                     OrderStatus.RET_RECEIVED_DAMAGED : OrderStatus.RET_REFUNDED_RCVD_DAMAGED,
1462
                     OrderStatus.RET_LOST_IN_TRANSIT : OrderStatus.RET_REFUNDED_LOST_IN_TRANSIT,
4682 rajveer 1463
                     OrderStatus.COD_VERIFICATION_PENDING : OrderStatus.COD_VERIFICATION_FAILED,
1464
                     OrderStatus.SUBMITTED_FOR_PROCESSING : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1465
                     OrderStatus.INVENTORY_LOW : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1466
                     OrderStatus.LOW_INV_PO_RAISED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1467
                     OrderStatus.LOW_INV_REVERSAL_IN_PROCESS : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1468
                     OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1469
                     OrderStatus.ACCEPTED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1470
                     OrderStatus.BILLED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
4247 rajveer 1471
                     OrderStatus.CANCEL_REQUEST_CONFIRMED : OrderStatus.CANCELLED_ON_CUSTOMER_REQUEST
3366 chandransh 1472
                     }
1473
        if order.status not in status_transition.keys():
1474
            raise TransactionServiceException(114, "This order can't be refunded")
1475
 
5199 mandeep.dh 1476
        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 1477
            __update_inventory_reservation(order)
1478
            order.statusDescription = "Order Cancelled"
3415 chandransh 1479
        elif order.status == OrderStatus.BILLED:
3413 chandransh 1480
            __create_return_order(order)
1481
            order.statusDescription = "Order Cancelled"
4486 rajveer 1482
        elif order.status in [OrderStatus.RTO_RECEIVED_PRESTINE, OrderStatus.RTO_RECEIVED_DAMAGED, OrderStatus.RTO_LOST_IN_TRANSIT]:
3226 chandransh 1483
            __create_return_order(order)
4486 rajveer 1484
            order.statusDescription = "RTO Refunded"
4662 rajveer 1485
        elif order.status in [OrderStatus.LOST_IN_TRANSIT]:
1486
            __create_return_order(order)
1487
            order.statusDescription = "Lost in Transit Refunded"
4479 rajveer 1488
        elif order.status in [OrderStatus.DOA_CERT_INVALID, OrderStatus.DOA_CERT_VALID, OrderStatus.DOA_RECEIVED_DAMAGED, OrderStatus.DOA_LOST_IN_TRANSIT] :
4078 chandransh 1489
            __create_return_order(order)
3226 chandransh 1490
            __create_refund(order)
4495 rajveer 1491
            order.statusDescription = "DOA Refunded"
1492
        elif order.status in [OrderStatus.RET_PRODUCT_UNUSABLE, OrderStatus.RET_PRODUCT_USABLE, OrderStatus.RET_RECEIVED_DAMAGED, OrderStatus.RET_LOST_IN_TRANSIT] :
1493
            __create_return_order(order)
1494
            __create_refund(order)
1495
            order.statusDescription = "Return Refunded"
4247 rajveer 1496
        elif order.status == OrderStatus.CANCEL_REQUEST_CONFIRMED:
5199 mandeep.dh 1497
            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 1498
                __update_inventory_reservation(order)
1499
                order.statusDescription = "Order Cancelled on customer request"
1500
            elif order.previousStatus == OrderStatus.BILLED:
1501
                __create_return_order(order)
1502
                order.statusDescription = "Order Cancelled on customer request"
3226 chandransh 1503
    else:
4662 rajveer 1504
        status_transition = {OrderStatus.LOST_IN_TRANSIT : OrderStatus.LOST_IN_TRANSIT_REFUNDED,
1505
                     OrderStatus.RTO_RECEIVED_PRESTINE : OrderStatus.RTO_REFUNDED,
4486 rajveer 1506
                     OrderStatus.RTO_RECEIVED_DAMAGED : OrderStatus.RTO_DAMAGED_REFUNDED,
1507
                     OrderStatus.RTO_LOST_IN_TRANSIT : OrderStatus.RTO_LOST_IN_TRANSIT_REFUNDED,
3366 chandransh 1508
                     OrderStatus.DOA_CERT_INVALID : OrderStatus.DOA_INVALID_REFUNDED,
1509
                     OrderStatus.DOA_CERT_VALID : OrderStatus.DOA_VALID_REFUNDED,
4479 rajveer 1510
                     OrderStatus.DOA_RECEIVED_DAMAGED : OrderStatus.DOA_REFUNDED_RCVD_DAMAGED,
1511
                     OrderStatus.DOA_LOST_IN_TRANSIT : OrderStatus.DOA_REFUNDED_LOST_IN_TRANSIT,
4495 rajveer 1512
                     OrderStatus.RET_PRODUCT_UNUSABLE : OrderStatus.RET_PRODUCT_UNUSABLE_REFUNDED,
1513
                     OrderStatus.RET_PRODUCT_USABLE : OrderStatus.RET_PRODUCT_USABLE_REFUNDED,
1514
                     OrderStatus.RET_RECEIVED_DAMAGED : OrderStatus.RET_REFUNDED_RCVD_DAMAGED,
1515
                     OrderStatus.RET_LOST_IN_TRANSIT : OrderStatus.RET_REFUNDED_LOST_IN_TRANSIT,
4682 rajveer 1516
                     OrderStatus.SUBMITTED_FOR_PROCESSING : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1517
                     OrderStatus.INVENTORY_LOW : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1518
                     OrderStatus.LOW_INV_PO_RAISED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1519
                     OrderStatus.LOW_INV_REVERSAL_IN_PROCESS : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1520
                     OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1521
                     OrderStatus.ACCEPTED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1522
                     OrderStatus.BILLED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
4247 rajveer 1523
                     OrderStatus.CANCEL_REQUEST_CONFIRMED : OrderStatus.CANCELLED_ON_CUSTOMER_REQUEST,
1524
                     OrderStatus.PAYMENT_FLAGGED : OrderStatus.PAYMENT_FLAGGED_DENIED
3366 chandransh 1525
                     }
1526
        if order.status not in status_transition.keys():
1527
            raise TransactionServiceException(114, "This order can't be refunded")
1528
 
4495 rajveer 1529
        if order.status in [OrderStatus.RTO_RECEIVED_PRESTINE, OrderStatus.RTO_RECEIVED_DAMAGED, OrderStatus.RTO_LOST_IN_TRANSIT] :
3226 chandransh 1530
            __create_return_order(order)
1531
            __create_refund(order)
4495 rajveer 1532
            order.statusDescription = "RTO Refunded"
4662 rajveer 1533
        elif order.status in [OrderStatus.LOST_IN_TRANSIT]:
1534
            __create_return_order(order)
1535
            __create_refund(order)
1536
            order.statusDescription = "Lost in Transit Refunded"
4495 rajveer 1537
        elif order.status in [OrderStatus.DOA_CERT_INVALID, OrderStatus.DOA_CERT_VALID, OrderStatus.DOA_RECEIVED_DAMAGED, OrderStatus.DOA_LOST_IN_TRANSIT] :
1538
            __create_return_order(order)
1539
            __create_refund(order)
1540
            order.statusDescription = "DOA Refunded"
1541
        elif order.status in [OrderStatus.RET_PRODUCT_UNUSABLE, OrderStatus.RET_PRODUCT_USABLE, OrderStatus.RET_RECEIVED_DAMAGED, OrderStatus.RET_LOST_IN_TRANSIT] :
1542
            __create_return_order(order)
1543
            __create_refund(order)
1544
            order.statusDescription = "Return Refunded"
5199 mandeep.dh 1545
        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 1546
            __update_inventory_reservation(order)
1547
            order.statusDescription = "Order Refunded"
4247 rajveer 1548
        elif order.status == OrderStatus.CANCEL_REQUEST_CONFIRMED:
5272 mandeep.dh 1549
            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 1550
                if order.previousStatus == OrderStatus.ACCEPTED:
1551
                    __create_refund(order)
4247 rajveer 1552
                __update_inventory_reservation(order)
1553
                order.statusDescription = "Order Cancelled on customer request"
1554
            elif order.previousStatus == OrderStatus.BILLED:
1555
                __create_return_order(order)
1556
                __create_refund(order)
1557
                order.statusDescription = "Order Cancelled on customer request"
1558
        elif order.status == OrderStatus.PAYMENT_FLAGGED:
1559
            __update_inventory_reservation(order)
1560
            order.statusDescription = "Order Cancelled due to payment flagged"
3195 chandransh 1561
 
4873 mandeep.dh 1562
    # For orders that are cancelled after being billed, we need to scan in the scanned out
1563
    # inventory item and change availability accordingly
5110 mandeep.dh 1564
    catalogClient = CatalogClient().get_client()
1565
    warehouse = catalogClient.getWarehouse(order.warehouse_id)
1566
    if warehouse.billingType == BillingType.OURS:
4873 mandeep.dh 1567
        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]):
1568
            lineitem = order.lineitems[0]
5177 mandeep.dh 1569
            item = catalogClient.getItem(lineitem.item_id)
5361 mandeep.dh 1570
            warehouseClient = WarehouseClient().get_client()
5177 mandeep.dh 1571
            if ItemType.SERIALIZED == item.type:
1572
                warehouseClient.scanSerializedItemForOrder(lineitem.serial_number, ScanType.SALE_RET, order.id, order.fulfilmentWarehouseId, lineitem.quantity, order.warehouse_id)
5361 mandeep.dh 1573
            else:
1574
                warehouseClient.scanForOrder(None, ScanType.SALE_RET, lineitem.quantity, order.id, order.fulfilmentWarehouseId, order.warehouse_id)
4873 mandeep.dh 1575
 
3195 chandransh 1576
    order.status = status_transition[order.status]
1577
    order.refund_timestamp = datetime.datetime.now()
3226 chandransh 1578
    order.refunded_by = refunded_by
1579
    order.refund_reason = reason
4873 mandeep.dh 1580
 
2628 chandransh 1581
    session.commit()
1582
    return True
1583
 
3186 chandransh 1584
def __update_inventory_reservation(order):
3191 chandransh 1585
    '''
1586
    Reduce the reservation count for all line items of the given order.
1587
    '''
3186 chandransh 1588
    try:
1589
        catalog_client = CatalogClient().get_client()
1590
        for lineitem in order.lineitems:
5110 mandeep.dh 1591
            catalog_client.reduceReservationCount(lineitem.item_id, order.fulfilmentWarehouseId, lineitem.quantity);
3186 chandransh 1592
    except:
1593
        print "Unable to reduce reservation count"
1594
 
4220 rajveer 1595
def __clone_order(order, should_copy_billing_info, is_cod):
2628 chandransh 1596
    current_time = datetime.datetime.now()
1597
    new_order = Order()
1598
    new_order.customer_id = order.customer_id
1599
    new_order.customer_name = order.customer_name
1600
    new_order.customer_city = order.customer_city
1601
    new_order.customer_state = order.customer_state
1602
    new_order.customer_mobilenumber = order.customer_mobilenumber
1603
    new_order.customer_pincode = order.customer_pincode
1604
    new_order.customer_address1 = order.customer_address1
1605
    new_order.customer_address2 = order.customer_address2
1606
    new_order.customer_email = order.customer_email
1607
    new_order.total_amount = order.total_amount
1608
    new_order.total_weight = order.total_weight
1609
    new_order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
1610
    new_order.statusDescription = 'Submitted for Processing'
1611
    new_order.created_timestamp = current_time
5062 varun.gupt 1612
    new_order.originalOrderId = order.originalOrderId if order.originalOrderId is not None else order.id 
2628 chandransh 1613
 
1614
    new_order.transaction = order.transaction
4220 rajveer 1615
    new_order.cod = is_cod
2628 chandransh 1616
 
1617
    for line_item in order.lineitems:
1618
        litem = LineItem()
1619
        litem.item_id = line_item.item_id
1620
        litem.productGroup = line_item.productGroup
1621
        litem.brand = line_item.brand
1622
        if line_item.model_number:
1623
            litem.model_number = line_item.model_number
1624
        if line_item.model_name:    
1625
            litem.model_name = line_item.model_name
1626
        if line_item.color:
1627
            litem.color = line_item.color
1628
        if line_item.extra_info:
1629
            litem.extra_info = line_item.extra_info
1630
        litem.quantity = line_item.quantity
1631
        litem.unit_price = line_item.unit_price
1632
        litem.unit_weight = line_item.unit_weight
1633
        litem.total_price = line_item.total_price
1634
        litem.total_weight = line_item.total_weight
1635
        litem.transfer_price = line_item.transfer_price
4840 mandeep.dh 1636
        litem.dealText = line_item.dealText
2628 chandransh 1637
        litem.order = new_order
1638
 
1639
    logistics_client = LogisticsClient().get_client()
1640
    item_id = new_order.lineitems[0].item_id
4479 rajveer 1641
    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 1642
    logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
1643
    new_order.warehouse_id = logistics_info.warehouseId
5110 mandeep.dh 1644
    new_order.fulfilmentWarehouseId = logistics_info.fulfilmentWarehouseId
2628 chandransh 1645
    new_order.logistics_provider_id = logistics_info.providerId
1646
    new_order.airwaybill_no = logistics_info.airway_billno
1647
    new_order.tracking_id = new_order.airwaybill_no
1648
    new_order.expected_delivery_time = current_time + datetime.timedelta(days=logistics_info.deliveryTime)
3986 chandransh 1649
    new_order.promised_delivery_time = new_order.expected_delivery_time
4299 rajveer 1650
 
2628 chandransh 1651
    if should_copy_billing_info:
1652
        new_order.invoice_number = order.invoice_number
1653
        new_order.billed_by = order.billed_by
1654
        new_order.warehouse_id = order.warehouse_id
5110 mandeep.dh 1655
        new_order.fulfilmentWarehouseId = order.fulfilmentWarehouseId
2628 chandransh 1656
        new_order.accepted_timestamp = current_time
1657
        new_order.billing_timestamp = current_time    
1658
        new_order.status = OrderStatus.BILLED
1659
        new_order.statusDescription = 'Order Billed'
1660
    else:       
3133 rajveer 1661
        catalog_client = CatalogClient().get_client()
5110 mandeep.dh 1662
        catalog_client.reserveItemInWarehouse(item_id, logistics_info.fulfilmentWarehouseId, new_order.lineitems[0].quantity)
2628 chandransh 1663
 
1664
    return new_order
1665
 
1666
def __create_return_order(order):
2687 chandransh 1667
    ret_order = ReturnOrder(order)
2628 chandransh 1668
    return ret_order
1669
 
1670
def __create_refund(order):
4078 chandransh 1671
    payment_client = PaymentClient().get_client()
1672
    payment_client.createRefund(order.id, order.transaction.id, order.total_amount)
2747 chandransh 1673
    return
2628 chandransh 1674
 
2536 chandransh 1675
def __get_order_address(order):
1676
    address = order.customer_name + "\n" + order.customer_address1 + "\n"
1677
    if order.customer_address2:
1678
        address = address + order.customer_address2 + "\n"
1679
    address = address + order.customer_city + "\n"
1680
    address = address + order.customer_state + "\n"
1681
    address = address + "PIN " + order.customer_pincode + "\n"
1682
    address = address + "Phone: " + order.customer_mobilenumber
1683
    return address
1684
 
4815 phani.kuma 1685
def __generate_return_advice(order, warehouse, provider, filename):
1686
    if warehouse.id == 7:
1687
        executive = 'Amit Kumar'
1688
    else:
4966 phani.kuma 1689
        executive = 'Dinesh Kumar'
2536 chandransh 1690
    pdf = Canvas(filename)
1691
    pdf.setFont('Times-Bold',16)
1692
    address_text = pdf.beginText(inch, PAGE_HEIGHT - inch)
1693
    address_text.textLine("To")
4815 phani.kuma 1694
    address_text.textLine(executive)
2536 chandransh 1695
    for line in warehouse.location.split("\n"):
1696
        address_text.textLine(line)
1697
    address_text.textLine("PIN " + warehouse.pincode)
1698
    pdf.drawText(address_text)
1699
 
1700
    pdf.setFont('Times-Roman',12)
1701
    order_text = pdf.beginText(inch, PAGE_HEIGHT - 4 * inch)
3051 chandransh 1702
    order_text.textLine("Pickup CODE: " + provider.details[DeliveryType.PREPAID].accountNo)
2536 chandransh 1703
    lineitem = order.lineitems[0] 
4234 rajveer 1704
    order_text.textLine("Content : " + lineitem.brand + " " + str(lineitem.model_number) + " " + str(lineitem.color))
2536 chandransh 1705
    order_text.textLine("Declared Value: Rs. " + str(order.total_amount))
1706
    order_text.textLine("Order ID : " + str(order.id))
1707
    pdf.drawText(order_text)
1708
    pdf.showPage()
1709
    pdf.save()
1710
    return filename
1711
 
2697 chandransh 1712
def get_return_orders(warehouse_id, from_date, to_date):
1713
    query = ReturnOrder.query.filter_by(processedStatus = False)
1714
    if warehouse_id != -1:
1715
        query = query.filter_by(warehouseId = warehouse_id)
1716
    if from_date:
4118 chandransh 1717
        query = query.filter(ReturnOrder.createdAt >from_date)
2697 chandransh 1718
    if to_date:
4118 chandransh 1719
        query = query.filter(ReturnOrder.createdAt < to_date)
2697 chandransh 1720
    return [return_order.to_thrift_object() for return_order in query.all()]
1721
 
2700 chandransh 1722
def get_return_order(id):
1723
    ret_order = ReturnOrder.get_by(orderId = id)
1724
    if ret_order is None:
1725
        raise TransactionServiceException(116, "No return order found for the given order id")
1726
    return ret_order.to_thrift_object()
1727
 
2697 chandransh 1728
def process_return(ret_order_id):
1729
    ret_order = ReturnOrder.get_by(orderId = ret_order_id)
1730
    if ret_order is None:
1731
        raise TransactionServiceException(116, "No return order found for the given order id")
1732
    ret_order.processedStatus = True
2701 chandransh 1733
    ret_order.processedAt = datetime.datetime.now()
2697 chandransh 1734
    session.commit()
1735
 
4757 mandeep.dh 1736
def update_orders_as_PORaised(itemIdQuantityMap, purchaseOrderId, warehouseId):
1737
    """
1738
    Updates orders as PO raised. Also updates purchase order id in orders. Pass a map of items mapped to
1739
    the quantities for which the PO is raised.
1740
 
1741
    Parameters:
1742
     - itemIdQuantityMap
1743
     - purchaseOrderId
1744
     - warehouseId
1745
    """
3451 chandransh 1746
    query = Order.query.with_lockmode("update").filter_by(warehouse_id=warehouseId)
4757 mandeep.dh 1747
    query = query.filter(or_(Order.status == OrderStatus.SUBMITTED_FOR_PROCESSING, Order.status == OrderStatus.INVENTORY_LOW))
2819 chandransh 1748
    query = query.filter_by(purchase_order_id=None)
1749
    query = query.order_by(Order.created_timestamp)
1750
    pending_orders = query.all()
4586 mandeep.dh 1751
 
1752
    for order in pending_orders:
4757 mandeep.dh 1753
        lineitem = order.lineitems[0]
1754
        if itemIdQuantityMap.has_key(lineitem.item_id):
1755
            if itemIdQuantityMap[lineitem.item_id] >= lineitem.quantity:
1756
                order.status = OrderStatus.LOW_INV_PO_RAISED
1757
                order.statusDescription = 'In Process'
1758
                order.purchase_order_id = purchaseOrderId
1759
                itemIdQuantityMap[lineitem.item_id] -= lineitem.quantity
4434 mandeep.dh 1760
 
2819 chandransh 1761
    session.commit()
1762
 
3451 chandransh 1763
def update_weight(order_id, weight):
3469 chandransh 1764
    '''
1765
    Update the weight of order
1766
    '''
3451 chandransh 1767
    order = get_order(order_id)
1768
    order.total_weight = weight
3469 chandransh 1769
    lineitem = order.lineitems[0]
1770
    lineitem.total_weight = weight
1771
    lineitem.unit_weight = weight
3451 chandransh 1772
 
3469 chandransh 1773
    session.commit()
1774
    return order
1775
 
1776
def change_product(order_id, item_id):
1777
    '''
1778
    Ship a product of a different color to the customer.
1779
    '''
1780
    order = get_order(order_id)
4662 rajveer 1781
    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 1782
        raise TransactionServiceException(120, "This order has already been processed. Please seek help from engineering.")
1783
 
1784
    lineitem = order.lineitems[0]
3451 chandransh 1785
 
3469 chandransh 1786
    catalog_client = CatalogClient().get_client()
1787
 
1788
    old_item = catalog_client.getItem(lineitem.item_id)
1789
    item = catalog_client.getItem(item_id)
1790
    if old_item.catalogItemId != item.catalogItemId:
1791
        raise TransactionServiceException(121, "You can't ship a different item. You can only ship the same item in a different color.")
1792
 
5110 mandeep.dh 1793
    catalog_client.reserveItemInWarehouse(item_id, order.fulfilmentWarehouseId, lineitem.quantity)
1794
    __update_inventory_reservation(order)
3469 chandransh 1795
    #TODO: Check that this new item has the same price
1796
 
1797
    lineitem.item_id = item_id
1798
    lineitem.color = item.color
1799
 
3451 chandransh 1800
    session.commit()
3469 chandransh 1801
 
1802
    order = get_order(order_id)
3451 chandransh 1803
    return order
3469 chandransh 1804
 
1805
def change_warehouse(order_id, warehouse_id):
1806
    '''
1807
    Update the warehouse which will be used to fulfil this order.
1808
    '''
1809
    order = get_order(order_id)
4662 rajveer 1810
    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 1811
        raise TransactionServiceException(117, "This order has already been processed. Please seek help from engineering.")
1812
 
1813
    if warehouse_id == order.warehouse_id:
1814
        raise TransactionServiceException(118, "You have selected the current warehouse again. Nothing to do")
1815
 
1816
    lineitem = order.lineitems[0]
1817
    catalog_client = CatalogClient().get_client()
1818
    try:
1819
        warehouse = catalog_client.getWarehouse(warehouse_id)
1820
    except:
1821
        raise TransactionServiceException(119, "No warehouse with id" + str(warehouse_id))
5110 mandeep.dh 1822
 
5147 mandeep.dh 1823
    if warehouse.billingWarehouseId is None:
1824
        raise TransactionServiceException(119, "Shifting of warehouse allowed to warehouse with billing support only")
5110 mandeep.dh 1825
 
5147 mandeep.dh 1826
    # If One gives a shipping location for warehouse shift, we should assign order to the GOOD warehouse
1827
    # present with this shipping location with maximum availability
1828
    if warehouse.inventoryType != InventoryType.GOOD:
1829
        warehouses = catalog_client.getWarehouses(None, InventoryType.GOOD, 0, 0, warehouse.id)
1830
        if warehouses:
1831
            itemInventory = catalog_client.getItemInventoryByItemId(lineitem.item_id)
1832
            warehouse = warehouses[0]
1833
            maxAvailability = 0
1834
            for goodWarehouse in warehouses:
1835
                if itemInventory.availability.has_key(goodWarehouse.id) and maxAvailability < itemInventory.availability[goodWarehouse.id]:
1836
                    warehouse = goodWarehouse
1837
                    maxAvailability = itemInventory.availability[goodWarehouse.id]
1838
 
1839
            # Use preferred vendor's warehouse if not available anywhere
1840
            if not maxAvailability:
1841
                item = catalog_client.getItem(lineitem.item_id)
1842
                if item.preferredVendor:
1843
                    for goodWarehouse in warehouses:
1844
                        if goodWarehouse.vendor.id == item.preferredVendor:
1845
                            warehouse = goodWarehouse
1846
        else:
1847
            raise TransactionServiceException(119, "Shifting of warehouse allowed to GOOD inventory type warehouse with billing support")
1848
 
5199 mandeep.dh 1849
    catalog_client.reserveItemInWarehouse(lineitem.item_id, warehouse.id, lineitem.quantity)
5110 mandeep.dh 1850
    __update_inventory_reservation(order)
1851
 
1852
    order.warehouse_id = warehouse.billingWarehouseId
5147 mandeep.dh 1853
    order.fulfilmentWarehouseId = warehouse.id
3469 chandransh 1854
    session.commit()
1855
    return order
3553 chandransh 1856
 
4647 rajveer 1857
def add_delay_reason(order_id, reason, further_delay, delayReasonText):
3553 chandransh 1858
    '''
3994 chandransh 1859
    Adds a delay reason to the order and updates the expected delivery time.
3553 chandransh 1860
    '''
1861
    order = get_order(order_id)
1862
    try:
3581 chandransh 1863
        order.delay_reason = DelayReason._VALUES_TO_NAMES[reason]
4647 rajveer 1864
        order.delayReasonText = delayReasonText
4009 chandransh 1865
        actual_delivery_delay = adjust_delivery_time(order.expected_delivery_time, further_delay)
1866
        order.expected_delivery_time = order.expected_delivery_time + datetime.timedelta(days=actual_delivery_delay)
4102 chandransh 1867
 
4842 rajveer 1868
        actual_shipping_delay = adjust_delivery_time(order.expected_shipping_time, further_delay)
1869
        order.expected_shipping_time = order.expected_shipping_time + datetime.timedelta(days=actual_shipping_delay)
4102 chandransh 1870
 
3553 chandransh 1871
        session.commit()
4008 mandeep.dh 1872
 
1873
        try:
1874
            transaction_requiring_extra_processing = TransactionRequiringExtraProcessing()
1875
            transaction_requiring_extra_processing.category = 'DELAYED_DELIVERY'
1876
            transaction_requiring_extra_processing.transaction_id = order.transaction_id
1877
            session.commit()
1878
        except Exception as e:
4065 mandeep.dh 1879
            print 'Could not persist transaction id: ' + str(order.transaction_id) + ' for further processing due to: ' + str(e)
4008 mandeep.dh 1880
 
3553 chandransh 1881
        return True
1882
    except:
3994 chandransh 1883
        print sys.exc_info()[0]
3553 chandransh 1884
        return False
3956 chandransh 1885
 
1886
def reconcile_cod_collection(collected_amount_map, xferBy, xferTxnId, xferDate):
1887
    unprocessed_awbs = {}
1888
    for awb, amount in collected_amount_map.iteritems():
1889
        try:
1890
            order = Order.query.filter_by(airwaybill_no=awb).one()
1891
        except NoResultFound:
1892
            unprocessed_awbs[awb] = "No order was found for the given AWB: " + awb
1893
            continue
1894
        except MultipleResultsFound:
1895
            unprocessed_awbs[awb] = "Multiple orders were found for the given AWB:" + awb
1896
            continue
1897
 
1898
        if order.cod_reconciliation_timestamp:
1899
            #This order has been processed already! This may be a re-run. Let's allow other orders to be processed.
1900
            continue
1901
 
1902
        if order.status < OrderStatus.DELIVERY_SUCCESS:
1903
            #Order has not been delivered yet. No way we can receive the payment.
1904
            unprocessed_awbs[awb] = "Payment has been received for order: " + str(order.id) + " before delivery reconciliation"
1905
            continue
1906
 
4252 rajveer 1907
        ##As per ticket #743 if amount difference less than 0.5 we should reconcile
1908
        if abs(amount - order.total_amount) > 0.5:
3956 chandransh 1909
            #Received amount is less than or more than the order amount. Mustn't let the user proceed.
1910
            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)
1911
            continue
1912
 
1913
        try:
1914
            payment_client = PaymentClient().get_client()
1915
            payment_client.partiallyCapturePayment(order.transaction.id, amount, xferBy, xferTxnId, xferDate)
1916
        except Exception:
1917
            unprocessed_awbs[awb] = "We were unable to partially capture payment for order id " + str(order.id) + ", AWB: " + awb
1918
            continue
1919
 
1920
        #Payment has been recorded now. We can update the order peacefully.
1921
        order.cod_reconciliation_timestamp = datetime.datetime.now()
1922
        session.commit()
3469 chandransh 1923
 
3956 chandransh 1924
    return unprocessed_awbs
4008 mandeep.dh 1925
 
1926
def get_transactions_requiring_extra_processing(category):
4065 mandeep.dh 1927
    """
1928
    Returns the list of transaction ids that require some extra processing and
1929
    which belong to a particular category. This is currently used by CRM
1930
    application. If no such transaction ids are present, it returns an empty list.
1931
    """
1932
    query = TransactionRequiringExtraProcessing.query
4008 mandeep.dh 1933
 
4065 mandeep.dh 1934
    if category is not None:
1935
        query = query.filter_by(category = ExtraTransactionProcessingType._VALUES_TO_NAMES.get(category))
4008 mandeep.dh 1936
 
4065 mandeep.dh 1937
    return [a.transaction_id for a in query.all()]
4008 mandeep.dh 1938
 
1939
def mark_transaction_as_processed(transactionId, category):
4065 mandeep.dh 1940
    """
1941
    Marks a particular transaction as processed for a particular cateogory.
1942
    It essentially deletes the transaction id record for a particular
1943
    processing type category (if present) from DB.
1944
    This is currently used by CRM application.
1945
    """
4008 mandeep.dh 1946
    TransactionRequiringExtraProcessing.query.filter_by(transaction_id = transactionId).filter_by(category = ExtraTransactionProcessingType._VALUES_TO_NAMES.get(category)).delete()
1947
    session.commit()
1948
 
4018 chandransh 1949
def get_item_wise_risky_orders_count():
1950
    """
1951
    Returns a map containing the number of risky orders keyed by item id. A risky order
1952
    is defined as one whose shipping date is about to expire.
1953
    """
1954
    item_wise_risky_orders_count = {}
4019 chandransh 1955
    shipping_cutoff_time = (datetime.datetime.now() + datetime.timedelta(days = 1)).replace(hour=PREPAID_SHIPPING_CUTOFF_TIME, minute=0, second=0)
4018 chandransh 1956
    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()
1957
    for order in orders:
1958
        for lineitem in order.lineitems:
1959
            quantity = lineitem.quantity
1960
            if item_wise_risky_orders_count.has_key(lineitem.item_id):
1961
                quantity = quantity + item_wise_risky_orders_count[lineitem.item_id]
1962
 
1963
            item_wise_risky_orders_count[lineitem.item_id] = quantity
1964
    return item_wise_risky_orders_count
1965
 
4324 mandeep.dh 1966
def update_shipment_address(order_id, address_id):
1967
    """
1968
    Updates shipment address of an order. Delivery and shipping date estimates
1969
    etc. are also updated here.
1970
 
1971
    Throws TransactionServiceException in case address change is not
1972
    possible due to certain reasons such as new pincode in address is
1973
    not serviceable etc.
1974
 
1975
    Parameters:
1976
     - orderId
1977
     - addressId
1978
    """
1979
    user_client = UserClient().get_client()
1980
    address     = user_client.getAddressById(address_id)
1981
    order       = get_order(order_id)
1982
 
4630 mandeep.dh 1983
    type = DeliveryType.PREPAID
1984
    if order.cod:
1985
        type = DeliveryType.COD
1986
 
4324 mandeep.dh 1987
    logistics_client = LogisticsClient().get_client()
4630 mandeep.dh 1988
    logistics_info = logistics_client.getLogisticsEstimation(order.lineitems[0].item_id, address.pin, type)
4324 mandeep.dh 1989
 
1990
    # Check for new estimate. Raise exception if new address is not serviceable
1991
    if logistics_info.deliveryTime == -1:
1992
        raise TransactionServiceException(1, 'Location not serviceable')
1993
 
1994
    # COD services are not available everywhere
1995
    if order.cod:
4868 rajveer 1996
        if not logistics_info.codAllowed:
4324 mandeep.dh 1997
            raise TransactionServiceException(2, 'COD service not available')
1998
 
1999
    current_time = datetime.datetime.now()
2000
    logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
2001
    logistics_info.shippingTime = adjust_delivery_time(current_time, logistics_info.shippingTime)
2002
 
2003
    order.customer_name         = address.name
2004
    order.customer_pincode      = address.pin
2005
    order.customer_address1     = address.line1
2006
    order.customer_address2     = address.line2
2007
    order.customer_city         = address.city
2008
    order.customer_state        = address.state
2009
    order.customer_mobilenumber = address.phone
2010
 
2011
    if order.cod:
2012
        order.expected_shipping_time = (current_time + datetime.timedelta(days=logistics_info.shippingTime)).replace(hour=COD_SHIPPING_CUTOFF_TIME, minute=0, second=0)
2013
    else:
2014
        order.expected_shipping_time = (current_time + datetime.timedelta(days=logistics_info.shippingTime)).replace(hour=PREPAID_SHIPPING_CUTOFF_TIME, minute=0, second=0)
2015
 
2016
    order.expected_delivery_time = current_time + datetime.timedelta(days=logistics_info.deliveryTime)
2017
    order.promised_shipping_time = order.expected_shipping_time
2018
    order.promised_delivery_time = order.expected_delivery_time 
2019
 
2020
    session.commit()
2021
 
4247 rajveer 2022
def mark_order_cancellation_request_received(orderId):
2023
    """
2024
    Mark order as cancellation request received. If customer sends request of cancellation of
2025
    a particular order, this method will be called. It will just change status of the order
2026
    depending on its current status. It also records the previous status, so that we can move
2027
    back to that status if cancellation request is denied.
2028
 
2029
    Parameters:
2030
     - orderId
2031
    """
4662 rajveer 2032
    status_transition = {OrderStatus.COD_VERIFICATION_PENDING : OrderStatus.CANCEL_REQUEST_RECEIVED,
4247 rajveer 2033
             OrderStatus.SUBMITTED_FOR_PROCESSING : OrderStatus.CANCEL_REQUEST_RECEIVED,
2034
             OrderStatus.INVENTORY_LOW : OrderStatus.CANCEL_REQUEST_RECEIVED,
4306 rajveer 2035
             OrderStatus.LOW_INV_PO_RAISED : OrderStatus.CANCEL_REQUEST_RECEIVED,
2036
             OrderStatus.LOW_INV_REVERSAL_IN_PROCESS : OrderStatus.CANCEL_REQUEST_RECEIVED,
2037
             OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT : OrderStatus.CANCEL_REQUEST_RECEIVED,
4247 rajveer 2038
             OrderStatus.ACCEPTED : OrderStatus.CANCEL_REQUEST_RECEIVED,
2039
             OrderStatus.BILLED : OrderStatus.CANCEL_REQUEST_RECEIVED,
2040
             OrderStatus.PAYMENT_FLAGGED : OrderStatus.CANCEL_REQUEST_RECEIVED
2041
             }
4662 rajveer 2042
 
2043
    order = get_order(orderId)
4247 rajveer 2044
    if order.status not in status_transition.keys():
2045
        raise TransactionServiceException(114, "This order can't be considered for cancellation")
2046
 
4662 rajveer 2047
 
4247 rajveer 2048
    order.previousStatus = order.status
2049
    order.status = OrderStatus.CANCEL_REQUEST_RECEIVED
2050
    order.statusDescription = "Cancellation request received from user"
2051
    session.commit()
2052
 
4662 rajveer 2053
def mark_order_as_lost_in_transit(orderId):
2054
    """
2055
    Parameters:
2056
     - orderId
2057
    """
2058
    order = get_order(orderId)
4910 phani.kuma 2059
    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 2060
        raise TransactionServiceException(115, "This order can't be marked as lost in transit")
2061
    order.status = OrderStatus.LOST_IN_TRANSIT
2062
    order.statusDescription = "Lost in Transit"
2063
    session.commit()
2064
 
4258 rajveer 2065
def mark_transaction_as_payment_flag_removed(transactionId):
4247 rajveer 2066
    """
4258 rajveer 2067
    If we and/or payment gateway has decided to accept the payment, this method needs to be called.
2068
    Changed transaction and all orders status to payment accepted.
4247 rajveer 2069
 
2070
    Parameters:
4258 rajveer 2071
     - transactionId
4247 rajveer 2072
    """
4258 rajveer 2073
    transaction = get_transaction(transactionId)
2074
    transaction.status = TransactionStatus.AUTHORIZED
2075
    for order in transaction.orders:
2076
        order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
2077
        order.statusDescription = "Submitted to warehouse"
4247 rajveer 2078
    session.commit()
2079
 
4259 anupam.sin 2080
def refund_transaction(transactionId, refundedBy, reason):
2081
    """
2082
    This method is called when a flagged payment is deemed unserviceable and the corresponding orders
2083
    need to be cancelled
2084
 
2085
    Parameters:
2086
     - transactionId
2087
    """
2088
    transaction = get_transaction(transactionId)
2089
    transaction.status = TransactionStatus.FAILED
2090
    for order in transaction.orders:
2091
        refund_order(order.id, refundedBy, reason)
2092
    session.commit()
2093
 
4247 rajveer 2094
def mark_order_cancellation_request_denied(orderId):
2095
    """
4283 anupam.sin 2096
    If we decide to not to cancel order, we will move the order to previous status.
4247 rajveer 2097
 
2098
    Parameters:
2099
     - orderId
2100
    """
2101
    order = get_order(orderId)
2102
    order.status = order.previousStatus
2103
    order.previousStatus = None
2104
    order.statusDescription = "Cancellation request denied"
2105
    session.commit()
2106
 
2107
def mark_order_cancellation_request_confirmed(orderId):
2108
    """
2109
    If we decide to to cancel order, CRM will call this method to move the status of order to
2110
    cancellation request confirmed. After this OM will be able to cancel the order.
2111
 
2112
    Parameters:
2113
     - orderId
2114
    """
2115
    order = get_order(orderId)
2116
    order.status = OrderStatus.CANCEL_REQUEST_CONFIRMED
2117
    order.statusDescription = "Cancellation request confirmed"
2118
    session.commit()
2119
 
4285 rajveer 2120
def accept_orders_for_item_id(itemId, inventory):
2121
    """
2122
    Marks the orders as ACCEPTED for the given itemId and inventory. It also updates the accepted timestamp. If the
2123
    given order is not a COD order, it also captures the payment if the same has not been captured.
2124
 
2125
    Parameters:
2126
     - itemId
2127
     - inventory
2128
    """
4938 rajveer 2129
    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 2130
    for order in orders:
4301 rajveer 2131
        if inventory > 0:
2132
            lineitem = order.lineitems[0]
2133
            if itemId == lineitem.item_id:
2134
                try:
2135
                    accept_order(order.id)
2136
                    inventory = inventory - lineitem.quantity
2137
                except:
2138
                    logging.info("Unable to accept the order")
2139
        else:
2140
            order_outofstock(order.id)
4285 rajveer 2141
    return
2142
 
4607 rajveer 2143
def get_slipped_sipping_date_orders():
4662 rajveer 2144
    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 2145
 
2146
def get_cancelled_orders(cancelDateFrom, cancelDateTo):
2147
    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 2148
 
4369 rajveer 2149
def mark_orders_as_po_raised(vendorId, itemId, quantity, estimate, isReminder):
2150
    if isReminder:
2151
        statuses = tuple([OrderStatus.LOW_INV_PO_RAISED_TIMEOUT, OrderStatus.LOW_INV_REVERSAL_TIMEOUT])
2152
    else:
2153
        statuses = tuple([OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW])
2154
 
2155
    orders = Order.query.filter(Order.status.in_(statuses)).order_by(Order.expected_shipping_time).all()
4303 rajveer 2156
    for order in orders:
2157
        lineitem = order.lineitems[0]
2158
        if quantity >= lineitem.quantity and itemId == lineitem.item_id:
2159
            if estimate > 0:
2160
                add_delay_reason(order.id, DelayReason.OTHERS, estimate)
2161
            order.status = OrderStatus.LOW_INV_PO_RAISED
4362 rajveer 2162
            order.statusDescription = "PO Raised"
4303 rajveer 2163
            quantity = quantity - lineitem.quantity
2164
            store_inventory_action(order, itemId, HotspotAction.PO_RAISED, estimate, lineitem.quantity)
2165
            session.commit()
2166
 
4369 rajveer 2167
def mark_orders_as_reversal_initiated(vendorId, itemId, quantity, estimate, isReminder):
2168
    if isReminder:
2169
        statuses = tuple([OrderStatus.LOW_INV_PO_RAISED_TIMEOUT, OrderStatus.LOW_INV_REVERSAL_TIMEOUT])
2170
    else:
2171
        statuses = tuple([OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW])
2172
    orders = Order.query.filter(Order.status.in_(statuses)).order_by(Order.expected_shipping_time).all()
4303 rajveer 2173
    for order in orders:
2174
        lineitem = order.lineitems[0]
2175
        if quantity >= lineitem.quantity and itemId == lineitem.item_id:
2176
            if estimate > 0:
2177
                add_delay_reason(order.id, DelayReason.OTHERS, estimate)
2178
            order.status = OrderStatus.LOW_INV_REVERSAL_IN_PROCESS
4362 rajveer 2179
            order.statusDescription = "Reversal Initiated"
4303 rajveer 2180
            quantity = quantity - lineitem.quantity
2181
            store_inventory_action(order, itemId, HotspotAction.REVERSAL_INITIATED, estimate, lineitem.quantity)
2182
            session.commit()
2183
 
4369 rajveer 2184
def mark_orders_as_not_available(vendorId, itemId, quantity, estimate, isReminder):
2185
    if isReminder:
2186
        statuses = tuple([OrderStatus.LOW_INV_PO_RAISED_TIMEOUT, OrderStatus.LOW_INV_REVERSAL_TIMEOUT])
2187
    else:
2188
        statuses = tuple([OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW])
2189
 
2190
    orders = Order.query.filter(Order.status.in_(statuses)).order_by(Order.expected_shipping_time).all()
4303 rajveer 2191
    for order in orders:
2192
        lineitem = order.lineitems[0]
2193
        if quantity >= lineitem.quantity and itemId == lineitem.item_id:
2194
            order.status = OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT
4362 rajveer 2195
            order.statusDescription = "Not Available"
4303 rajveer 2196
            quantity = quantity - lineitem.quantity
2197
            store_inventory_action(order, itemId, HotspotAction.NOT_AVAILABLE, estimate, lineitem.quantity)
2198
            session.commit()
2199
 
2200
def store_inventory_action(order, itemId, hotspotAction, estimate, quantity):
4369 rajveer 2201
    orderInv = OrderInventory.get_by(order_id=order.id)
2202
    if not orderInv:
2203
        orderInv = OrderInventory()
2204
        orderInv.order = order
4303 rajveer 2205
    orderInv.hotspotAction = hotspotAction  
2206
    orderInv.estimate = estimate
2207
    orderInv.itemId = itemId
2208
    orderInv.timestamp = datetime.datetime.now()
2209
    orderInv.quantity = quantity
2210
 
4556 mandeep.dh 2211
'''    
4369 rajveer 2212
def mark_orders_as_timeout(vendorId):
2213
    ret_timeouts = {}
2214
    orderInvs = OrderInventory.query.all()
2215
    for orderInv in orderInvs:
2216
        if orderInv.timestamp +  timedelta(days=orderInv.estimate) < datetime.datetime.now():
2217
            if not ret_timeouts.has_key(orderInv.itemId):
2218
                timeout = TimeoutSummary()
2219
                ret_timeouts[orderInv.itemId] = timeout
2220
            else:
2221
                timeout = ret_timeouts.get(orderInv.itemId)
2222
            if orderInv.hotspotAction == HotspotAction.PO_RAISED and orderInv.order.status == OrderStatus.LOW_INV_PO_RAISED:
2223
                if timeout.poRaised:
2224
                    timeout.poRaised += 1
2225
                else:
2226
                    timeout.poRaised = 1
2227
 
2228
                if timeout.poEstimate:
2229
                    timeout.poEstimate += orderInv.estimate
2230
                else:
2231
                    timeout.poEstimate = orderInv.estimate
2232
                orderInv.order.status = OrderStatus.LOW_INV_PO_RAISED_TIMEOUT
2233
                orderInv.order.statusDescription = "PO Raised Timeout"
2234
            elif orderInv.hotspotAction == HotspotAction.REVERSAL_INITIATED and orderInv.order.status == OrderStatus.LOW_INV_REVERSAL_IN_PROCESS:
2235
                if timeout.reversalInitiated:
2236
                    timeout.reversalInitiated += 1
2237
                else:
2238
                    timeout.reversalInitiated = 1
2239
 
2240
                if timeout.reversalEstimate:
2241
                    timeout.reversalEstimate += orderInv.estimate
2242
                else:
2243
                    timeout.reversalEstimate = orderInv.estimate
2244
                orderInv.order.status = OrderStatus.LOW_INV_REVERSAL_TIMEOUT
2245
                orderInv.order.statusDescription = "Reversal Initiated Timeout"
2246
            else:
2247
                orderInv.delete()
2248
    session.commit()
2249
    return ret_timeouts
4556 mandeep.dh 2250
'''
2251
 
2252
 
2253
def mark_orders_as_timeout(vendorId):
2254
    ret_timeouts = {}
2255
    orderInvs = OrderInventory.query.all()
2256
    for orderInv in orderInvs:
2257
        if not ret_timeouts.has_key(orderInv.itemId):
2258
            timeout = TimeoutSummary()
2259
            ret_timeouts[orderInv.itemId] = timeout
2260
        else:
2261
            timeout = ret_timeouts.get(orderInv.itemId)
2262
        if orderInv.hotspotAction == HotspotAction.PO_RAISED and orderInv.order.status == OrderStatus.LOW_INV_PO_RAISED:
2263
            if timeout.poRaised:
2264
                timeout.poRaised += 1
2265
            else:
2266
                timeout.poRaised = 1
2267
 
2268
            if timeout.poEstimate:
2269
                timeout.poEstimate = max(orderInv.estimate, timeout.poEstimate)
2270
            else:
2271
                timeout.poEstimate = orderInv.estimate
2272
        elif orderInv.hotspotAction == HotspotAction.REVERSAL_INITIATED and orderInv.order.status == OrderStatus.LOW_INV_REVERSAL_IN_PROCESS:
2273
            if timeout.reversalInitiated:
2274
                timeout.reversalInitiated += 1
2275
            else:
2276
                timeout.reversalInitiated = 1
2277
 
2278
            if timeout.reversalEstimate:
2279
                timeout.reversalEstimate = max(orderInv.estimate, timeout.reversalEstimate)
2280
            else:
2281
                timeout.reversalEstimate = orderInv.estimate
2282
        orderInv.order.status = OrderStatus.INVENTORY_LOW
2283
        orderInv.order.statusDescription = "Low Inventory"
2284
        orderInv.delete()
2285
    session.commit()
2286
    return ret_timeouts
2287
 
4386 anupam.sin 2288
def get_order_for_awb(awb):
2289
    order = Order.get_by(airwaybill_no=awb)
2290
    if not order:
2291
        raise TransactionServiceException(108, "no such order")
2292
 
2293
    return order
4369 rajveer 2294
 
4910 phani.kuma 2295
def get_orders_for_provider_for_status(provider_id, order_status_list):
2296
    if not provider_id or not order_status_list:
4506 phani.kuma 2297
        raise TransactionServiceException(101, "bad provider id or order status")
4910 phani.kuma 2298
    doa_provider = False
2299
    for order_status in order_status_list:
2300
        if order_status in [OrderStatus.DOA_PICKUP_CONFIRMED, OrderStatus.RET_PICKUP_CONFIRMED]:
2301
            doa_provider = True
2302
    if doa_provider:
2303
        query = Order.query.filter_by(doa_logistics_provider_id = provider_id).filter(Order.status.in_(order_status_list))
4815 phani.kuma 2304
    else:
4910 phani.kuma 2305
        query = Order.query.filter_by(logistics_provider_id = provider_id).filter(Order.status.in_(order_status_list))
4506 phani.kuma 2306
    return query.all()
4386 anupam.sin 2307
 
4600 varun.gupt 2308
def get_billed_orders_for_vendor(vendor_id, billing_date_from, billing_date_to):
5368 mandeep.dh 2309
    query = Order.query.filter(Order.status != OrderStatus.PAYMENT_PENDING)
2310
 
2311
    if vendor_id:
2312
        query = query.filter_by(vendorId = vendor_id)
2313
 
4600 varun.gupt 2314
    if billing_date_from:
2315
        query = query.filter(Order.billing_timestamp >= billing_date_from)
5368 mandeep.dh 2316
 
4600 varun.gupt 2317
    if billing_date_to:
2318
        query = query.filter(Order.billing_timestamp <= billing_date_to)
5368 mandeep.dh 2319
 
4600 varun.gupt 2320
    return query.all()
2321
 
4875 varun.gupt 2322
def get_orders_where_vendor_not_paid(vendor_id):
4885 varun.gupt 2323
    query = Order.query.filter_by(vendorId = vendor_id)
2324
    query = query.filter(Order.billing_timestamp != None)
5139 varun.gupt 2325
    query = query.filter(Order.vendor_paid != True)
5189 varun.gupt 2326
    orderStatusGroup = OrderStatusGroups()
2327
    query = query.filter(not_(Order.status.in_(orderStatusGroup.refundedOrders)))
5208 varun.gupt 2328
    #query = query.filter(not_(Order.status.in_([15,31,32,33,34,48,50,54,56,70,72,76,74,79])))
2329
    #(15,31,32,33,34,48,54,70,72,74)
4885 varun.gupt 2330
    return query.all()
4875 varun.gupt 2331
 
4600 varun.gupt 2332
def save_bluedart_settlements(map_awb_and_amount):
2333
    payment_client = PaymentClient().get_client()
2334
 
2335
    for awb, amount in map_awb_and_amount.iteritems():
2336
        order = Order.get_by(airwaybill_no = awb)
2337
 
2338
        payment = payment_client.getSuccessfulPaymentForTxnId(order.transaction_id)
2339
        settlement = PaymentSettlement()
2340
        settlement.paymentId = payment.paymentId
2341
        settlement.paymentGatewayId = payment.gatewayId
2342
        settlement.netCollection = amount
2343
        session.commit()
2344
 
4905 varun.gupt 2345
def save_payment_settlements(settlementDate, paymentGatewayId, referenceId, serviceTax, otherCharges, netCollection):
4600 varun.gupt 2346
 
2347
    settlement = PaymentSettlement()
2348
    settlement.settlementDate = settlementDate
2349
    settlement.paymentGatewayId = paymentGatewayId
4905 varun.gupt 2350
    settlement.referenceId = referenceId
4600 varun.gupt 2351
    settlement.serviceTax = serviceTax
2352
    settlement.otherCharges = otherCharges
2353
    settlement.netCollection = netCollection
2354
    session.commit()
2355
 
5382 varun.gupt 2356
def get_settlement_for_referenceId(reference_id, payment_gateway_id, is_refund = False):
5189 varun.gupt 2357
    query = PaymentSettlement.query.filter_by(referenceId = reference_id)
4600 varun.gupt 2358
 
5189 varun.gupt 2359
    if is_refund:
2360
        query = query.filter(PaymentSettlement.netCollection < 0)
2361
    else:
2362
        query = query.filter(PaymentSettlement.netCollection > 0)
2363
 
5382 varun.gupt 2364
    if payment_gateway_id:
2365
        query = query.filter_by(paymentGatewayId = payment_gateway_id)
2366
 
5189 varun.gupt 2367
    return query.first()
4600 varun.gupt 2368
 
2369
def save_ebs_settlement_summary(settlement_id, settlement_date, transaction_date_from, transaction_date_to, amount):
2370
    summary = EBSSettlementSummary()
2371
    summary.settlementId = settlement_id
2372
    summary.settlementDate = settlement_date
2373
    summary.transactionDateFrom = transaction_date_from
2374
    summary.transactionDateTo = transaction_date_to
2375
    summary.amount = amount
2376
    summary.detailsUploaded = False
2377
    session.commit()
2378
 
2379
def get_ebs_settlement_summaries():
2380
    summaries = EBSSettlementSummary.query.filter_by(detailsUploaded = False).order_by(EBSSettlementSummary.transactionDateFrom).all()
2381
    summary_map = {}
2382
 
2383
    for summary in summaries:
2384
        transactionDateFrom = str(summary.transactionDateFrom.year) + '-' + str(summary.transactionDateFrom.month) + '-' + str(summary.transactionDateFrom.day)
2385
        transactionDateTo = str(summary.transactionDateTo.year) + '-' + str(summary.transactionDateTo.month) + '-' + str(summary.transactionDateTo.day)
2386
 
2387
        summary_map[summary.settlementId] = "%s to %s" %(transactionDateFrom, transactionDateTo)
2388
 
2389
    return summary_map
2390
 
2391
def get_ebs_settlement_date(settlement_id):
2392
    summary = EBSSettlementSummary.get_by(settlementId = settlement_id)
2393
 
2394
    if summary:
2395
        return summary.settlementDate
2396
 
2397
def mark_ebs_settlement_uploaded(settlement_id):
2398
    summary = EBSSettlementSummary.get_by(settlementId = settlement_id)
2399
 
2400
    if summary:
2401
        summary.detailsUploaded = True
2402
        session.commit()
4715 varun.gupt 2403
 
2404
def get_settlements_by_date(settlement_date_from, settlement_date_to, is_refund):
2405
    query = PaymentSettlement.query
4600 varun.gupt 2406
 
4715 varun.gupt 2407
    if settlement_date_from:
2408
        query = query.filter(PaymentSettlement.settlementDate >= settlement_date_from)
2409
 
2410
    if settlement_date_to:
2411
        query = query.filter(PaymentSettlement.settlementDate <= settlement_date_to)
2412
 
4749 varun.gupt 2413
    if is_refund is True:
2414
        query = query.filter(PaymentSettlement.netCollection < 0.0)
2415
    else:
2416
        query = query.filter(PaymentSettlement.netCollection > 0.0)
4715 varun.gupt 2417
 
4749 varun.gupt 2418
    return query.all()
4715 varun.gupt 2419
 
2420
def get_reshipped_order_ids(order_ids):
2421
    reshipped_order_ids = []
2422
    return [order.new_order_id for order in Order.query.filter(Order.new_order_id.in_(order_ids)).all()]
2423
 
4749 varun.gupt 2424
def get_shipping_confirmation_email_body(order):
2425
 
2426
    html = """
2427
<html>
2428
<body>
2429
<div>
2430
    <p>Dear Customer,</p>
2431
    <p>
4885 varun.gupt 2432
        We are pleased to inform that we have shipped the order: $order_id for your product $product_name on $shipping_datetime. 
5139 varun.gupt 2433
        The shipment will be delivered to you via $courier_name Courier Service vide AWB# $awb.
4749 varun.gupt 2434
    </p>
2435
    <p>
2436
        Expected delivery date for your order is $expected_delivery_date. 
2437
        The product can be delivered to you between business hours of 10am to 6pm. 
2438
        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.
2439
    </p>
2440
    <p>
2441
        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#.
2442
    </p>
5139 varun.gupt 2443
    <p>$courier_name: $courier_phone</p>
4749 varun.gupt 2444
    <p>
2445
        Warm Regards,<br />
2446
        Saholic Team
2447
    </p>
4750 varun.gupt 2448
</div>
4749 varun.gupt 2449
</body>
2450
</html>
2451
    """
5139 varun.gupt 2452
    logistics_providers = {1: {'name': 'BlueDart', 'phone': '011-66111234'}, 2: {'name': 'Aramex', 'phone': '0124- 39419900'}}
2453
    provider_name = logistics_providers[order.logistics_provider_id]['name']
2454
    provider_phone = logistics_providers[order.logistics_provider_id]['phone']
2455
 
4749 varun.gupt 2456
    dt = datetime.datetime.strptime(str(order.shipping_timestamp), "%Y-%m-%d %H:%M:%S")
4885 varun.gupt 2457
    shipping_date = dt.strftime("%A, %d %B %Y %I:%M%p")
4749 varun.gupt 2458
    product = "%s %s %s" % (order.lineitems[0].brand, order.lineitems[0].model_name, order.lineitems[0].model_number)
4885 varun.gupt 2459
    new_expected_delivery_timestamp = datetime.datetime.now() + timedelta(adjust_delivery_time(datetime.datetime.now(), (order.promised_delivery_time - order.promised_shipping_time).days))
2460
    new_expected_delivery_date = new_expected_delivery_timestamp.strftime("%A, %d %B %Y")
5139 varun.gupt 2461
    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 2462
    return Template(html).substitute(info)
4749 varun.gupt 2463
 
2464
def enqueue_shipping_confirmation_email(orders):
4915 varun.gupt 2465
    # Calling helper service on production
2466
    helperClient = HelperClient(host_key = "helper_service_server_host_prod").get_client()
5139 varun.gupt 2467
 
4749 varun.gupt 2468
    for order in orders:
2469
        try:
2470
            emailSubject = 'Shipping Details for Order ID: ' + str(order.id)
2471
            emailBody = get_shipping_confirmation_email_body(order)
4885 varun.gupt 2472
            helperClient.saveUserEmailForSending(order.customer_email, None, emailSubject, emailBody, '', 'ShippingConfirmation')
4749 varun.gupt 2473
        except Exception as e:
2474
            print e
2475
 
4915 varun.gupt 2476
def get_order_distribution_by_status(start_date, end_date):
5067 varun.gupt 2477
    query = session.query(Order.status, func.count(Order.id)).group_by(Order.status)
2478
    query = query.filter(Order.created_timestamp >= start_date)
2479
    query = query.filter(Order.created_timestamp <= end_date)
2480
    return query.all()
4915 varun.gupt 2481
 
5067 varun.gupt 2482
def get_order_ids_for_status(status, start_datetime, end_datetime):
2483
    query = Order.query.filter(Order.status == status)
2484
    query = query.filter(Order.created_timestamp >= start_datetime)
2485
    query = query.filter(Order.created_timestamp <= end_datetime)
2486
    return query.all()
2487
 
5099 varun.gupt 2488
def update_orders_as_paid_to_vendor(order_id):
5139 varun.gupt 2489
    paid_order = Order.get_by(id = order_id)
5099 varun.gupt 2490
 
5139 varun.gupt 2491
    if paid_order.originalOrderId is None:
2492
        paid_order.vendor_paid = True
5099 varun.gupt 2493
        session.commit()
5139 varun.gupt 2494
 
2495
        for order in Order.query.filter(Order.originalOrderId == order_id).all():
2496
            order.vendor_paid = True
2497
            session.commit()
2498
    else:
5208 varun.gupt 2499
        original_order_id = paid_order.originalOrderId
5139 varun.gupt 2500
 
5208 varun.gupt 2501
        for order in Order.query.filter(Order.originalOrderId == original_order_id).all():
5139 varun.gupt 2502
            order.vendor_paid = True
2503
            session.commit()
2504
            original_order_id = order.originalOrderId
2505
 
2506
        original_order = Order.get_by(id = original_order_id)
2507
        if original_order:  original_order.vendor_paid = True
2508
        session.commit()
5348 anupam.sin 2509
 
2510
def update_COD_agent(agentEmailId, orderId):
2511
    order = Order.get_by(id=orderId)
2512
    if not order:
2513
        raise TransactionServiceException(101, "No order found for the given order id" + str(orderId))
2514
    agent = CodVerificationAgent()
2515
    agent.orderId = orderId
2516
    agent.verificationAgent = agentEmailId
2517
    session.commit()
2518
 
5099 varun.gupt 2519
 
5208 varun.gupt 2520
def get_refunded_orders_marked_paid():
2521
    orderStatusGroup = OrderStatusGroups()
2522
    return Order.query.filter(Order.vendor_paid == 1).filter(Order.status.in_(orderStatusGroup.refundedOrders)).all()
2523
 
766 rajveer 2524
def close_session():
2525
    if session.is_active:
2526
        print "session is active. closing it."
2783 chandransh 2527
        session.close()
3376 rajveer 2528
 
2529
def is_alive():
2530
    try:
2531
        session.query(Transaction.id).limit(1).one()
2532
        return True
2533
    except:
4343 varun.gupt 2534
        return False