Subversion Repositories SmartDukaan

Rev

Rev 5555 | Rev 5573 | 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()
1443
    elif order.status == OrderStatus.DOA_CERT_VALID:
4220 rajveer 1444
        new_order = __clone_order(order, False, False)
2628 chandransh 1445
        ret_order = __create_return_order(order)
4452 rajveer 1446
        order.status = OrderStatus.DOA_VALID_RESHIPPED
2628 chandransh 1447
        order.statusDescription = "Order Reshipped"
1448
        session.commit()
4479 rajveer 1449
    elif order.status == OrderStatus.DOA_RECEIVED_DAMAGED:
1450
        new_order = __clone_order(order, False, False)
1451
        ret_order = __create_return_order(order)
1452
        order.status = OrderStatus.DOA_RESHIPPED_RCVD_DAMAGED
1453
        order.statusDescription = "Order Reshipped Received Damaged"
1454
        session.commit()
1455
    elif order.status == OrderStatus.DOA_LOST_IN_TRANSIT:
1456
        new_order = __clone_order(order, False, False)
1457
        order.status = OrderStatus.DOA_RESHIPPED_LOST_IN_TRANSIT
1458
        order.statusDescription = "Order Reshipped Lost In Transit"
1459
        session.commit()
4614 rajveer 1460
    elif order.status == OrderStatus.RET_PRODUCT_USABLE:
4495 rajveer 1461
        new_order = __clone_order(order, True, False)
4614 rajveer 1462
        order.status = OrderStatus.RET_PRODUCT_USABLE_RESHIPPED
4495 rajveer 1463
        order.statusDescription = "Order Reshipped"
1464
        session.commit()
4614 rajveer 1465
    elif order.status == OrderStatus.RET_PRODUCT_UNUSABLE:
4495 rajveer 1466
        new_order = __clone_order(order, False, False)
1467
        ret_order = __create_return_order(order)
4614 rajveer 1468
        order.status = OrderStatus.RET_PRODUCT_UNUSABLE_RESHIPPED
4495 rajveer 1469
        order.statusDescription = "Order Reshipped"
1470
        session.commit()
1471
    elif order.status == OrderStatus.RET_RECEIVED_DAMAGED:
1472
        new_order = __clone_order(order, False, False)
1473
        ret_order = __create_return_order(order)
1474
        order.status = OrderStatus.RET_RESHIPPED_RCVD_DAMAGED
1475
        order.statusDescription = "Order Reshipped Received Damaged"
1476
        session.commit()
1477
    elif order.status == OrderStatus.RET_LOST_IN_TRANSIT:
1478
        new_order = __clone_order(order, False, False)
1479
        order.status = OrderStatus.RET_RESHIPPED_LOST_IN_TRANSIT
1480
        order.statusDescription = "Order Reshipped Lost In Transit"
1481
        session.commit()
2628 chandransh 1482
    else:
1483
        raise TransactionServiceException(112, "This order can't be reshipped")
1484
 
2764 chandransh 1485
    order.reship_timestamp = datetime.datetime.now()
2628 chandransh 1486
    order.new_order_id = new_order.id
1487
    session.commit()
1488
 
1489
    return new_order.id
1490
 
3226 chandransh 1491
def refund_order(order_id, refunded_by, reason):
2628 chandransh 1492
    """
4484 rajveer 1493
    If the order is in RTO_RECEIVED_PRESTINE, DOA_CERT_VALID or DOA_CERT_INVALID state, it does the following:
2628 chandransh 1494
        1. Creates a refund request for batch processing.
1495
        2. Creates a return order for the warehouse executive to return the shipped material.
4484 rajveer 1496
        3. Marks the current order as RTO_REFUNDED, DOA_VALID_REFUNDED or DOA_INVALID_REFUNDED final states.
2628 chandransh 1497
 
1498
    If the order is in SUBMITTED_FOR_PROCESSING or INVENTORY_LOW state, it does the following:
1499
        1. Creates a refund request for batch processing.
3226 chandransh 1500
        2. Cancels the reservation of the item in the warehouse.
1501
        3. Marks the current order as the REFUNDED final state.
2628 chandransh 1502
 
3226 chandransh 1503
    For all COD orders, if the order is in INIT, SUBMITTED_FOR_PROCESSING or INVENTORY_LOW state, it does the following:
1504
        1. Cancels the reservation of the item in the warehouse.
1505
        2. Marks the current order as CANCELED.
1506
 
1507
    In all cases, it updates the reason for cancellation or refund and the person who performed the action.
1508
 
1509
    Returns True if it is successful, False otherwise.
2628 chandransh 1510
 
1511
    Throws an exception if the order with the given id couldn't be found.
1512
 
1513
    Parameters:
3226 chandransh 1514
     - order_id
1515
     - refunded_by
1516
     - reason
2628 chandransh 1517
    """
3414 chandransh 1518
    logging.info("Refunding order id: " + str(order_id))
2628 chandransh 1519
    order = get_order(order_id)
3186 chandransh 1520
 
3226 chandransh 1521
    if order.cod:
3414 chandransh 1522
        logging.info("Refunding COD order with status " + str(order.status))
4662 rajveer 1523
        status_transition = { OrderStatus.LOST_IN_TRANSIT : OrderStatus.LOST_IN_TRANSIT_REFUNDED,
1524
                     OrderStatus.RTO_RECEIVED_PRESTINE : OrderStatus.RTO_REFUNDED,
4486 rajveer 1525
                     OrderStatus.RTO_RECEIVED_DAMAGED : OrderStatus.RTO_DAMAGED_REFUNDED,
1526
                     OrderStatus.RTO_LOST_IN_TRANSIT : OrderStatus.RTO_LOST_IN_TRANSIT_REFUNDED,
3366 chandransh 1527
                     OrderStatus.DOA_CERT_INVALID : OrderStatus.DOA_INVALID_REFUNDED,
1528
                     OrderStatus.DOA_CERT_VALID : OrderStatus.DOA_VALID_REFUNDED,
4479 rajveer 1529
                     OrderStatus.DOA_RECEIVED_DAMAGED : OrderStatus.DOA_REFUNDED_RCVD_DAMAGED,
1530
                     OrderStatus.DOA_LOST_IN_TRANSIT : OrderStatus.DOA_REFUNDED_LOST_IN_TRANSIT,
4495 rajveer 1531
                     OrderStatus.RET_PRODUCT_UNUSABLE : OrderStatus.RET_PRODUCT_UNUSABLE_REFUNDED,
1532
                     OrderStatus.RET_PRODUCT_USABLE : OrderStatus.RET_PRODUCT_USABLE_REFUNDED,
1533
                     OrderStatus.RET_RECEIVED_DAMAGED : OrderStatus.RET_REFUNDED_RCVD_DAMAGED,
1534
                     OrderStatus.RET_LOST_IN_TRANSIT : OrderStatus.RET_REFUNDED_LOST_IN_TRANSIT,
4682 rajveer 1535
                     OrderStatus.COD_VERIFICATION_PENDING : OrderStatus.COD_VERIFICATION_FAILED,
1536
                     OrderStatus.SUBMITTED_FOR_PROCESSING : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1537
                     OrderStatus.INVENTORY_LOW : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1538
                     OrderStatus.LOW_INV_PO_RAISED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1539
                     OrderStatus.LOW_INV_REVERSAL_IN_PROCESS : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1540
                     OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1541
                     OrderStatus.ACCEPTED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1542
                     OrderStatus.BILLED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
4247 rajveer 1543
                     OrderStatus.CANCEL_REQUEST_CONFIRMED : OrderStatus.CANCELLED_ON_CUSTOMER_REQUEST
3366 chandransh 1544
                     }
1545
        if order.status not in status_transition.keys():
1546
            raise TransactionServiceException(114, "This order can't be refunded")
1547
 
5199 mandeep.dh 1548
        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 1549
            __update_inventory_reservation(order)
1550
            order.statusDescription = "Order Cancelled"
3415 chandransh 1551
        elif order.status == OrderStatus.BILLED:
3413 chandransh 1552
            __create_return_order(order)
1553
            order.statusDescription = "Order Cancelled"
4486 rajveer 1554
        elif order.status in [OrderStatus.RTO_RECEIVED_PRESTINE, OrderStatus.RTO_RECEIVED_DAMAGED, OrderStatus.RTO_LOST_IN_TRANSIT]:
5386 phani.kuma 1555
            if order.status != OrderStatus.RTO_LOST_IN_TRANSIT:
1556
                __create_return_order(order)
4486 rajveer 1557
            order.statusDescription = "RTO Refunded"
4662 rajveer 1558
        elif order.status in [OrderStatus.LOST_IN_TRANSIT]:
5386 phani.kuma 1559
            #__create_return_order(order)
4662 rajveer 1560
            order.statusDescription = "Lost in Transit Refunded"
4479 rajveer 1561
        elif order.status in [OrderStatus.DOA_CERT_INVALID, OrderStatus.DOA_CERT_VALID, OrderStatus.DOA_RECEIVED_DAMAGED, OrderStatus.DOA_LOST_IN_TRANSIT] :
