Subversion Repositories SmartDukaan

Rev

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