Subversion Repositories SmartDukaan

Rev

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