5386 phani.kuma 1562
            if order.status != OrderStatus.DOA_LOST_IN_TRANSIT:
1563
                __create_return_order(order)
3226 chandransh 1564
            __create_refund(order)
4495 rajveer 1565
            order.statusDescription = "DOA Refunded"
1566
        elif order.status in [OrderStatus.RET_PRODUCT_UNUSABLE, OrderStatus.RET_PRODUCT_USABLE, OrderStatus.RET_RECEIVED_DAMAGED, OrderStatus.RET_LOST_IN_TRANSIT] :
5386 phani.kuma 1567
            if order.status != OrderStatus.RET_LOST_IN_TRANSIT:
1568
                __create_return_order(order)
4495 rajveer 1569
            __create_refund(order)
1570
            order.statusDescription = "Return Refunded"
4247 rajveer 1571
        elif order.status == OrderStatus.CANCEL_REQUEST_CONFIRMED:
5199 mandeep.dh 1572
            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 1573
                __update_inventory_reservation(order)
1574
                order.statusDescription = "Order Cancelled on customer request"
1575
            elif order.previousStatus == OrderStatus.BILLED:
1576
                __create_return_order(order)
1577
                order.statusDescription = "Order Cancelled on customer request"
3226 chandransh 1578
    else:
4662 rajveer 1579
        status_transition = {OrderStatus.LOST_IN_TRANSIT : OrderStatus.LOST_IN_TRANSIT_REFUNDED,
1580
                     OrderStatus.RTO_RECEIVED_PRESTINE : OrderStatus.RTO_REFUNDED,
4486 rajveer 1581
                     OrderStatus.RTO_RECEIVED_DAMAGED : OrderStatus.RTO_DAMAGED_REFUNDED,
1582
                     OrderStatus.RTO_LOST_IN_TRANSIT : OrderStatus.RTO_LOST_IN_TRANSIT_REFUNDED,
3366 chandransh 1583
                     OrderStatus.DOA_CERT_INVALID : OrderStatus.DOA_INVALID_REFUNDED,
1584
                     OrderStatus.DOA_CERT_VALID : OrderStatus.DOA_VALID_REFUNDED,
4479 rajveer 1585
                     OrderStatus.DOA_RECEIVED_DAMAGED : OrderStatus.DOA_REFUNDED_RCVD_DAMAGED,
1586
                     OrderStatus.DOA_LOST_IN_TRANSIT : OrderStatus.DOA_REFUNDED_LOST_IN_TRANSIT,
4495 rajveer 1587
                     OrderStatus.RET_PRODUCT_UNUSABLE : OrderStatus.RET_PRODUCT_UNUSABLE_REFUNDED,
1588
                     OrderStatus.RET_PRODUCT_USABLE : OrderStatus.RET_PRODUCT_USABLE_REFUNDED,
1589
                     OrderStatus.RET_RECEIVED_DAMAGED : OrderStatus.RET_REFUNDED_RCVD_DAMAGED,
1590
                     OrderStatus.RET_LOST_IN_TRANSIT : OrderStatus.RET_REFUNDED_LOST_IN_TRANSIT,
4682 rajveer 1591
                     OrderStatus.SUBMITTED_FOR_PROCESSING : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1592
                     OrderStatus.INVENTORY_LOW : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1593
                     OrderStatus.LOW_INV_PO_RAISED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1594
                     OrderStatus.LOW_INV_REVERSAL_IN_PROCESS : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1595
                     OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1596
                     OrderStatus.ACCEPTED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
1597
                     OrderStatus.BILLED : OrderStatus.CANCELLED_DUE_TO_LOW_INVENTORY,
4247 rajveer 1598
                     OrderStatus.CANCEL_REQUEST_CONFIRMED : OrderStatus.CANCELLED_ON_CUSTOMER_REQUEST,
1599
                     OrderStatus.PAYMENT_FLAGGED : OrderStatus.PAYMENT_FLAGGED_DENIED
3366 chandransh 1600
                     }
1601
        if order.status not in status_transition.keys():
1602
            raise TransactionServiceException(114, "This order can't be refunded")
1603
 
4495 rajveer 1604
        if order.status in [OrderStatus.RTO_RECEIVED_PRESTINE, OrderStatus.RTO_RECEIVED_DAMAGED, OrderStatus.RTO_LOST_IN_TRANSIT] :
5386 phani.kuma 1605
            if order.status != OrderStatus.RTO_LOST_IN_TRANSIT:
1606
                __create_return_order(order)
3226 chandransh 1607
            __create_refund(order)
4495 rajveer 1608
            order.statusDescription = "RTO Refunded"
4662 rajveer 1609
        elif order.status in [OrderStatus.LOST_IN_TRANSIT]:
5386 phani.kuma 1610
            #__create_return_order(order)
4662 rajveer 1611
            __create_refund(order)
1612
            order.statusDescription = "Lost in Transit Refunded"
4495 rajveer 1613
        elif order.status in [OrderStatus.DOA_CERT_INVALID, OrderStatus.DOA_CERT_VALID, OrderStatus.DOA_RECEIVED_DAMAGED, OrderStatus.DOA_LOST_IN_TRANSIT] :
5386 phani.kuma 1614
            if order.status != OrderStatus.DOA_LOST_IN_TRANSIT:
1615
                __create_return_order(order)
4495 rajveer 1616
            __create_refund(order)
1617
            order.statusDescription = "DOA Refunded"
1618
        elif order.status in [OrderStatus.RET_PRODUCT_UNUSABLE, OrderStatus.RET_PRODUCT_USABLE, OrderStatus.RET_RECEIVED_DAMAGED, OrderStatus.RET_LOST_IN_TRANSIT] :
5386 phani.kuma 1619
            if order.status != OrderStatus.RET_LOST_IN_TRANSIT:
1620
                __create_return_order(order)
4495 rajveer 1621
            __create_refund(order)
1622
            order.statusDescription = "Return Refunded"
5199 mandeep.dh 1623
        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 1624
            __update_inventory_reservation(order)
1625
            order.statusDescription = "Order Refunded"
4247 rajveer 1626
        elif order.status == OrderStatus.CANCEL_REQUEST_CONFIRMED:
5272 mandeep.dh 1627
            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 1628
                if order.previousStatus == OrderStatus.ACCEPTED:
1629
                    __create_refund(order)
4247 rajveer 1630
                __update_inventory_reservation(order)
1631
                order.statusDescription = "Order Cancelled on customer request"
1632
            elif order.previousStatus == OrderStatus.BILLED:
1633
                __create_return_order(order)
1634
                __create_refund(order)
1635
                order.statusDescription = "Order Cancelled on customer request"
1636
        elif order.status == OrderStatus.PAYMENT_FLAGGED:
1637
            __update_inventory_reservation(order)
1638
            order.statusDescription = "Order Cancelled due to payment flagged"
3195 chandransh 1639
 
4873 mandeep.dh 1640
    # For orders that are cancelled after being billed, we need to scan in the scanned out
1641
    # inventory item and change availability accordingly
5110 mandeep.dh 1642
    catalogClient = CatalogClient().get_client()
1643
    warehouse = catalogClient.getWarehouse(order.warehouse_id)
1644
    if warehouse.billingType == BillingType.OURS:
4873 mandeep.dh 1645
        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]):
1646
            lineitem = order.lineitems[0]
5177 mandeep.dh 1647
            item = catalogClient.getItem(lineitem.item_id)
5361 mandeep.dh 1648
            warehouseClient = WarehouseClient().get_client()
5177 mandeep.dh 1649
            if ItemType.SERIALIZED == item.type:
1650
                warehouseClient.scanSerializedItemForOrder(lineitem.serial_number, ScanType.SALE_RET, order.id, order.fulfilmentWarehouseId, lineitem.quantity, order.warehouse_id)
5361 mandeep.dh 1651
            else:
1652
                warehouseClient.scanForOrder(None, ScanType.SALE_RET, lineitem.quantity, order.id, order.fulfilmentWarehouseId, order.warehouse_id)
4873 mandeep.dh 1653
 
3195 chandransh 1654
    order.status = status_transition[order.status]
1655
    order.refund_timestamp = datetime.datetime.now()
3226 chandransh 1656
    order.refunded_by = refunded_by
1657
    order.refund_reason = reason
4873 mandeep.dh 1658
 
2628 chandransh 1659
    session.commit()
1660
    return True
1661
 
3186 chandransh 1662
def __update_inventory_reservation(order):
3191 chandransh 1663
    '''
1664
    Reduce the reservation count for all line items of the given order.
1665
    '''
3186 chandransh 1666
    try:
1667
        catalog_client = CatalogClient().get_client()
1668
        for lineitem in order.lineitems:
5530 mandeep.dh 1669
            catalog_client.reduceReservationCount(lineitem.item_id, order.fulfilmentWarehouseId, lineitem.quantity)
3186 chandransh 1670
    except:
1671
        print "Unable to reduce reservation count"
1672
 
4220 rajveer 1673
def __clone_order(order, should_copy_billing_info, is_cod):
2628 chandransh 1674
    current_time = datetime.datetime.now()
