Subversion Repositories SmartDukaan

Rev

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