Subversion Repositories SmartDukaan

Rev

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

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