1675
    new_order = Order()
1676
    new_order.customer_id = order.customer_id
1677
    new_order.customer_name = order.customer_name
1678
    new_order.customer_city = order.customer_city
1679
    new_order.customer_state = order.customer_state
1680
    new_order.customer_mobilenumber = order.customer_mobilenumber
1681
    new_order.customer_pincode = order.customer_pincode
1682
    new_order.customer_address1 = order.customer_address1
1683
    new_order.customer_address2 = order.customer_address2
1684
    new_order.customer_email = order.customer_email
1685
    new_order.total_amount = order.total_amount
1686
    new_order.total_weight = order.total_weight
1687
    new_order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
1688
    new_order.statusDescription = 'Submitted for Processing'
1689
    new_order.created_timestamp = current_time
5062 varun.gupt 1690
    new_order.originalOrderId = order.originalOrderId if order.originalOrderId is not None else order.id 
2628 chandransh 1691
 
1692
    new_order.transaction = order.transaction
4220 rajveer 1693
    new_order.cod = is_cod
5527 anupam.sin 1694
    new_order.orderType = order.orderType
2628 chandransh 1695
 
1696
    for line_item in order.lineitems:
1697
        litem = LineItem()
1698
        litem.item_id = line_item.item_id
1699
        litem.productGroup = line_item.productGroup
1700
        litem.brand = line_item.brand
1701
        if line_item.model_number:
1702
            litem.model_number = line_item.model_number
1703
        if line_item.model_name:    
1704
            litem.model_name = line_item.model_name
1705
        if line_item.color:
1706
            litem.color = line_item.color
1707
        if line_item.extra_info:
1708
            litem.extra_info = line_item.extra_info
1709
        litem.quantity = line_item.quantity
1710
        litem.unit_price = line_item.unit_price
1711
        litem.unit_weight = line_item.unit_weight
1712
        litem.total_price = line_item.total_price
1713
        litem.total_weight = line_item.total_weight
1714
        litem.transfer_price = line_item.transfer_price
4840 mandeep.dh 1715
        litem.dealText = line_item.dealText
2628 chandransh 1716
        litem.order = new_order
1717
 
1718
    logistics_client = LogisticsClient().get_client()
1719
    item_id = new_order.lineitems[0].item_id
4479 rajveer 1720
    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 1721
    logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
1722
    new_order.warehouse_id = logistics_info.warehouseId
5110 mandeep.dh 1723
    new_order.fulfilmentWarehouseId = logistics_info.fulfilmentWarehouseId
2628 chandransh 1724
    new_order.logistics_provider_id = logistics_info.providerId
1725
    new_order.airwaybill_no = logistics_info.airway_billno
1726
    new_order.tracking_id = new_order.airwaybill_no
1727
    new_order.expected_delivery_time = current_time + datetime.timedelta(days=logistics_info.deliveryTime)
3986 chandransh 1728
    new_order.promised_delivery_time = new_order.expected_delivery_time
4299 rajveer 1729
 
2628 chandransh 1730
    if should_copy_billing_info:
5388 phani.kuma 1731
        new_order.vendorId = order.vendorId
2628 chandransh 1732
        new_order.invoice_number = order.invoice_number
1733
        new_order.billed_by = order.billed_by
1734
        new_order.warehouse_id = order.warehouse_id
5110 mandeep.dh 1735
        new_order.fulfilmentWarehouseId = order.fulfilmentWarehouseId
2628 chandransh 1736
        new_order.accepted_timestamp = current_time
1737
        new_order.billing_timestamp = current_time    
1738
        new_order.status = OrderStatus.BILLED
1739
        new_order.statusDescription = 'Order Billed'
1740
    else:       
3133 rajveer 1741
        catalog_client = CatalogClient().get_client()
5110 mandeep.dh 1742
        catalog_client.reserveItemInWarehouse(item_id, logistics_info.fulfilmentWarehouseId, new_order.lineitems[0].quantity)
2628 chandransh 1743
 
1744
    return new_order
1745
 
1746
def __create_return_order(order):
2687 chandransh 1747
    ret_order = ReturnOrder(order)
2628 chandransh 1748
    return ret_order
1749
 
1750
def __create_refund(order):
4078 chandransh 1751
    payment_client = PaymentClient().get_client()
1752
    payment_client.createRefund(order.id, order.transaction.id, order.total_amount)
2747 chandransh 1753
    return
2628 chandransh 1754
 
2536 chandransh 1755
def __get_order_address(order):
1756
    address = order.customer_name + "\n" + order.customer_address1 + "\n"
1757
    if order.customer_address2:
1758
        address = address + order.customer_address2 + "\n"
1759
    address = address + order.customer_city + "\n"
1760
    address = address + order.customer_state + "\n"
1761
    address = address + "PIN " + order.customer_pincode + "\n"
1762
    address = address + "Phone: " + order.customer_mobilenumber
1763
    return address
1764
 
4815 phani.kuma 1765
def __generate_return_advice(order, warehouse, provider, filename):
1766
    if warehouse.id == 7:
1767
        executive = 'Amit Kumar'
1768
    else:
4966 phani.kuma 1769
        executive = 'Dinesh Kumar'
2536 chandransh 1770
    pdf = Canvas(filename)
1771
    pdf.setFont('Times-Bold',16)
1772
    address_text = pdf.beginText(inch, PAGE_HEIGHT - inch)
1773
    address_text.textLine("To")
4815 phani.kuma 1774
    address_text.textLine(executive)
2536 chandransh 1775
    for line in warehouse.location.split("\n"):
1776
        address_text.textLine(line)
1777
    address_text.textLine("PIN " + warehouse.pincode)
1778
    pdf.drawText(address_text)
1779
 
1780
    pdf.setFont('Times-Roman',12)
1781
    order_text = pdf.beginText(inch, PAGE_HEIGHT - 4 * inch)
3051 chandransh 1782
    order_text.textLine("Pickup CODE: " + provider.details[DeliveryType.PREPAID].accountNo)
2536 chandransh 1783
    lineitem = order.lineitems[0] 
4234 rajveer 1784
    order_text.textLine("Content : " + lineitem.brand + " " + str(lineitem.model_number) + " " + str(lineitem.color))
2536 chandransh 1785
    order_text.textLine("Declared Value: Rs. " + str(order.total_amount))
1786
    order_text.textLine("Order ID : " + str(order.id))
1787
    pdf.drawText(order_text)
1788
    pdf.showPage()
1789
    pdf.save()
1790
    return filename
1791
 
2697 chandransh 1792
def get_return_orders(warehouse_id, from_date, to_date):
1793
    query = ReturnOrder.query.filter_by(processedStatus = False)
1794
    if warehouse_id != -1:
1795
        query = query.filter_by(warehouseId = warehouse_id)
1796
    if from_date:
4118 chandransh 1797
        query = query.filter(ReturnOrder.createdAt >from_date)
2697 chandransh 1798
    if to_date:
4118 chandransh 1799
        query = query.filter(ReturnOrder.createdAt < to_date)
2697 chandransh 1800
    return [return_order.to_thrift_object() for return_order in query.all()]
1801
 
5481 phani.kuma 1802
def get_all_return_orders(onlyNotProcessed, from_date, to_date):
1803
    query = ReturnOrder.query
1804
    if onlyNotProcessed:
1805
        query = query.filter_by(processedStatus = False)
1806
    if from_date:
1807
        query = query.filter(ReturnOrder.createdAt >= from_date)
1808
    if to_date:
1809
        query = query.filter(ReturnOrder.createdAt <= to_date)
1810
    return [return_order.to_thrift_object() for return_order in query.all()]
1811
 
2700 chandransh 1812
def get_return_order(id):
1813
    ret_order = ReturnOrder.get_by(orderId = id)
1814
    if ret_order is None:
1815
        raise TransactionServiceException(116, "No return order found for the given order id")
1816
    return ret_order.to_thrift_object()
1817
 
2697 chandransh 1818
def process_return(ret_order_id):
1819
    ret_order = ReturnOrder.get_by(orderId = ret_order_id)
1820
    if ret_order is None:
1821
        raise TransactionServiceException(116, "No return order found for the given order id")
1822
    ret_order.processedStatus = True
2701 chandransh 1823
    ret_order.processedAt = datetime.datetime.now()
2697 chandransh 1824
    session.commit()
1825
 
4757 mandeep.dh 1826
def update_orders_as_PORaised(itemIdQuantityMap, purchaseOrderId, warehouseId):
1827
    """
1828
    Updates orders as PO raised. Also updates purchase order id in orders. Pass a map of items mapped to
1829
    the quantities for which the PO is raised.
1830
 
1831
    Parameters:
1832
     - itemIdQuantityMap
1833
     - purchaseOrderId
1834
     - warehouseId
1835
    """
3451 chandransh 1836
    query = Order.query.with_lockmode("update").filter_by(warehouse_id=warehouseId)
4757 mandeep.dh 1837
    query = query.filter(or_(Order.status == OrderStatus.SUBMITTED_FOR_PROCESSING, Order.status == OrderStatus.INVENTORY_LOW))
