Subversion Repositories SmartDukaan

Rev

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