Subversion Repositories SmartDukaan

Rev

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