Subversion Repositories SmartDukaan

Rev

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