Subversion Repositories SmartDukaan

Rev

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