2819 chandransh 1838
    query = query.filter_by(purchase_order_id=None)
1839
    query = query.order_by(Order.created_timestamp)
1840
    pending_orders = query.all()
4586 mandeep.dh 1841
 
1842
    for order in pending_orders:
4757 mandeep.dh 1843
        lineitem = order.lineitems[0]
1844
        if itemIdQuantityMap.has_key(lineitem.item_id):
1845
            if itemIdQuantityMap[lineitem.item_id] >= lineitem.quantity:
1846
                order.status = OrderStatus.LOW_INV_PO_RAISED
1847
                order.statusDescription = 'In Process'
1848
                order.purchase_order_id = purchaseOrderId
1849
                itemIdQuantityMap[lineitem.item_id] -= lineitem.quantity
4434 mandeep.dh 1850
 
2819 chandransh 1851
    session.commit()
1852
 
3451 chandransh 1853
def update_weight(order_id, weight):
3469 chandransh 1854
    '''
1855
    Update the weight of order
1856
    '''
3451 chandransh 1857
    order = get_order(order_id)
1858
    order.total_weight = weight
3469 chandransh 1859
    lineitem = order.lineitems[0]
1860
    lineitem.total_weight = weight
1861
    lineitem.unit_weight = weight
3451 chandransh 1862
 
3469 chandransh 1863
    session.commit()
1864
    return order
1865
 
1866
def change_product(order_id, item_id):
1867
    '''
1868
    Ship a product of a different color to the customer.
1869
    '''
1870
    order = get_order(order_id)
4662 rajveer 1871
    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 1872
        raise TransactionServiceException(120, "This order has already been processed. Please seek help from engineering.")
1873
 
1874
    lineitem = order.lineitems[0]
3451 chandransh 1875
 
3469 chandransh 1876
    catalog_client = CatalogClient().get_client()
1877
 
1878
    old_item = catalog_client.getItem(lineitem.item_id)
1879
    item = catalog_client.getItem(item_id)
1880
    if old_item.catalogItemId != item.catalogItemId:
1881
        raise TransactionServiceException(121, "You can't ship a different item. You can only ship the same item in a different color.")
1882
 
5110 mandeep.dh 1883
    catalog_client.reserveItemInWarehouse(item_id, order.fulfilmentWarehouseId, lineitem.quantity)
1884
    __update_inventory_reservation(order)
3469 chandransh 1885
    #TODO: Check that this new item has the same price
1886
 
1887
    lineitem.item_id = item_id
1888
    lineitem.color = item.color
1889
 
3451 chandransh 1890
    session.commit()
3469 chandransh 1891
 
1892
    order = get_order(order_id)
3451 chandransh 1893
    return order
3469 chandransh 1894
 
1895
def change_warehouse(order_id, warehouse_id):
1896
    '''
1897
    Update the warehouse which will be used to fulfil this order.
1898
    '''
1899
    order = get_order(order_id)
4662 rajveer 1900
    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 1901
        raise TransactionServiceException(117, "This order has already been processed. Please seek help from engineering.")
1902
 
1903
    if warehouse_id == order.warehouse_id:
1904
        raise TransactionServiceException(118, "You have selected the current warehouse again. Nothing to do")
1905
 
1906
    lineitem = order.lineitems[0]
1907
    catalog_client = CatalogClient().get_client()
1908
    try:
1909
        warehouse = catalog_client.getWarehouse(warehouse_id)
1910
    except:
1911
        raise TransactionServiceException(119, "No warehouse with id" + str(warehouse_id))
5110 mandeep.dh 1912
 
5147 mandeep.dh 1913
    if warehouse.billingWarehouseId is None:
1914
        raise TransactionServiceException(119, "Shifting of warehouse allowed to warehouse with billing support only")
5110 mandeep.dh 1915
 
5147 mandeep.dh 1916
    # If One gives a shipping location for warehouse shift, we should assign order to the GOOD warehouse
1917
    # present with this shipping location with maximum availability
1918
    if warehouse.inventoryType != InventoryType.GOOD:
1919
        warehouses = catalog_client.getWarehouses(None, InventoryType.GOOD, 0, 0, warehouse.id)
1920
        if warehouses:
1921
            itemInventory = catalog_client.getItemInventoryByItemId(lineitem.item_id)
1922
            warehouse = warehouses[0]
1923
            maxAvailability = 0
1924
            for goodWarehouse in warehouses:
1925
                if itemInventory.availability.has_key(goodWarehouse.id) and maxAvailability < itemInventory.availability[goodWarehouse.id]:
1926
                    warehouse = goodWarehouse
1927
                    maxAvailability = itemInventory.availability[goodWarehouse.id]
1928
 
1929
            # Use preferred vendor's warehouse if not available anywhere
1930
            if not maxAvailability:
1931
                item = catalog_client.getItem(lineitem.item_id)
1932
                if item.preferredVendor:
1933
                    for goodWarehouse in warehouses:
1934
                        if goodWarehouse.vendor.id == item.preferredVendor:
1935
                            warehouse = goodWarehouse
1936
        else:
1937
            raise TransactionServiceException(119, "Shifting of warehouse allowed to GOOD inventory type warehouse with billing support")
1938
 
5199 mandeep.dh 1939
    catalog_client.reserveItemInWarehouse(lineitem.item_id, warehouse.id, lineitem.quantity)
5110 mandeep.dh 1940
    __update_inventory_reservation(order)
1941
 
1942
    order.warehouse_id = warehouse.billingWarehouseId
5147 mandeep.dh 1943
    order.fulfilmentWarehouseId = warehouse.id
3469 chandransh 1944
    session.commit()
1945
    return order
3553 chandransh 1946
 
4647 rajveer 1947
def add_delay_reason(order_id, reason, further_delay, delayReasonText):
3553 chandransh 1948
    '''
3994 chandransh 1949
    Adds a delay reason to the order and updates the expected delivery time.
3553 chandransh 1950
    '''
1951
    order = get_order(order_id)
1952
    try:
3581 chandransh 1953
        order.delay_reason = DelayReason._VALUES_TO_NAMES[reason]
4647 rajveer 1954
        order.delayReasonText = delayReasonText
4009 chandransh 1955
        actual_delivery_delay = adjust_delivery_time(order.expected_delivery_time, further_delay)
1956
        order.expected_delivery_time = order.expected_delivery_time + datetime.timedelta(days=actual_delivery_delay)
4102 chandransh 1957
 
4842 rajveer 1958
        actual_shipping_delay = adjust_delivery_time(order.expected_shipping_time, further_delay)
1959
        order.expected_shipping_time = order.expected_shipping_time + datetime.timedelta(days=actual_shipping_delay)
4102 chandransh 1960
 
3553 chandransh 1961
        session.commit()
4008 mandeep.dh 1962
 
1963
        try:
1964
            transaction_requiring_extra_processing = TransactionRequiringExtraProcessing()
1965
            transaction_requiring_extra_processing.category = 'DELAYED_DELIVERY'
1966
            transaction_requiring_extra_processing.transaction_id = order.transaction_id
1967
            session.commit()
1968
        except Exception as e:
4065 mandeep.dh 1969
            print 'Could not persist transaction id: ' + str(order.transaction_id) + ' for further processing due to: ' + str(e)
4008 mandeep.dh 1970
 
3553 chandransh 1971
        return True
1972
    except:
3994 chandransh 1973
        print sys.exc_info()[0]
3553 chandransh 1974
        return False
3956 chandransh 1975
 
1976
def reconcile_cod_collection(collected_amount_map, xferBy, xferTxnId, xferDate):
1977
    unprocessed_awbs = {}
1978
    for awb, amount in collected_amount_map.iteritems():
1979
        try:
1980
            order = Order.query.filter_by(airwaybill_no=awb).one()
1981
        except NoResultFound:
1982
            unprocessed_awbs[awb] = "No order was found for the given AWB: " + awb
1983
            continue
1984
        except MultipleResultsFound:
1985
            unprocessed_awbs[awb] = "Multiple orders were found for the given AWB:" + awb
1986
            continue
1987
 
1988
        if order.cod_reconciliation_timestamp:
1989
            #This order has been processed already! This may be a re-run. Let's allow other orders to be processed.
1990
            continue
1991
 
1992
        if order.status < OrderStatus.DELIVERY_SUCCESS:
1993
            #Order has not been delivered yet. No way we can receive the payment.
1994
            unprocessed_awbs[awb] = "Payment has been received for order: " + str(order.id) + " before delivery reconciliation"
1995
            continue
1996
 
4252 rajveer 1997
        ##As per ticket #743 if amount difference less than 0.5 we should reconcile
1998
        if abs(amount - order.total_amount) > 0.5:
3956 chandransh 1999
            #Received amount is less than or more than the order amount. Mustn't let the user proceed.
2000
            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)
2001
            continue
2002
 
2003
        try:
2004
            payment_client = PaymentClient().get_client()
2005
            payment_client.partiallyCapturePayment(order.transaction.id, amount, xferBy, xferTxnId, xferDate)
2006
        except Exception:
