Subversion Repositories SmartDukaan

Rev

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

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