Subversion Repositories SmartDukaan

Rev

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