2007
            unprocessed_awbs[awb] = "We were unable to partially capture payment for order id " + str(order.id) + ", AWB: " + awb
2008
            continue
2009
 
2010
        #Payment has been recorded now. We can update the order peacefully.
2011
        order.cod_reconciliation_timestamp = datetime.datetime.now()
2012
        session.commit()
3469 chandransh 2013
 
3956 chandransh 2014
    return unprocessed_awbs
4008 mandeep.dh 2015
 
2016
def get_transactions_requiring_extra_processing(category):
4065 mandeep.dh 2017
    """
2018
    Returns the list of transaction ids that require some extra processing and
2019
    which belong to a particular category. This is currently used by CRM
2020
    application. If no such transaction ids are present, it returns an empty list.
2021
    """
2022
    query = TransactionRequiringExtraProcessing.query
4008 mandeep.dh 2023
 
4065 mandeep.dh 2024
    if category is not None:
2025
        query = query.filter_by(category = ExtraTransactionProcessingType._VALUES_TO_NAMES.get(category))
4008 mandeep.dh 2026
 
4065 mandeep.dh 2027
    return [a.transaction_id for a in query.all()]
4008 mandeep.dh 2028
 
2029
def mark_transaction_as_processed(transactionId, category):
4065 mandeep.dh 2030
    """
2031
    Marks a particular transaction as processed for a particular cateogory.
2032
    It essentially deletes the transaction id record for a particular
2033
    processing type category (if present) from DB.
2034
    This is currently used by CRM application.
2035
    """
4008 mandeep.dh 2036
    TransactionRequiringExtraProcessing.query.filter_by(transaction_id = transactionId).filter_by(category = ExtraTransactionProcessingType._VALUES_TO_NAMES.get(category)).delete()
2037
    session.commit()
2038
 
4018 chandransh 2039
def get_item_wise_risky_orders_count():
2040
    """
2041
    Returns a map containing the number of risky orders keyed by item id. A risky order
2042
    is defined as one whose shipping date is about to expire.
2043
    """
2044
    item_wise_risky_orders_count = {}
4019 chandransh 2045
    shipping_cutoff_time = (datetime.datetime.now() + datetime.timedelta(days = 1)).replace(hour=PREPAID_SHIPPING_CUTOFF_TIME, minute=0, second=0)
4018 chandransh 2046
    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()
2047
    for order in orders:
2048
        for lineitem in order.lineitems:
2049
            quantity = lineitem.quantity
2050
            if item_wise_risky_orders_count.has_key(lineitem.item_id):
2051
                quantity = quantity + item_wise_risky_orders_count[lineitem.item_id]
2052
 
2053
            item_wise_risky_orders_count[lineitem.item_id] = quantity
2054
    return item_wise_risky_orders_count
2055
 
4324 mandeep.dh 2056
def update_shipment_address(order_id, address_id):
2057
    """
2058
    Updates shipment address of an order. Delivery and shipping date estimates
2059
    etc. are also updated here.
2060
 
2061
    Throws TransactionServiceException in case address change is not
2062
    possible due to certain reasons such as new pincode in address is
2063
    not serviceable etc.
2064
 
2065
    Parameters:
2066
     - orderId
2067
     - addressId
2068
    """
2069
    user_client = UserClient().get_client()
2070
    address     = user_client.getAddressById(address_id)
2071
    order       = get_order(order_id)
2072
 
4630 mandeep.dh 2073
    type = DeliveryType.PREPAID
2074
    if order.cod:
2075
        type = DeliveryType.COD
2076
 
4324 mandeep.dh 2077
    logistics_client = LogisticsClient().get_client()
4630 mandeep.dh 2078
    logistics_info = logistics_client.getLogisticsEstimation(order.lineitems[0].item_id, address.pin, type)
4324 mandeep.dh 2079
 
2080
    # Check for new estimate. Raise exception if new address is not serviceable
2081
    if logistics_info.deliveryTime == -1:
2082
        raise TransactionServiceException(1, 'Location not serviceable')
2083
 
2084
    # COD services are not available everywhere
2085
    if order.cod:
4868 rajveer 2086
        if not logistics_info.codAllowed:
4324 mandeep.dh 2087
            raise TransactionServiceException(2, 'COD service not available')
2088
 
2089
    current_time = datetime.datetime.now()
2090
    logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
2091
    logistics_info.shippingTime = adjust_delivery_time(current_time, logistics_info.shippingTime)
2092
 
2093
    order.customer_name         = address.name
2094
    order.customer_pincode      = address.pin
2095
    order.customer_address1     = address.line1
2096
    order.customer_address2     = address.line2
2097
    order.customer_city         = address.city
2098
    order.customer_state        = address.state
2099
    order.customer_mobilenumber = address.phone
2100
 
2101
    if order.cod:
2102
        order.expected_shipping_time = (current_time + datetime.timedelta(days=logistics_info.shippingTime)).replace(hour=COD_SHIPPING_CUTOFF_TIME, minute=0, second=0)
2103
    else:
2104
        order.expected_shipping_time = (current_time + datetime.timedelta(days=logistics_info.shippingTime)).replace(hour=PREPAID_SHIPPING_CUTOFF_TIME, minute=0, second=0)
2105
 
2106
    order.expected_delivery_time = current_time + datetime.timedelta(days=logistics_info.deliveryTime)
2107
    order.promised_shipping_time = order.expected_shipping_time
2108
    order.promised_delivery_time = order.expected_delivery_time 
2109
 
2110
    session.commit()
2111
 
4247 rajveer 2112
def mark_order_cancellation_request_received(orderId):
2113
    """
2114
    Mark order as cancellation request received. If customer sends request of cancellation of
2115
    a particular order, this method will be called. It will just change status of the order
2116
    depending on its current status. It also records the previous status, so that we can move
2117
    back to that status if cancellation request is denied.
2118
 
2119
    Parameters:
2120
     - orderId
2121
    """
4662 rajveer 2122
    status_transition = {OrderStatus.COD_VERIFICATION_PENDING : OrderStatus.CANCEL_REQUEST_RECEIVED,
4247 rajveer 2123
             OrderStatus.SUBMITTED_FOR_PROCESSING : OrderStatus.CANCEL_REQUEST_RECEIVED,
2124
             OrderStatus.INVENTORY_LOW : OrderStatus.CANCEL_REQUEST_RECEIVED,
4306 rajveer 2125
             OrderStatus.LOW_INV_PO_RAISED : OrderStatus.CANCEL_REQUEST_RECEIVED,
2126
             OrderStatus.LOW_INV_REVERSAL_IN_PROCESS : OrderStatus.CANCEL_REQUEST_RECEIVED,
2127
             OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT : OrderStatus.CANCEL_REQUEST_RECEIVED,
4247 rajveer 2128
             OrderStatus.ACCEPTED : OrderStatus.CANCEL_REQUEST_RECEIVED,
2129
             OrderStatus.BILLED : OrderStatus.CANCEL_REQUEST_RECEIVED,
2130
             OrderStatus.PAYMENT_FLAGGED : OrderStatus.CANCEL_REQUEST_RECEIVED
2131
             }
4662 rajveer 2132
 
2133
    order = get_order(orderId)
4247 rajveer 2134
    if order.status not in status_transition.keys():
2135
        raise TransactionServiceException(114, "This order can't be considered for cancellation")
2136
 
4662 rajveer 2137
 
4247 rajveer 2138
    order.previousStatus = order.status
2139
    order.status = OrderStatus.CANCEL_REQUEST_RECEIVED
2140
    order.statusDescription = "Cancellation request received from user"
2141
    session.commit()
2142
 
4662 rajveer 2143
def mark_order_as_lost_in_transit(orderId):
2144
    """
2145
    Parameters:
2146
     - orderId
2147
    """
2148
    order = get_order(orderId)
4910 phani.kuma 2149
    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 2150
        raise TransactionServiceException(115, "This order can't be marked as lost in transit")
2151
    order.status = OrderStatus.LOST_IN_TRANSIT
2152
    order.statusDescription = "Lost in Transit"
2153
    session.commit()
2154
 
4258 rajveer 2155
def mark_transaction_as_payment_flag_removed(transactionId):
4247 rajveer 2156
    """
4258 rajveer 2157
    If we and/or payment gateway has decided to accept the payment, this method needs to be called.
2158
    Changed transaction and all orders status to payment accepted.
4247 rajveer 2159
 
2160
    Parameters:
4258 rajveer 2161
     - transactionId
4247 rajveer 2162
    """
4258 rajveer 2163
    transaction = get_transaction(transactionId)
2164
    transaction.status = TransactionStatus.AUTHORIZED
2165
    for order in transaction.orders:
2166
        order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
2167
        order.statusDescription = "Submitted to warehouse"
4247 rajveer 2168
    session.commit()
2169
 
4259 anupam.sin 2170
def refund_transaction(transactionId, refundedBy, reason):
2171
    """
2172
    This method is called when a flagged payment is deemed unserviceable and the corresponding orders
2173
    need to be cancelled
2174
 
2175
    Parameters:
2176
     - transactionId
2177
    """
