Subversion Repositories SmartDukaan

Rev

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