Subversion Repositories SmartDukaan

Rev

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