2178
    transaction = get_transaction(transactionId)
2179
    transaction.status = TransactionStatus.FAILED
2180
    for order in transaction.orders:
2181
        refund_order(order.id, refundedBy, reason)
2182
    session.commit()
2183
 
4247 rajveer 2184
def mark_order_cancellation_request_denied(orderId):
2185
    """
4283 anupam.sin 2186
    If we decide to not to cancel order, we will move the order to previous status.
4247 rajveer 2187
 
2188
    Parameters:
2189
     - orderId
2190
    """
2191
    order = get_order(orderId)
2192
    order.status = order.previousStatus
2193
    order.previousStatus = None
2194
    order.statusDescription = "Cancellation request denied"
2195
    session.commit()
2196
 
2197
def mark_order_cancellation_request_confirmed(orderId):
2198
    """
2199
    If we decide to to cancel order, CRM will call this method to move the status of order to
2200
    cancellation request confirmed. After this OM will be able to cancel the order.
2201
 
2202
    Parameters:
2203
     - orderId
2204
    """
2205
    order = get_order(orderId)
2206
    order.status = OrderStatus.CANCEL_REQUEST_CONFIRMED
2207
    order.statusDescription = "Cancellation request confirmed"
2208
    session.commit()
2209
 
4285 rajveer 2210
def accept_orders_for_item_id(itemId, inventory):
2211
    """
2212
    Marks the orders as ACCEPTED for the given itemId and inventory. It also updates the accepted timestamp. If the
2213
    given order is not a COD order, it also captures the payment if the same has not been captured.
2214
 
2215
    Parameters:
2216
     - itemId
2217
     - inventory
2218
    """
4938 rajveer 2219
    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 2220
    for order in orders:
4301 rajveer 2221
        if inventory > 0:
2222
            lineitem = order.lineitems[0]
2223
            if itemId == lineitem.item_id:
2224
                try:
2225
                    accept_order(order.id)
2226
                    inventory = inventory - lineitem.quantity
2227
                except:
2228
                    logging.info("Unable to accept the order")
2229
        else:
2230
            order_outofstock(order.id)
4285 rajveer 2231
    return
2232
 
4607 rajveer 2233
def get_slipped_sipping_date_orders():
4662 rajveer 2234
    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 2235
 
2236
def get_cancelled_orders(cancelDateFrom, cancelDateTo):
2237
    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 2238
 
4369 rajveer 2239
def mark_orders_as_po_raised(vendorId, itemId, quantity, estimate, isReminder):
2240
    if isReminder:
2241
        statuses = tuple([OrderStatus.LOW_INV_PO_RAISED_TIMEOUT, OrderStatus.LOW_INV_REVERSAL_TIMEOUT])
2242
    else:
2243
        statuses = tuple([OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW])
2244
 
2245
    orders = Order.query.filter(Order.status.in_(statuses)).order_by(Order.expected_shipping_time).all()
4303 rajveer 2246
    for order in orders:
2247
        lineitem = order.lineitems[0]
2248
        if quantity >= lineitem.quantity and itemId == lineitem.item_id:
2249
            if estimate > 0:
2250
                add_delay_reason(order.id, DelayReason.OTHERS, estimate)
2251
            order.status = OrderStatus.LOW_INV_PO_RAISED
4362 rajveer 2252
            order.statusDescription = "PO Raised"
4303 rajveer 2253
            quantity = quantity - lineitem.quantity
2254
            store_inventory_action(order, itemId, HotspotAction.PO_RAISED, estimate, lineitem.quantity)
2255
            session.commit()
2256
 
4369 rajveer 2257
def mark_orders_as_reversal_initiated(vendorId, itemId, quantity, estimate, isReminder):
2258
    if isReminder:
2259
        statuses = tuple([OrderStatus.LOW_INV_PO_RAISED_TIMEOUT, OrderStatus.LOW_INV_REVERSAL_TIMEOUT])
2260
    else:
2261
        statuses = tuple([OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW])
2262
    orders = Order.query.filter(Order.status.in_(statuses)).order_by(Order.expected_shipping_time).all()
4303 rajveer 2263
    for order in orders:
2264
        lineitem = order.lineitems[0]
2265
        if quantity >= lineitem.quantity and itemId == lineitem.item_id:
2266
            if estimate > 0:
2267
                add_delay_reason(order.id, DelayReason.OTHERS, estimate)
2268
            order.status = OrderStatus.LOW_INV_REVERSAL_IN_PROCESS
4362 rajveer 2269
            order.statusDescription = "Reversal Initiated"
4303 rajveer 2270
            quantity = quantity - lineitem.quantity
2271
            store_inventory_action(order, itemId, HotspotAction.REVERSAL_INITIATED, estimate, lineitem.quantity)
2272
            session.commit()
2273
 
4369 rajveer 2274
def mark_orders_as_not_available(vendorId, itemId, quantity, estimate, isReminder):
2275
    if isReminder:
2276
        statuses = tuple([OrderStatus.LOW_INV_PO_RAISED_TIMEOUT, OrderStatus.LOW_INV_REVERSAL_TIMEOUT])
2277
    else:
2278
        statuses = tuple([OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW])
2279
 
2280
    orders = Order.query.filter(Order.status.in_(statuses)).order_by(Order.expected_shipping_time).all()
4303 rajveer 2281
    for order in orders:
2282
        lineitem = order.lineitems[0]
2283
        if quantity >= lineitem.quantity and itemId == lineitem.item_id:
2284
            order.status = OrderStatus.LOW_INV_NOT_AVAILABLE_AT_HOTSPOT
4362 rajveer 2285
            order.statusDescription = "Not Available"
4303 rajveer 2286
            quantity = quantity - lineitem.quantity
2287
            store_inventory_action(order, itemId, HotspotAction.NOT_AVAILABLE, estimate, lineitem.quantity)
2288
            session.commit()
2289
 
2290
def store_inventory_action(order, itemId, hotspotAction, estimate, quantity):
4369 rajveer 2291
    orderInv = OrderInventory.get_by(order_id=order.id)
2292
    if not orderInv:
2293
        orderInv = OrderInventory()
2294
        orderInv.order = order
4303 rajveer 2295
    orderInv.hotspotAction = hotspotAction  
2296
    orderInv.estimate = estimate
2297
    orderInv.itemId = itemId
2298
    orderInv.timestamp = datetime.datetime.now()
2299
    orderInv.quantity = quantity
2300
 
4556 mandeep.dh 2301
'''    
4369 rajveer 2302
def mark_orders_as_timeout(vendorId):
2303
    ret_timeouts = {}
2304
    orderInvs = OrderInventory.query.all()
2305
    for orderInv in orderInvs:
2306
        if orderInv.timestamp +  timedelta(days=orderInv.estimate) < datetime.datetime.now():
2307
            if not ret_timeouts.has_key(orderInv.itemId):
2308
                timeout = TimeoutSummary()
2309
                ret_timeouts[orderInv.itemId] = timeout
2310
            else:
2311
                timeout = ret_timeouts.get(orderInv.itemId)
2312
            if orderInv.hotspotAction == HotspotAction.PO_RAISED and orderInv.order.status == OrderStatus.LOW_INV_PO_RAISED:
2313
                if timeout.poRaised:
2314
                    timeout.poRaised += 1
2315
                else:
2316
                    timeout.poRaised = 1
2317
 
2318
                if timeout.poEstimate:
2319
                    timeout.poEstimate += orderInv.estimate
2320
                else:
2321
                    timeout.poEstimate = orderInv.estimate
2322
                orderInv.order.status = OrderStatus.LOW_INV_PO_RAISED_TIMEOUT
2323
                orderInv.order.statusDescription = "PO Raised Timeout"
2324
            elif orderInv.hotspotAction == HotspotAction.REVERSAL_INITIATED and orderInv.order.status == OrderStatus.LOW_INV_REVERSAL_IN_PROCESS:
2325
                if timeout.reversalInitiated:
2326
                    timeout.reversalInitiated += 1
2327
                else:
2328
                    timeout.reversalInitiated = 1
2329
 
2330
                if timeout.reversalEstimate:
2331
                    timeout.reversalEstimate += orderInv.estimate
2332
                else:
2333
                    timeout.reversalEstimate = orderInv.estimate
2334
                orderInv.order.status = OrderStatus.LOW_INV_REVERSAL_TIMEOUT
2335
                orderInv.order.statusDescription = "Reversal Initiated Timeout"
2336
            else:
2337
                orderInv.delete()
2338
    session.commit()
2339
    return ret_timeouts
4556 mandeep.dh 2340
'''
2341
 
2342
 
2343
def mark_orders_as_timeout(vendorId):
2344
    ret_timeouts = {}
2345
    orderInvs = OrderInventory.query.all()
2346
    for orderInv in orderInvs:
2347
        if not ret_timeouts.has_key(orderInv.itemId):
2348
            timeout = TimeoutSummary()
2349
            ret_timeouts[orderInv.itemId] = timeout
2350
        else:
2351
            timeout = ret_timeouts.get(orderInv.itemId)
