Subversion Repositories SmartDukaan

Rev

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

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