Subversion Repositories SmartDukaan

Rev

Rev 5778 | Rev 5784 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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