2352
        if orderInv.hotspotAction == HotspotAction.PO_RAISED and orderInv.order.status == OrderStatus.LOW_INV_PO_RAISED:
2353
            if timeout.poRaised:
2354
                timeout.poRaised += 1
2355
            else:
2356
                timeout.poRaised = 1
2357
 
2358
            if timeout.poEstimate:
2359
                timeout.poEstimate = max(orderInv.estimate, timeout.poEstimate)
2360
            else:
2361
                timeout.poEstimate = orderInv.estimate
2362
        elif orderInv.hotspotAction == HotspotAction.REVERSAL_INITIATED and orderInv.order.status == OrderStatus.LOW_INV_REVERSAL_IN_PROCESS:
2363
            if timeout.reversalInitiated:
2364
                timeout.reversalInitiated += 1
2365
            else:
2366
                timeout.reversalInitiated = 1
2367
 
2368
            if timeout.reversalEstimate:
2369
                timeout.reversalEstimate = max(orderInv.estimate, timeout.reversalEstimate)
2370
            else:
2371
                timeout.reversalEstimate = orderInv.estimate
2372
        orderInv.order.status = OrderStatus.INVENTORY_LOW
2373
        orderInv.order.statusDescription = "Low Inventory"
2374
        orderInv.delete()
2375
    session.commit()
2376
    return ret_timeouts
2377
 
4386 anupam.sin 2378
def get_order_for_awb(awb):
2379
    order = Order.get_by(airwaybill_no=awb)
2380
    if not order:
2381
        raise TransactionServiceException(108, "no such order")
2382
 
2383
    return order
4369 rajveer 2384
 
4910 phani.kuma 2385
def get_orders_for_provider_for_status(provider_id, order_status_list):
2386
    if not provider_id or not order_status_list:
4506 phani.kuma 2387
        raise TransactionServiceException(101, "bad provider id or order status")
4910 phani.kuma 2388
    doa_provider = False
2389
    for order_status in order_status_list:
2390
        if order_status in [OrderStatus.DOA_PICKUP_CONFIRMED, OrderStatus.RET_PICKUP_CONFIRMED]:
2391
            doa_provider = True
2392
    if doa_provider:
2393
        query = Order.query.filter_by(doa_logistics_provider_id = provider_id).filter(Order.status.in_(order_status_list))
4815 phani.kuma 2394
    else:
4910 phani.kuma 2395
        query = Order.query.filter_by(logistics_provider_id = provider_id).filter(Order.status.in_(order_status_list))
4506 phani.kuma 2396
    return query.all()
4386 anupam.sin 2397
 
4600 varun.gupt 2398
def get_billed_orders_for_vendor(vendor_id, billing_date_from, billing_date_to):
5368 mandeep.dh 2399
    query = Order.query.filter(Order.status != OrderStatus.PAYMENT_PENDING)
2400
 
2401
    if vendor_id:
2402
        query = query.filter_by(vendorId = vendor_id)
2403
 
4600 varun.gupt 2404
    if billing_date_from:
2405
        query = query.filter(Order.billing_timestamp >= billing_date_from)
5368 mandeep.dh 2406
 
4600 varun.gupt 2407
    if billing_date_to:
2408
        query = query.filter(Order.billing_timestamp <= billing_date_to)
5368 mandeep.dh 2409
 
4600 varun.gupt 2410
    return query.all()
2411
 
5481 phani.kuma 2412
def get_billed_orders(vendor_id, onlyVendorNotPaid, billing_date_from, billing_date_to):
5386 phani.kuma 2413
    query = Order.query.filter(Order.billing_timestamp != None)
5481 phani.kuma 2414
 
2415
    if onlyVendorNotPaid:
5488 phani.kuma 2416
        query = query.filter_by(vendor_paid = False)
5481 phani.kuma 2417
 
5386 phani.kuma 2418
    if vendor_id != -1:
2419
        query = query.filter_by(vendorId = vendor_id)
2420
 
5481 phani.kuma 2421
    if billing_date_from:
2422
        query = query.filter(Order.billing_timestamp >= billing_date_from)
2423
 
2424
    if billing_date_to:
2425
        query = query.filter(Order.billing_timestamp <= billing_date_to)
2426
 
4885 varun.gupt 2427
    return query.all()
4875 varun.gupt 2428
 
4600 varun.gupt 2429
def save_bluedart_settlements(map_awb_and_amount):
2430
    payment_client = PaymentClient().get_client()
2431
 
2432
    for awb, amount in map_awb_and_amount.iteritems():
2433
        order = Order.get_by(airwaybill_no = awb)
2434
 
2435
        payment = payment_client.getSuccessfulPaymentForTxnId(order.transaction_id)
2436
        settlement = PaymentSettlement()
2437
        settlement.paymentId = payment.paymentId
2438
        settlement.paymentGatewayId = payment.gatewayId
2439
        settlement.netCollection = amount
2440
        session.commit()
2441
 
4905 varun.gupt 2442
def save_payment_settlements(settlementDate, paymentGatewayId, referenceId, serviceTax, otherCharges, netCollection):
5386 phani.kuma 2443
    originalOrderId = None
2444
    if paymentGatewayId == 4:
2445
        cod_order = Order.get_by(id = referenceId)
2446
        if cod_order.originalOrderId:
2447
            originalOrderId = cod_order.originalOrderId
2448
        else:
2449
            originalOrderId = referenceId
4600 varun.gupt 2450
    settlement = PaymentSettlement()
2451
    settlement.settlementDate = settlementDate
2452
    settlement.paymentGatewayId = paymentGatewayId
5386 phani.kuma 2453
    if originalOrderId is not None:
2454
        settlement.originalOrderId = originalOrderId
4905 varun.gupt 2455
    settlement.referenceId = referenceId
4600 varun.gupt 2456
    settlement.serviceTax = serviceTax
2457
    settlement.otherCharges = otherCharges
2458
    settlement.netCollection = netCollection
2459
    session.commit()
2460
 
5386 phani.kuma 2461
def get_settlement_for_Prepaid(reference_id, is_refund = False):
2462
    query = PaymentSettlement.query.filter_by(referenceId = reference_id).filter(PaymentSettlement.paymentGatewayId != 4)
4600 varun.gupt 2463
 
5189 varun.gupt 2464
    if is_refund:
2465
        query = query.filter(PaymentSettlement.netCollection < 0)
2466
    else:
2467
        query = query.filter(PaymentSettlement.netCollection > 0)
2468
 
5386 phani.kuma 2469
    return query.first()
2470
 
2471
def get_settlement_for_Cod(orderId, is_refund = False):
2472
    query = PaymentSettlement.query.filter_by(originalOrderId = orderId)
5382 varun.gupt 2473
 
5386 phani.kuma 2474
    if is_refund:
2475
        query = query.filter(PaymentSettlement.netCollection < 0)
2476
    else:
2477
        query = query.filter(PaymentSettlement.netCollection > 0)
2478
 
5189 varun.gupt 2479
    return query.first()
4600 varun.gupt 2480
 
2481
def save_ebs_settlement_summary(settlement_id, settlement_date, transaction_date_from, transaction_date_to, amount):
5551 phani.kuma 2482
    summary = EBSSettlementSummary.query.filter_by(settlementId = settlement_id).first()
5481 phani.kuma 2483
    if summary is None:
2484
        summary = EBSSettlementSummary()
2485
        summary.settlementId = settlement_id
2486
        summary.settlementDate = settlement_date
2487
        summary.transactionDateFrom = transaction_date_from
2488
        summary.transactionDateTo = transaction_date_to
2489
        summary.amount = amount
2490
        summary.detailsUploaded = False
2491
        session.commit()
4600 varun.gupt 2492
 
2493
def get_ebs_settlement_summaries():
2494
    summaries = EBSSettlementSummary.query.filter_by(detailsUploaded = False).order_by(EBSSettlementSummary.transactionDateFrom).all()
2495
    summary_map = {}
2496
 
2497
    for summary in summaries:
2498
        transactionDateFrom = str(summary.transactionDateFrom.year) + '-' + str(summary.transactionDateFrom.month) + '-' + str(summary.transactionDateFrom.day)
2499
        transactionDateTo = str(summary.transactionDateTo.year) + '-' + str(summary.transactionDateTo.month) + '-' + str(summary.transactionDateTo.day)
2500
 
2501
        summary_map[summary.settlementId] = "%s to %s" %(transactionDateFrom, transactionDateTo)
2502
 
2503
    return summary_map
2504
 
2505
def get_ebs_settlement_date(settlement_id):
2506
    summary = EBSSettlementSummary.get_by(settlementId = settlement_id)
2507
 
2508
    if summary:
2509
        return summary.settlementDate
2510
 
2511
def mark_ebs_settlement_uploaded(settlement_id):
2512
    summary = EBSSettlementSummary.get_by(settlementId = settlement_id)
2513
 
2514
    if summary:
2515
        summary.detailsUploaded = True
2516
        session.commit()
4715 varun.gupt 2517
 
2518
def get_settlements_by_date(settlement_date_from, settlement_date_to, is_refund):
2519
    query = PaymentSettlement.query
