Subversion Repositories SmartDukaan

Rev

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