4600 varun.gupt 2520
 
4715 varun.gupt 2521
    if settlement_date_from:
2522
        query = query.filter(PaymentSettlement.settlementDate >= settlement_date_from)
2523
 
2524
    if settlement_date_to:
2525
        query = query.filter(PaymentSettlement.settlementDate <= settlement_date_to)
2526
 
4749 varun.gupt 2527
    if is_refund is True:
2528
        query = query.filter(PaymentSettlement.netCollection < 0.0)
2529
    else:
2530
        query = query.filter(PaymentSettlement.netCollection > 0.0)
4715 varun.gupt 2531
 
4749 varun.gupt 2532
    return query.all()
4715 varun.gupt 2533
 
2534
def get_reshipped_order_ids(order_ids):
2535
    reshipped_order_ids = []
2536
    return [order.new_order_id for order in Order.query.filter(Order.new_order_id.in_(order_ids)).all()]
2537
 
4749 varun.gupt 2538
def get_shipping_confirmation_email_body(order):
2539
 
2540
    html = """
2541
<html>
2542
<body>
2543
<div>
2544
    <p>Dear Customer,</p>
2545
    <p>
4885 varun.gupt 2546
        We are pleased to inform that we have shipped the order: $order_id for your product $product_name on $shipping_datetime. 
5139 varun.gupt 2547
        The shipment will be delivered to you via $courier_name Courier Service vide AWB# $awb.
4749 varun.gupt 2548
    </p>
2549
    <p>
2550
        Expected delivery date for your order is $expected_delivery_date. 
2551
        The product can be delivered to you between business hours of 10am to 6pm. 
2552
        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.
2553
    </p>
2554
    <p>
2555
        For scheduling the delivery of your product at some specific timings, we recommend you to contact the helpline for Bluedart/Aramex with your complete AWB#.
2556
    </p>
5139 varun.gupt 2557
    <p>$courier_name: $courier_phone</p>
4749 varun.gupt 2558
    <p>
2559
        Warm Regards,<br />
2560
        Saholic Team
2561
    </p>
4750 varun.gupt 2562
</div>
4749 varun.gupt 2563
</body>
2564
</html>
2565
    """
5139 varun.gupt 2566
    logistics_providers = {1: {'name': 'BlueDart', 'phone': '011-66111234'}, 2: {'name': 'Aramex', 'phone': '0124- 39419900'}}
2567
    provider_name = logistics_providers[order.logistics_provider_id]['name']
2568
    provider_phone = logistics_providers[order.logistics_provider_id]['phone']
2569
 
4749 varun.gupt 2570
    dt = datetime.datetime.strptime(str(order.shipping_timestamp), "%Y-%m-%d %H:%M:%S")
4885 varun.gupt 2571
    shipping_date = dt.strftime("%A, %d %B %Y %I:%M%p")
4749 varun.gupt 2572
    product = "%s %s %s" % (order.lineitems[0].brand, order.lineitems[0].model_name, order.lineitems[0].model_number)
4885 varun.gupt 2573
    new_expected_delivery_timestamp = datetime.datetime.now() + timedelta(adjust_delivery_time(datetime.datetime.now(), (order.promised_delivery_time - order.promised_shipping_time).days))
2574
    new_expected_delivery_date = new_expected_delivery_timestamp.strftime("%A, %d %B %Y")
5139 varun.gupt 2575
    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 2576
    return Template(html).substitute(info)
4749 varun.gupt 2577
 
2578
def enqueue_shipping_confirmation_email(orders):
4915 varun.gupt 2579
    # Calling helper service on production
2580
    helperClient = HelperClient(host_key = "helper_service_server_host_prod").get_client()
5139 varun.gupt 2581
 
4749 varun.gupt 2582
    for order in orders:
2583
        try:
2584
            emailSubject = 'Shipping Details for Order ID: ' + str(order.id)
2585
            emailBody = get_shipping_confirmation_email_body(order)
4885 varun.gupt 2586
            helperClient.saveUserEmailForSending(order.customer_email, None, emailSubject, emailBody, '', 'ShippingConfirmation')
4749 varun.gupt 2587
        except Exception as e:
2588
            print e
2589
 
4915 varun.gupt 2590
def get_order_distribution_by_status(start_date, end_date):
5067 varun.gupt 2591
    query = session.query(Order.status, func.count(Order.id)).group_by(Order.status)
2592
    query = query.filter(Order.created_timestamp >= start_date)
2593
    query = query.filter(Order.created_timestamp <= end_date)
2594
    return query.all()
4915 varun.gupt 2595
 
5067 varun.gupt 2596
def get_order_ids_for_status(status, start_datetime, end_datetime):
2597
    query = Order.query.filter(Order.status == status)
2598
    query = query.filter(Order.created_timestamp >= start_datetime)
2599
    query = query.filter(Order.created_timestamp <= end_datetime)
2600
    return query.all()
2601
 
5099 varun.gupt 2602
def update_orders_as_paid_to_vendor(order_id):
5139 varun.gupt 2603
    paid_order = Order.get_by(id = order_id)
5099 varun.gupt 2604
 
5139 varun.gupt 2605
    if paid_order.originalOrderId is None:
2606
        paid_order.vendor_paid = True
5099 varun.gupt 2607
        session.commit()
5139 varun.gupt 2608
 
2609
        for order in Order.query.filter(Order.originalOrderId == order_id).all():
2610
            order.vendor_paid = True
2611
            session.commit()
2612
    else:
5208 varun.gupt 2613
        original_order_id = paid_order.originalOrderId
5139 varun.gupt 2614
 
5208 varun.gupt 2615
        for order in Order.query.filter(Order.originalOrderId == original_order_id).all():
5139 varun.gupt 2616
            order.vendor_paid = True
2617
            session.commit()
2618
 
2619
        original_order = Order.get_by(id = original_order_id)
2620
        if original_order:  original_order.vendor_paid = True
2621
        session.commit()
5348 anupam.sin 2622
 
2623
def update_COD_agent(agentEmailId, orderId):
2624
    order = Order.get_by(id=orderId)
2625
    if not order:
2626
        raise TransactionServiceException(101, "No order found for the given order id" + str(orderId))
2627
    agent = CodVerificationAgent()
2628
    agent.orderId = orderId
2629
    agent.verificationAgent = agentEmailId
2630
    session.commit()
2631
 
5099 varun.gupt 2632
 
5386 phani.kuma 2633
def update_order_only_as_paid_to_vendor(order_id):
2634
    paid_order = Order.get_by(id = order_id)
2635
    if paid_order is None:
2636
        raise TransactionServiceException(116, "No order found for the given order id")
2637
    paid_order.vendor_paid = True
2638
    session.commit()
2639
 
5208 varun.gupt 2640
def get_refunded_orders_marked_paid():
2641
    orderStatusGroup = OrderStatusGroups()
2642
    return Order.query.filter(Order.vendor_paid == 1).filter(Order.status.in_(orderStatusGroup.refundedOrders)).all()
2643
 
5447 anupam.sin 2644
def get_all_verification_agents(minOrderId, maxOrderId):
2645
    return CodVerificationAgent.query.filter(CodVerificationAgent.orderId >= minOrderId).filter(CodVerificationAgent.orderId <= maxOrderId).all()
2646
 
5527 anupam.sin 2647
def get_all_attributes_for_order_id(orderId):
2648
    return Attribute.query.filter(Attribute.orderId == orderId).all()
2649
 
2650
def set_order_attribute_for_transaction(transactionId, t_attribute):
2651
    for order in Order.query.filter_by(transaction_id = transactionId).all():
2652
        attribute = Attribute()
2653
        attribute.orderId = order.id
2654
        attribute.name = t_attribute.name
2655
        attribute.value = t_attribute.value
2656
        session.commit()
2657
 
5558 mandeep.dh 2658
def accept_order_for_item(itemId, quantity, fulfilmentWarehouseId, billingWarehouseId):
2659
    catalogClient = CatalogClient().get_client()
2660
    inventory = catalogClient.getItemInventoryByItemId(itemId)
2661
    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()
2662
    for order in orders:
2663
        lineitem = order.limeitems[0]
2664
        if lineitem.item_id == itemId and lineitem.quantity <= quantity:
2665
            warehouse = catalogClient.getWarehouse(order.fulfilmentWarehouseId)
2666
            if not warehouse.billingWarehouseId and warehouse.warehouseType == WarehouseType._VALUES_TO_NAMES[WarehouseType.THIRD_PARTY]:
2667
                if inventory.availability.has_key(fulfilmentWarehouseId) and inventory.availability[fulfilmentWarehouseId] > inventory.reserved[fulfilmentWarehouseId]:
2668
                    accept_order(order.id)
2669
                    quantity -= lineitem.quantity
2670
 
766 rajveer 2671
def close_session():
2672
    if session.is_active:
2673
        print "session is active. closing it."
2783 chandransh 2674
        session.close()
3376 rajveer 2675
 
2676
def is_alive():
2677
    try:
2678
        session.query(Transaction.id).limit(1).one()
2679
        return True
2680
    except:
4343 varun.gupt 2681
        return False