Subversion Repositories SmartDukaan

Rev

Rev 4102 | Rev 4133 | 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
 
7
from datetime import date
8
from elixir import *
3499 mandeep.dh 9
from reportlab.lib.units import inch
2536 chandransh 10
from reportlab.pdfgen.canvas import Canvas
11
from reportlab.rl_config import defaultPageSize
3499 mandeep.dh 12
from shop2020.clients.CatalogClient import CatalogClient
13
from shop2020.clients.HelperClient import HelperClient
14
from shop2020.clients.LogisticsClient import LogisticsClient
2747 chandransh 15
from shop2020.clients.PaymentClient import PaymentClient
3499 mandeep.dh 16
from shop2020.clients.TransactionClient import TransactionClient
17
from shop2020.clients.UserClient import UserClient
18
from shop2020.clients.WarehouseClient import WarehouseClient
19
from shop2020.model.v1 import order
20
from shop2020.model.v1.order.impl.DataService import Transaction, LineItem, \
4008 mandeep.dh 21
    Alerts, Order, BatchNoGenerator, InvoiceIDGenerator, \
22
    TransactionRequiringExtraProcessing
2687 chandransh 23
from shop2020.model.v1.order.impl.model.ReturnOrder import ReturnOrder
3499 mandeep.dh 24
from shop2020.thriftpy.logistics.ttypes import DeliveryType
25
from shop2020.thriftpy.model.v1.catalog.ttypes import BillingType
26
from shop2020.thriftpy.model.v1.order.ttypes import Transaction as T_Transaction, \
4008 mandeep.dh 27
    TransactionServiceException, TransactionStatus, OrderStatus, DelayReason, \
28
    ExtraTransactionProcessingType
3499 mandeep.dh 29
from shop2020.thriftpy.warehouse.ttypes import PurchaseOrder, \
30
    LineItem as POLineItem
31
from shop2020.utils.EmailAttachmentSender import mail, get_attachment_part
855 rajveer 32
from shop2020.utils.Utils import to_py_date, to_java_date
4008 mandeep.dh 33
from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
3499 mandeep.dh 34
from sqlalchemy.sql import func
35
from sqlalchemy.sql.expression import and_, or_, desc, not_, distinct
36
from string import Template
37
from textwrap import dedent
38
import datetime
39
import logging
40
import os
41
import sys
42
import time
4019 chandransh 43
from shop2020.config.client.ConfigClient import ConfigClient
3499 mandeep.dh 44
logging.basicConfig(level=logging.DEBUG)
104 ashish 45
 
3499 mandeep.dh 46
 
4019 chandransh 47
try:
48
    config_client = ConfigClient()
49
    PREPAID_SHIPPING_CUTOFF_TIME = int(config_client.get_property('delivery_cutoff_time'))
50
except Exception as ex:
51
    print "[ERROR] Unexpected config error:", sys.exc_info()[0]
52
    PREPAID_SHIPPING_CUTOFF_TIME = 15
3499 mandeep.dh 53
 
4019 chandransh 54
COD_SHIPPING_CUTOFF_TIME = 12
3499 mandeep.dh 55
 
2819 chandransh 56
PAGE_HEIGHT=defaultPageSize[1]
57
PAGE_WIDTH=defaultPageSize[0]
58
 
3499 mandeep.dh 59
ORDER_STATUS_TO_USER_TRUST_LEVEL_DELTA_DICT = {
60
        OrderStatus.SALES_RET_RESHIPPED     :  3,
61
        OrderStatus.SALES_RETURN_IN_TRANSIT : -5,
62
        OrderStatus.DELIVERY_SUCCESS        :  1,
3578 mandeep.dh 63
        OrderStatus.DOA_CERT_INVALID        : -5
3499 mandeep.dh 64
}
65
 
104 ashish 66
def get_new_transaction():
67
    transaction = Transaction()
68
    transaction.createdOn = datetime.datetime.now()
738 chandransh 69
    transaction.status = TransactionStatus.INIT
104 ashish 70
    transaction.status_message = "New transaction"
483 rajveer 71
    return transaction
72
 
73
def create_order(t_order):
74
    order = Order()
75
    if t_order.warehouse_id:
76
        order.warehouse_id = t_order.warehouse_id
509 rajveer 77
    if t_order.logistics_provider_id:    
483 rajveer 78
        order.logistics_provider_id = t_order.logistics_provider_id
79
        order.airwaybill_no = t_order.airwaybill_no
80
        order.tracking_id = t_order.tracking_id
4009 chandransh 81
    if t_order.expected_shipping_time:
4019 chandransh 82
        order.expected_shipping_time = to_py_date(t_order.expected_shipping_time).replace(hour=PREPAID_SHIPPING_CUTOFF_TIME, minute=0, second=0)
4102 chandransh 83
        order.promised_shipping_time = order.expected_shipping_time
4009 chandransh 84
    if t_order.expected_delivery_time:
483 rajveer 85
        order.expected_delivery_time = to_py_date(t_order.expected_delivery_time)
4102 chandransh 86
        order.promised_delivery_time = order.expected_delivery_time
483 rajveer 87
    if t_order.customer_id:    
88
        order.customer_id = t_order.customer_id
89
        order.customer_name = t_order.customer_name
860 rajveer 90
        order.customer_city = t_order.customer_city
91
        order.customer_state = t_order.customer_state
483 rajveer 92
        order.customer_mobilenumber = t_order.customer_mobilenumber
93
        order.customer_pincode = t_order.customer_pincode
738 chandransh 94
        order.customer_address1 = t_order.customer_address1
95
        order.customer_address2 = t_order.customer_address2
483 rajveer 96
        order.customer_email = t_order.customer_email
97
    #new status and status description to be added    
716 rajveer 98
    order.status = t_order.status  
483 rajveer 99
    order.statusDescription = t_order.statusDescription
100
    order.total_amount = t_order.total_amount
101
    order.total_weight = t_order.total_weight
102
    if t_order.created_timestamp:
103
        order.created_timestamp = to_py_date(t_order.created_timestamp)
104
    else:
685 chandransh 105
        order.created_timestamp = datetime.datetime.now()
483 rajveer 106
    return order
107
 
108
def create_transaction(t_transaction):
109
    t_orders = t_transaction.orders
110
    if not t_orders:
111
        raise TransactionServiceException(101, "Orders missing from the transaction")
112
    transaction = get_new_transaction()
113
    transaction.customer_id = t_transaction.customer_id 
114
    transaction.shopping_cart_id = t_transaction.shoppingCartid
2219 varun.gupt 115
    transaction.coupon_code = t_transaction.coupon_code
2815 vikas 116
    transaction.session_source = t_transaction.sessionSource
117
    transaction.session_start_time = to_py_date(t_transaction.sessionStartTime)
3858 vikas 118
    transaction.first_source = t_transaction.firstSource
119
    transaction.first_source_start_time = to_py_date(t_transaction.firstSourceTime)
483 rajveer 120
 
121
    for t_order in t_orders:
122
        order = create_order(t_order)
123
        order.transaction = transaction 
124
        for line_item in t_order.lineitems:
125
            litem = LineItem()
716 rajveer 126
            litem.item_id = line_item.item_id
963 chandransh 127
            litem.productGroup = line_item.productGroup
483 rajveer 128
            litem.brand = line_item.brand
129
            if line_item.model_number:
130
                litem.model_number = line_item.model_number
131
            if line_item.model_name:    
132
                litem.model_name = line_item.model_name
908 chandransh 133
            if line_item.color:
134
                litem.color = line_item.color
483 rajveer 135
            if line_item.extra_info:
136
                litem.extra_info = line_item.extra_info
137
            litem.quantity = line_item.quantity
138
            litem.unit_price = line_item.unit_price
139
            litem.unit_weight = line_item.unit_weight
140
            litem.total_price = line_item.total_price
141
            litem.total_weight = line_item.total_weight
1262 varun.gupt 142
            litem.transfer_price = line_item.transfer_price
1976 varun.gupt 143
 
483 rajveer 144
            """
145
            if line_item.addedOn:
146
                litem.added_on = to_py_date(line_item.addedOn)
147
            else:
148
                litem.added_on = datetime.datetime.now()
149
            """
150
            litem.order = order
151
    session.commit()
152
    return transaction.id
153
 
154
def get_transaction(transaction_id):
155
    transaction = Transaction.get_by(id=transaction_id)
156
    if not transaction:
157
        raise TransactionServiceException(108, "no such transaction")
158
 
159
    return transaction
160
 
161
def get_transactions_for_customer(customer_id, from_date, to_date, status):
162
    if not customer_id:
163
        raise TransactionServiceException(101, "bad customer id")
164
    query = Transaction.query.filter(Transaction.customer_id == customer_id)
1493 vikas 165
    if status is not None:
483 rajveer 166
        query = query.filter(Transaction.status == status)
167
    if from_date:
168
        query = query.filter(Transaction.createdOn >from_date)
169
    if to_date:
170
        query = query.filter(Transaction.createdOn < to_date)
171
    return query.all()
172
 
173
def get_transactions_for_shopping_cart_id(shopping_cart_id):
174
    transactions = Transaction.query.filter_by(shopping_cart_id=shopping_cart_id).all()
175
    return transactions
176
 
177
def get_transaction_status(transaction_id):
178
    if not transaction_id:
179
        raise TransactionServiceException(101, "bad transaction id")
180
 
181
    transaction = get_transaction(transaction_id)
182
 
183
    return transaction.status
184
 
185
def change_transaction_status(transaction_id, new_status, description):
186
    transaction = get_transaction(transaction_id)
187
    transaction.status = new_status
188
    transaction.status_message = description
690 chandransh 189
    if new_status == TransactionStatus.FAILED:
190
        for order in transaction.orders:
191
            order.status = OrderStatus.PAYMENT_FAILED
2339 chandransh 192
            order.statusDescription = "Payment Failed"
3010 chandransh 193
    elif new_status == TransactionStatus.AUTHORIZED:
690 chandransh 194
        for order in transaction.orders:
195
            order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
1219 chandransh 196
            order.statusDescription = "Submitted to warehouse"
3092 chandransh 197
            order.cod = False
743 rajveer 198
            #After we got payment success, we will set logistics info also 
199
            logistics_client = LogisticsClient().get_client()
200
            #FIXME line item is only one now. If multiple will come, need to fix.
871 chandransh 201
            item_id = order.lineitems[0].item_id
3044 chandransh 202
            logistics_info = logistics_client.getLogisticsInfo(order.customer_pincode, item_id, DeliveryType.PREPAID)
743 rajveer 203
 
1730 ankur.sing 204
            current_time = datetime.datetime.now()
205
            logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
4009 chandransh 206
            logistics_info.shippingTime = adjust_delivery_time(current_time, logistics_info.shippingTime)
1730 ankur.sing 207
 
743 rajveer 208
            order.warehouse_id = logistics_info.warehouseId
209
            order.logistics_provider_id = logistics_info.providerId
210
            order.airwaybill_no = logistics_info.airway_billno
211
            order.tracking_id = order.airwaybill_no
4019 chandransh 212
            order.expected_shipping_time = (current_time + datetime.timedelta(days=logistics_info.shippingTime)).replace(hour=PREPAID_SHIPPING_CUTOFF_TIME, minute=0, second=0)
4102 chandransh 213
            order.promised_shipping_time = order.expected_shipping_time
1730 ankur.sing 214
            order.expected_delivery_time = current_time + datetime.timedelta(days=logistics_info.deliveryTime)
3986 chandransh 215
            order.promised_delivery_time = order.expected_delivery_time 
871 chandransh 216
 
3133 rajveer 217
            catalog_client = CatalogClient().get_client()
871 chandransh 218
            catalog_client.reserveItemInWarehouse(item_id, logistics_info.warehouseId, order.lineitems[0].quantity)
1351 varun.gupt 219
 
1341 chandransh 220
            item_pricing = catalog_client.getItemPricing(item_id, order.warehouse_id)
221
            order.lineitems[0].transfer_price = item_pricing.transferPrice
3064 chandransh 222
    elif new_status == TransactionStatus.COD_IN_PROCESS:
223
        for order in transaction.orders:
224
            order.status = OrderStatus.INIT
225
            order.statusDescription = "Verification Pending"
226
            order.cod = True
227
            #After we got payment success, we will set logistics info also 
228
            logistics_client = LogisticsClient().get_client()
229
            #FIXME line item is only one now. If multiple will come, need to fix.
230
            item_id = order.lineitems[0].item_id
231
            logistics_info = logistics_client.getLogisticsInfo(order.customer_pincode, item_id, DeliveryType.COD)
232
 
233
            current_time = datetime.datetime.now()
234
            logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
4009 chandransh 235
            logistics_info.shippingTime = adjust_delivery_time(current_time, logistics_info.shippingTime)
3064 chandransh 236
 
237
            order.warehouse_id = logistics_info.warehouseId
238
            order.logistics_provider_id = logistics_info.providerId
239
            order.airwaybill_no = logistics_info.airway_billno
240
            order.tracking_id = order.airwaybill_no
4019 chandransh 241
            order.expected_shipping_time = (current_time + datetime.timedelta(days=logistics_info.shippingTime)).replace(hour=COD_SHIPPING_CUTOFF_TIME, minute=0, second=0)
4102 chandransh 242
            order.promised_shipping_time = order.expected_shipping_time
3064 chandransh 243
            order.expected_delivery_time = current_time + datetime.timedelta(days=logistics_info.deliveryTime)
3986 chandransh 244
            order.promised_delivery_time = order.expected_delivery_time
3064 chandransh 245
 
3133 rajveer 246
            catalog_client = CatalogClient().get_client()
3064 chandransh 247
            catalog_client.reserveItemInWarehouse(item_id, logistics_info.warehouseId, order.lineitems[0].quantity)
248
 
249
            item_pricing = catalog_client.getItemPricing(item_id, order.warehouse_id)
250
            order.lineitems[0].transfer_price = item_pricing.transferPrice        
3499 mandeep.dh 251
 
483 rajveer 252
    session.commit()
3499 mandeep.dh 253
 
3530 mandeep.dh 254
    try:
255
        if new_status == TransactionStatus.COD_IN_PROCESS:
4008 mandeep.dh 256
            transaction_requiring_extra_processing = TransactionRequiringExtraProcessing()
257
            transaction_requiring_extra_processing.category = 'COD_VERIFICATION'
258
            transaction_requiring_extra_processing.transaction_id = transaction_id
259
            session.commit()
3530 mandeep.dh 260
    except Exception as e:
4065 mandeep.dh 261
        print "Error inserting transaction Id: " + str(transaction_id) + " due to " + str(e)
3499 mandeep.dh 262
 
483 rajveer 263
    return True
264
 
3994 chandransh 265
def __get_holidays(start_time=0L, to_time=-1L):
266
    '''
267
    Get the list of all public holidays since start time including the
268
    day of start time if it's a holiday
269
    '''
270
    midnightTime = start_time.replace(hour=0, minute=0, second=0, microsecond=0)
1730 ankur.sing 271
    fromDate = to_java_date(midnightTime)
272
    logistics_client = LogisticsClient().get_client()
3994 chandransh 273
    #TODO: This list should be cached after the first call.
274
    #Calling logistics server is also unnecessary.
275
    holidays = logistics_client.getHolidays(fromDate, to_time)
276
    holidays = [to_py_date(holiday).date() for holiday in holidays]
277
    return holidays
278
 
279
 
280
def adjust_delivery_time(start_time, delivery_days):
281
    '''
282
    Returns the actual no. of days which will pass while 'delivery_days'
283
    no. of business days will pass since 'order_time'. 
284
    '''
285
    start_date = start_time.date()
286
    end_date = start_date + datetime.timedelta(days = delivery_days)
287
    holidays = __get_holidays(start_time)
1730 ankur.sing 288
 
3994 chandransh 289
    while start_date <= end_date:
290
        if start_date.weekday() == 6 or start_date in holidays:
1730 ankur.sing 291
            delivery_days = delivery_days + 1
3994 chandransh 292
            end_date = end_date + datetime.timedelta(days = 1)
4088 chandransh 293
        start_date = start_date + datetime.timedelta(days = 1)
3994 chandransh 294
 
1730 ankur.sing 295
    return delivery_days
296
 
1398 varun.gupt 297
def enqueue_transaction_info_email(transaction_id):
1262 varun.gupt 298
    transaction = get_transaction(transaction_id)
299
 
300
    html_header = """
301
<html>
302
<body>
303
<div>
304
    <p>
305
        Hello,<br /><br />
1742 rajveer 306
        Thanks for placing order with us. Following are the details of your order:
1262 varun.gupt 307
    </p>
308
    <div>
309
        Order Date: $order_date
1569 varun.gupt 310
    </div>
1262 varun.gupt 311
    <div>
312
        <table>
1569 varun.gupt 313
        <tr><td colspan="5"><hr /></td></tr>
314
        <tr><td colspan="5" align="left"><b>Order Details</b></td></tr>
315
        <tr><td colspan="5"><hr /></td></tr>
1262 varun.gupt 316
        <tr>
2050 varun.gupt 317
            <th width="100">Order No.</th>
318
            <th>Product</th>
319
            <th width="100">Quantity</th>
320
            <th width="100">Unit Price</th>
321
            <th width="100">Amount</th>
1262 varun.gupt 322
        </tr>
323
    """
1398 varun.gupt 324
    user_email = ""
1262 varun.gupt 325
    total_amount = 0.0
326
    html_table = ""
1569 varun.gupt 327
    order_date = datetime.datetime.now()
1262 varun.gupt 328
 
329
    for order in transaction.orders:
330
        order_date = order.created_timestamp
1398 varun.gupt 331
        user_email = order.customer_email
1569 varun.gupt 332
        html_tr = "<tr><td align='center'>" + str(order.id) + "</td>"
1262 varun.gupt 333
 
334
        for lineitem in order.lineitems:
2050 varun.gupt 335
            lineitem_total_price = round(lineitem.total_price, 2)
336
 
1276 chandransh 337
            html_tr += "<td>" + str(lineitem) + "</td>"
2050 varun.gupt 338
            html_tr += "<td align='center'>" + ("%.0f" % lineitem.quantity) + "</td>"
339
            html_tr += "<td align='center'> Rs. " + ("%.2f" % lineitem.unit_price) + "</td>"
340
            html_tr += "<td align='center'> Rs. " + ("%.2f" % lineitem_total_price) + "</td></tr>"
341
            total_amount += lineitem_total_price
1262 varun.gupt 342
            html_table += html_tr
2050 varun.gupt 343
 
1262 varun.gupt 344
    html_footer = """
345
        <tr><td colspan=5>&nbsp;</td></tr>
1565 varun.gupt 346
        <tr><td colspan=5><hr /></td></tr>
1262 varun.gupt 347
        <tr>
348
            <td colspan=4>Total Amount</td>
2050 varun.gupt 349
            <td> Rs. $total_amount</td>
1262 varun.gupt 350
        </tr>
1569 varun.gupt 351
        <tr><td colspan=5><hr /></td></tr>
1262 varun.gupt 352
        </table>
1569 varun.gupt 353
    </div>
1262 varun.gupt 354
    <p>
355
        Best Wishes,<br />
356
        Saholic Team
357
    </p>
358
</div>
359
</body>
360
</html>
361
    """
1398 varun.gupt 362
 
1569 varun.gupt 363
    dt = datetime.datetime.strptime(str(order_date), "%Y-%m-%d %H:%M:%S")
1565 varun.gupt 364
    formated_order_date = dt.strftime("%A, %d. %B %Y %I:%M%p")
365
 
1262 varun.gupt 366
    email_header = Template(html_header).substitute(dict(order_date = formated_order_date))
2050 varun.gupt 367
    email_footer = Template(html_footer).substitute(dict(total_amount = "%.2f" % total_amount))
1262 varun.gupt 368
 
1351 varun.gupt 369
    try:
370
        helper_client = HelperClient().get_client()
1398 varun.gupt 371
        helper_client.saveUserEmailForSending(user_email, "", "Saholic - Order Details", email_header + html_table + email_footer, str(transaction_id), "TransactionInfo")
1351 varun.gupt 372
        return True
373
    except Exception as e:
374
        print e
375
        return False
1262 varun.gupt 376
 
483 rajveer 377
def get_order(order_id):
378
    order = Order.get_by(id=order_id)
379
    if not order:
380
        raise TransactionServiceException(108, "no such order")
381
 
382
    return order
383
 
3014 chandransh 384
def get_orders_for_customer(customer_id, from_date, to_date, statuses):
483 rajveer 385
    if not customer_id:
386
        raise TransactionServiceException(101, "bad customer id")
387
    query = Order.query.filter(Order.customer_id == customer_id)
3014 chandransh 388
    if statuses:
389
        query = query.filter(Order.status.in_(tuple(statuses)))
483 rajveer 390
    if from_date:
391
        query = query.filter(Order.created_timestamp >from_date)
392
    if to_date:
393
        query = query.filter(Order.created_timestamp < to_date)
394
    return query.all()
395
 
1528 ankur.sing 396
def get_order_for_customer(order_id, customer_id):
397
    if not customer_id:
398
        raise TransactionServiceException(101, "bad customer id")
399
    order = get_order(order_id)
400
    if order.customer_id != customer_id:
401
        raise TransactionServiceException(108, "order: " + str(order_id) + " does not belong to customer: " + str(customer_id))
402
    return order
403
 
483 rajveer 404
def get_all_orders(status, from_date, to_date, warehouse_id):
405
    if not warehouse_id:
406
        raise TransactionServiceException(101, "bad warehouse id")
407
    query = Order.query.filter(Order.warehouse_id == warehouse_id)
408
    if status:
409
        query = query.filter(Order.status == status)
410
    if from_date:
411
        query = query.filter(Order.created_timestamp >from_date)
412
    if to_date:
413
        query = query.filter(Order.created_timestamp < to_date)
414
    return query.all()
415
 
1382 varun.gupt 416
def get_returnable_orders_for_customer(customer_id, limit = None):
417
    if not customer_id:
418
        raise TransactionServiceException(101, "bad customer id")
419
 
420
    query = Order.query.filter(Order.customer_id == customer_id)
421
    query = query.filter(Order.status != OrderStatus.PAYMENT_FAILED)
422
    query = query.filter(Order.status != OrderStatus.REJECTED)
423
    query = query.filter(Order.status > OrderStatus.SHIPPED_FROM_WH)
424
    query = query.filter(or_(Order.status < OrderStatus.DELIVERY_SUCCESS, Order.delivery_timestamp < datetime.datetime.now() + datetime.timedelta(hours = 48)))
425
    orders = query.all()
426
    order_ids = [order.id for order in orders]
427
    return order_ids
428
 
429
def get_cancellable_orders_for_customer(customer_id, limit = None):
430
    if not customer_id:
431
        raise TransactionServiceException(101, "bad customer id")
432
 
433
    query = Order.query.filter(Order.customer_id == customer_id)
434
    query = query.filter(Order.status != OrderStatus.REJECTED)
1483 varun.gupt 435
    query = query.filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING)
1382 varun.gupt 436
    query = query.filter(Order.status < OrderStatus.BILLED)
437
    orders = query.all()
438
    return [order.id for order in orders]
439
 
995 varun.gupt 440
def get_orders_by_billing_date(status, start_billing_date, end_billing_date, warehouse_id):
441
    if not warehouse_id:
442
        raise TransactionServiceException(101, "bad warehouse id")
443
 
444
    query = Order.query.filter(Order.warehouse_id == warehouse_id)
445
 
446
    if status:
447
        query = query.filter(Order.status == status)
448
 
449
    if start_billing_date:
450
        query = query.filter(Order.billing_timestamp >= start_billing_date)
451
 
452
    if end_billing_date:
453
        query = query.filter(Order.billing_timestamp <= end_billing_date)
454
 
455
    return query.all()
456
 
3451 chandransh 457
def get_orders_by_shipping_date(from_shipping_date, to_shipping_date, provider_id, warehouse_id, cod):
458
    query = Order.query.filter(Order.cod == cod)
3427 chandransh 459
 
460
    if warehouse_id and warehouse_id != -1:
461
        query = query.filter(Order.warehouse_id == warehouse_id)
462
 
463
    if provider_id and provider_id != -1:
464
        query = query.filter(Order.logistics_provider_id == provider_id)
465
 
466
    if from_shipping_date:
467
        query = query.filter(Order.shipping_timestamp >= from_shipping_date)
468
 
469
    if to_shipping_date:
470
        query = query.filter(Order.shipping_timestamp <= to_shipping_date)
471
 
472
    query = query.order_by(Order.airwaybill_no)
473
 
474
    return query.all()
475
 
1528 ankur.sing 476
def get_orders_for_transaction(transaction_id, customer_id):
477
    orders = Order.query.filter_by(transaction_id=transaction_id, customer_id=customer_id).all()
478
 
1208 chandransh 479
    if not orders:
480
        raise TransactionServiceException(101, "No order for the transaction")
481
    return orders
482
 
1405 ankur.sing 483
def get_undelivered_orders(provider_id, warehouse_id):
484
    query = Order.query
485
    if provider_id != -1:
486
        query = query.filter_by(Order.logistics_provider_id == provider_id)
487
    if warehouse_id != -1:
488
        query = query.filter(Order.warehouse_id == warehouse_id)
489
    query = query.filter(and_(Order.status != OrderStatus.DELIVERY_SUCCESS, Order.status != OrderStatus.FAILED, \
490
                              Order.status > OrderStatus.SHIPPED_FROM_WH))
1479 ankur.sing 491
    #Get last midnight time instead of current time as courier company would have sent the 
492
    #delivery records updated at least till midnight and not by the current time.
493
    time_format = "%Y-%m-%d %H:%M:%S.%f"
494
    t = time.strptime(str(datetime.datetime.now()), time_format)
495
    midnightTime = datetime.datetime(*t[:3])
496
    query = query.filter(Order.expected_delivery_time < midnightTime)
1405 ankur.sing 497
    orders = query.all()
498
    return orders
499
 
1208 chandransh 500
def get_line_items_for_order(order_id):
501
    query = LineItem.query.filter(LineItem.order_id == order_id)
502
    return query.all()
503
 
483 rajveer 504
def change_order_status(self, orderId, status, description):
505
    order = get_order(orderId)
506
    order.status = status
507
    order.statusDescription = description
508
    session.commit()
3578 mandeep.dh 509
    update_trust_level(order)
510
    return True
3499 mandeep.dh 511
 
3578 mandeep.dh 512
def update_trust_level(order):
3530 mandeep.dh 513
    try:
3578 mandeep.dh 514
        trust_level_delta = 0
515
        if order.cod == True:
516
            trust_level_delta = ORDER_STATUS_TO_USER_TRUST_LEVEL_DELTA_DICT.get(order.status, 0)
517
 
3530 mandeep.dh 518
        if (trust_level_delta != 0):
519
            user_client = UserClient().get_client()
520
            user_client.increaseTrustLevel(order.customer_id, trust_level_delta)
521
    except Exception as e:
522
        print e
3499 mandeep.dh 523
 
483 rajveer 524
    return True
3064 chandransh 525
 
526
def verify_order(self, orderId):
527
    logging.info("Verifying order no: " + str(orderId))
528
    order = get_order(orderId)
529
    if order.status == OrderStatus.INIT:
530
        order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
531
        order.statusDescription = "Submitted for processing"
532
        order.verification_timestamp = datetime.datetime.now()
533
        session.commit()
534
        logging.info("Successfully verified order no: " + str(orderId))
535
        return True
536
    else:
537
        logging.warning("Verify called for order no." + str(orderId) +" which is not in verification pending state");
538
        return False
539
 
921 rajveer 540
def accept_order(self, orderId):
3064 chandransh 541
    logging.info("Accepting order no: " + str(orderId))
921 rajveer 542
    order = get_order(orderId)
3036 chandransh 543
    if order.status in [OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW]:
3064 chandransh 544
        if not order.cod:
545
            if order.transaction.status == TransactionStatus.AUTHORIZED:
546
                __capture_txn(order.transaction.id)
3010 chandransh 547
        order.status = OrderStatus.ACCEPTED
548
        order.statusDescription = "Order Accepted"
549
        order.accepted_timestamp = datetime.datetime.now()
550
        session.commit()
3064 chandransh 551
        logging.info("Successfully accepted the order no.:" + str(orderId))
3010 chandransh 552
        return True
553
    else:
3064 chandransh 554
        logging.warning("Accept called for the unacceptable order: " + str(orderId))
3010 chandransh 555
        return False
921 rajveer 556
 
3010 chandransh 557
def __capture_txn(txnId):
558
    logging.info("Capturing payment for merchant txn:" + str(txnId))
559
    payment_client = PaymentClient().get_client()
560
    capture_result = payment_client.capturePayment(txnId)
561
    if capture_result:
3064 chandransh 562
        logging.info("Successfully captured payment for merchant txn:" + str(txnId))
563
        change_transaction_status(txnId, TransactionStatus.IN_PROCESS, "Payment received")
3010 chandransh 564
    else:
565
        raise TransactionServiceException(115, "Payment capture failed.")
566
 
921 rajveer 567
def bill_order(self, orderId):
568
    order = get_order(orderId)
569
    order.status = OrderStatus.BILLED
570
    order.statusDescription = "Order Billed"
571
    order.billing_timestamp = datetime.datetime.now()
572
    session.commit()
1208 chandransh 573
    return True
921 rajveer 574
 
1149 chandransh 575
def add_billing_details(orderId, invoice_number, billed_by):
494 rajveer 576
    order = Order.get_by(id=orderId)
577
    if not order:
2783 chandransh 578
        raise TransactionServiceException(101, "No order found for the given order id:" + str(orderId))
494 rajveer 579
    order.invoice_number = invoice_number
580
    order.billed_by = billed_by
581
    session.commit()
582
    return True
759 chandransh 583
 
2842 chandransh 584
def add_jacket_number(self, orderId, jacket_number, imei_number, item_number, billed_by, billing_type):
2783 chandransh 585
    if jacket_number is None or jacket_number <= 0:
586
        raise TransactionServiceException(110, "Invalid jacket number")
587
 
588
    if item_number is None or item_number.strip() == "":
589
        raise TransactionServiceException(110, "Invalid item number")
590
 
591
    if billed_by is None or billed_by.strip() == "":
592
        raise TransactionServiceException(110, "Invalid Biller")
593
 
1149 chandransh 594
    order = Order.get_by(id=orderId)
595
    if not order:
2783 chandransh 596
        raise TransactionServiceException(101, "No order found for the given order id" + str(orderId))
597
 
598
    order.jacket_number = jacket_number
2842 chandransh 599
    if billing_type == BillingType.OURS:
600
        order.invoice_number = get_next_invoice_number()
601
        order.billed_by = billed_by
602
        order.status = OrderStatus.BILLED
603
        order.statusDescription = "Order Billed"
604
        order.billing_timestamp = datetime.datetime.now()
2783 chandransh 605
 
2842 chandransh 606
        lineitem = order.lineitems[0]
607
        if lineitem.productGroup == "Handsets" and imei_number <= 0:
608
            raise TransactionServiceException(110, "No IMEI number supplied for a handset.")
609
        lineitem.item_number = item_number
610
        if imei_number > 0:
611
            lineitem.imei_number = str(imei_number)
2783 chandransh 612
 
1149 chandransh 613
    session.commit()
614
    return True
615
 
1220 chandransh 616
def batch_orders(warehouseId):
617
    if not warehouseId:
618
        raise TransactionServiceException(101, "bad warehouse id")
1225 chandransh 619
 
620
    batchno_generator = BatchNoGenerator()
621
    session.commit()
1220 chandransh 622
    query = Order.query.filter_by(warehouse_id=warehouseId)
623
    query = query.filter_by(status=OrderStatus.SUBMITTED_FOR_PROCESSING)
624
    query = query.order_by(Order.created_timestamp)
625
    pending_orders = query.all()
1225 chandransh 626
 
1220 chandransh 627
    serial_no = 1
628
    for order in pending_orders:
1276 chandransh 629
        order.batchNo = batchno_generator.id
1220 chandransh 630
        order.serialNo = serial_no
631
        serial_no += 1
632
    session.commit() 
633
    pending_orders = query.all()
634
    return pending_orders
635
 
636
def order_outofstock(orderId):
1911 chandransh 637
    '''
638
    Mark order as out of stock
639
    '''
1220 chandransh 640
    order = get_order(orderId)
641
    order.status = OrderStatus.INVENTORY_LOW
642
    order.statusDescription = "Low Inventory"
643
    order.outofstock_timestamp = datetime.datetime.now()
644
    session.commit()
645
    return True
646
 
3064 chandransh 647
def mark_orders_as_manifested(warehouse_id, provider_id, cod):
759 chandransh 648
    try:
986 chandransh 649
        current_timestamp = datetime.datetime.now()
3064 chandransh 650
        orders = Order.query.filter_by(warehouse_id = warehouse_id, logistics_provider_id = provider_id, status = OrderStatus.BILLED, cod = cod).all()
759 chandransh 651
        for order in orders:
652
            order.status = OrderStatus.SHIPPED_FROM_WH
987 chandransh 653
            order.statusDescription = "Order shipped from warehouse"
986 chandransh 654
            order.shipping_timestamp = current_timestamp
759 chandransh 655
        session.commit()
656
        return True
657
    except:
658
        return False
1113 chandransh 659
 
660
def mark_orders_as_picked_up(provider_id, pickup_details):
661
    for awb, pickup_timestamp in pickup_details.iteritems():
1135 chandransh 662
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
2684 chandransh 663
        if order == None or order.status != OrderStatus.SHIPPED_FROM_WH:
2220 chandransh 664
            #raise TransactionServiceException(102, "No order found for the awb: " + awb)
665
            continue
1113 chandransh 666
        order.status = OrderStatus.SHIPPED_TO_LOGST
667
        order.statusDescription = "Order picked up by Courier Company"
1246 chandransh 668
        order.pickup_timestamp = pickup_timestamp
1113 chandransh 669
    session.commit()
1217 chandransh 670
 
1132 chandransh 671
    current_time = datetime.datetime.now()
672
    to_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
1246 chandransh 673
    from_datetime = to_datetime - datetime.timedelta(2)
1132 chandransh 674
    orders_not_picked_up = Order.query.filter_by(logistics_provider_id = provider_id).filter_by(status=OrderStatus.SHIPPED_FROM_WH).filter(Order.shipping_timestamp >= from_datetime).filter(Order.shipping_timestamp <= to_datetime).all()
1113 chandransh 675
    return orders_not_picked_up
676
 
1132 chandransh 677
def mark_orders_as_delivered(provider_id, delivered_orders):
678
    for awb, detail in delivered_orders.iteritems():
1135 chandransh 679
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
2684 chandransh 680
        if order == None or order.status not in [OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST]:
1911 chandransh 681
            continue
682
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
1132 chandransh 683
        order.status = OrderStatus.DELIVERY_SUCCESS
684
        order.statusDescription = "Order delivered"
685
        order.delivery_timestamp, order.receiver = detail.split('|')
3578 mandeep.dh 686
        update_trust_level(order)
1132 chandransh 687
    session.commit()
688
 
1135 chandransh 689
def mark_orders_as_failed(provider_id, returned_orders):
690
    for awb, detail in returned_orders.iteritems():
691
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
2684 chandransh 692
        if order == None or order.status not in [OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST]:
693
            continue
694
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
695
        order.status = OrderStatus.SALES_RETURN_IN_TRANSIT
1135 chandransh 696
        order.delivery_timestamp, reason = detail.split('|')
697
        order.statusDescription = "Order Returned to Origin:" + reason
3578 mandeep.dh 698
        update_trust_level(order)
1911 chandransh 699
    session.commit()
1135 chandransh 700
 
1246 chandransh 701
def update_non_delivery_reason(provider_id, undelivered_orders):
702
    for awb, reason in undelivered_orders.iteritems():
703
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
704
        if order == None:
2684 chandransh 705
            continue
706
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
1246 chandransh 707
        order.statusDescription = reason
708
    session.commit()
709
 
483 rajveer 710
def get_alerts(order_id, all):
711
    query = Alerts.query.filter_by(order_id=order_id)
712
    if not all:
713
        query = query.filter_by(valid=True)
714
    return query.all()
715
 
716
def set_alert(order_id, unset, type, comment):
717
    #get existing alert
718
    if unset:
719
        query = Alerts.query.filter_by(order_id=order_id)
720
        query = query.filter_by(type=type)
721
        alerts = query.all()
722
        for alert in alerts:
723
            if alert.valid:
724
                alert.valid = False
725
                alert.comment = comment
726
                alert.time_unset = datetime.datetime.now()
727
    else:
728
        alert = Alerts()
729
        alert.order_id = order_id
730
        alert.valid = True
731
        alert.type = type
732
        alert.comment = comment
733
        alert.time_set = datetime.datetime.now()
766 rajveer 734
    session.commit()    
735
 
1596 ankur.sing 736
def get_valid_order_count():
2851 chandransh 737
    '''
738
    Returns the number of orders which we processed. The reshipped orders are not
739
    counted since there'll always be a new compensating order present.
740
    '''
3216 chandransh 741
    return Order.query.filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING).filter(not_(Order.status.in_((OrderStatus.SALES_RET_RESHIPPED, OrderStatus.DOA_INVALID_RESHIPPED, OrderStatus.DOA_RESHIPPED, OrderStatus.CANCELED)))).count()
1596 ankur.sing 742
 
1627 ankur.sing 743
def get_cust_count_with_successful_txn():
2851 chandransh 744
    '''
745
    Returns the number of distinct customers who have done successful transactions.
746
    It uses the sqlalchemy func module to construct an efficient query.
747
    '''
748
    return session.query(func.count(distinct(Order.customer_id))).filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING).scalar()
1627 ankur.sing 749
 
1730 ankur.sing 750
def get_valid_orders_amount_range():
2851 chandransh 751
    '''
752
    Returns a list containing the minimum and maximum amount across all
753
    orders placed with us. No need to consider reshippped orders for min/max
754
    amount of orders.
755
    '''
756
    return session.query(func.min(Order.total_amount), func.max(Order.total_amount)).filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING).one()
1627 ankur.sing 757
 
1886 ankur.sing 758
def get_valid_orders(limit):
2851 chandransh 759
    '''
760
    Returns the last limit number of valid orders placed with us. Ignored the
761
    limit if it's passed as 0. Raises an excpetion if the supplied limit is 
762
    less than 0. 
763
    '''
764
    if limit < 0:
765
        raise TransactionServiceException(101, "Invalid argument limit " + limit)
3072 chandransh 766
    query = Order.query.filter(Order.status >= OrderStatus.INIT)
1886 ankur.sing 767
    query = query.order_by(desc(Order.created_timestamp))
2851 chandransh 768
    if limit != 0:
1886 ankur.sing 769
        query = query.limit(limit)
770
    return query.all()
771
 
2783 chandransh 772
def get_next_invoice_number():
773
    entity_id = InvoiceIDGenerator.query.with_lockmode("update").one()
774
    invoice_number = entity_id.id + 1
775
    entity_id.id = invoice_number
776
    session.commit()
777
    return invoice_number
778
 
2536 chandransh 779
def toggle_doa_flag(order_id):
780
    order = get_order(order_id)
781
    if(order.doaFlag):
782
        order.doaFlag = False
783
    else:
784
        order.doaFlag = True
785
    session.commit()
786
    return order.doaFlag
787
 
788
def request_pickup_number(order_id):
789
    order = get_order(order_id)
790
    if order.status != OrderStatus.DELIVERY_SUCCESS and order.status != OrderStatus.DOA_PICKUP_REQUESTED:
791
        return False
792
    from_user = 'cnc.center@shop2020.in'
793
    from_pwd = '5h0p2o2o'
794
 
795
    subject = "Pickup request"
796
    try:
3133 rajveer 797
        catalog_client = CatalogClient().get_client()
2536 chandransh 798
        warehouse = catalog_client.getWarehouse(order.warehouse_id)
799
 
800
        logistics_client = LogisticsClient().get_client()
801
        provider = logistics_client.getProvider(order.logistics_provider_id)
3051 chandransh 802
        to_addr = provider.details[DeliveryType.PREPAID].email
2536 chandransh 803
        raw_message = '''
804
        Dear Sir/Madam,
805
 
2559 chandransh 806
        Kindly arrange a pickup today from %(customer_city)s. Pickup and delivery addresses are mentioned below.
2536 chandransh 807
 
808
        Pickup CODE: %(provider_code)s
809
        Total Weight: %(order_weight)s kg
810
 
2559 chandransh 811
        Pickup Address:
2536 chandransh 812
 
813
        %(customer_address)s
814
 
815
        Delivery Address:
816
 
817
        %(warehouse_executive)s
818
        %(warehouse_address)s
819
        PIN %(warehouse_pin)s
820
        Phone: %(warehouse_phone)s
821
 
822
        Thanks and Regards
823
        Anand Sinha
824
        '''
2559 chandransh 825
        message = dedent(raw_message) % { 'customer_city' : order.customer_city,
3051 chandransh 826
                                          'provider_code' : provider.details[DeliveryType.PREPAID].accountNo,
2536 chandransh 827
                                          'order_weight' : str(order.total_weight),
828
                                          'customer_address' : __get_order_address(order),
829
                                          'warehouse_executive' : 'Parmod Kumar',
830
                                          'warehouse_address' : warehouse.location,
831
                                          'warehouse_pin' : warehouse.pincode,
832
                                          'warehouse_phone': '9971573026'}
3527 chandransh 833
        mail(from_user, from_pwd, [to_addr], subject, message)
2536 chandransh 834
        order.status = OrderStatus.DOA_PICKUP_REQUESTED
835
        order.statusDescription = "Pick up requested for DOA"
836
        session.commit()
837
        return True
838
    except Exception as e:
839
        print sys.exc_info()[0]
840
        return False
841
 
842
def authorize_pickup(order_id, pickup_number):
843
    order = get_order(order_id)
844
    if order.status != OrderStatus.DOA_PICKUP_REQUESTED:
845
        return False
846
    from_user = 'help@shop2020.in'
847
    from_pwd = '5h0p2o2o'
848
    subject = 'Pickup details'
849
    filename = "/tmp/" +  str(order.id) +".pdf" 
850
    try:
3133 rajveer 851
        catalog_client = CatalogClient().get_client()
2536 chandransh 852
        warehouse = catalog_client.getWarehouse(order.warehouse_id)
853
 
854
        logistics_client = LogisticsClient().get_client()
855
        provider = logistics_client.getProvider(order.logistics_provider_id)
856
        provider_name = provider.name
857
 
858
        to_addr = order.customer_email
859
        today = date.today().strftime("%d-%B-%Y (%A)")
860
 
861
        raw_message = '''
862
        Dear Mr. %(customer_name)s,
863
 
864
        In reference to the return of order ID %(order_id)d. We request you to kindly pack the box properly with bubble wrap, and send it along with the original "DOA" certificate and the invoice.
865
        Take a printout of the attachment in this mail which contains the delivery address and paste it on the packed parcel.
866
        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.
867
 
868
        Pickup will happen from the below mentioned address:-
869
 
870
        %(customer_address)s
871
 
872
        Do let us know in case of any concerns
873
 
874
        Thanks & Regards
875
        Saholic Team
876
        '''
877
        message = dedent(raw_message) % {'customer_name' : order.customer_name,
878
                                         'order_id' : order_id,
879
                                         'provider_name' : provider_name,
880
                                         'date': today,
881
                                         'pickup_request_no' : pickup_number,
882
                                         'customer_address' : __get_order_address(order)}
883
        print message
884
        __generate_return_advice(order, warehouse, provider, filename)
3527 chandransh 885
        mail(from_user, from_pwd, [to_addr], subject, message, [get_attachment_part(filename)])
2536 chandransh 886
        order.pickupRequestNo = pickup_number
887
        order.status = OrderStatus.DOA_RETURN_AUTHORIZED
888
        order.statusDescription = "DOA pick up authorized"
2764 chandransh 889
        order.doa_auth_timestamp = datetime.datetime.now()
2536 chandransh 890
        session.commit()
891
        return True
892
    except Exception as e:
893
        print sys.exc_info()[0]
894
        return False
895
    finally:
896
        if os.path.exists(filename):
897
            os.remove(filename)
898
 
2764 chandransh 899
def mark_doas_as_picked_up(provider_id, pickup_details):
900
    for pickupNo, doa_pickup_timestamp in pickup_details.iteritems():
901
        order = Order.query.filter_by(pickupRequestNo=pickupNo, logistics_provider_id = provider_id).first()
902
        if order == None or order.status != OrderStatus.DOA_RETURN_AUTHORIZED:
903
            #raise TransactionServiceException(102, "No order found for the awb: " + awb)
904
            continue
905
        order.status = OrderStatus.DOA_RETURN_IN_TRANSIT
906
        order.statusDescription = "DOA picked up by Courier Company"
907
        order.doa_pickup_timestamp = doa_pickup_timestamp
908
    session.commit()
909
 
910
    current_time = datetime.datetime.now()
911
    to_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
912
    from_datetime = to_datetime - datetime.timedelta(2)
913
    orders_not_picked_up = Order.query.filter_by(logistics_provider_id = provider_id).filter_by(status=OrderStatus.DOA_RETURN_AUTHORIZED).filter(Order.doa_auth_timestamp >= from_datetime).filter(Order.doa_auth_timestamp <= to_datetime).all()
914
    return orders_not_picked_up
915
 
2616 chandransh 916
def receive_return(order_id):
2591 chandransh 917
    order = get_order(order_id)
2616 chandransh 918
    if order.status in [OrderStatus.DOA_RETURN_AUTHORIZED, OrderStatus.DOA_RETURN_IN_TRANSIT]:
919
        order.status = OrderStatus.DOA_RECEIVED
920
        order.statusDescription = "DOA package received"
2764 chandransh 921
        order.received_return_timestamp = datetime.datetime.now()
2616 chandransh 922
        session.commit()
923
    elif order.status == OrderStatus.SALES_RETURN_IN_TRANSIT :
924
        order.status = OrderStatus.SALES_RET_RECEIVED
925
        order.statusDescription = "Sales return received"
2764 chandransh 926
        order.received_return_timestamp = datetime.datetime.now()
2616 chandransh 927
        session.commit()
928
    else:
2591 chandransh 929
        return False
930
    return True
931
 
932
def validate_doa(order_id, is_valid):
933
    order = get_order(order_id)
2599 chandransh 934
    if order.status != OrderStatus.DOA_RECEIVED:
2591 chandransh 935
        return False
936
    if is_valid:
2609 chandransh 937
        order.status = OrderStatus.DOA_CERT_VALID
938
        order.statusDescription = "DOA Certificate Valid"
2591 chandransh 939
    else:
940
        order.status = OrderStatus.DOA_CERT_INVALID
941
        order.statusDescription = "DOA Certificate Invalid"
3578 mandeep.dh 942
        update_trust_level(order)
2591 chandransh 943
    session.commit()
944
    return True
945
 
2628 chandransh 946
def reship_order(order_id):
947
    """
948
    If the order is in SALES_RET_RECEIVED or DOA_CERT_INVALID state, it does the following:
949
        1. Creates a new order for processing in the BILLED state. All billing information is saved.
950
        2. Marks the current order as one of the final states SALES_RET_RESHIPPED and DOA_INVALID_RESHIPPED depending on what state the order started in.
951
 
952
    If the order is in DOA_CERT_VALID state, it does the following:
953
        1. Creates a new order for processing in the SUBMITTED_FOR_PROCESSING state.
954
        2. Creates a return order for the warehouse executive to return the DOA material.
955
        3. Marks the current order as the final DOA_RESHIPPED state.
956
 
957
    Returns the id of the newly created order.
958
 
959
    Throws an exception if the order with the given id couldn't be found.
960
 
961
    Parameters:
962
     - orderId
963
    """
964
    order = get_order(order_id)
965
    if order.status == OrderStatus.SALES_RET_RECEIVED:
966
        new_order = __clone_order(order, True)
967
        order.status = OrderStatus.SALES_RET_RESHIPPED
968
        order.statusDescription = "Order Reshipped"
969
        session.commit()
3578 mandeep.dh 970
        update_trust_level(order)
2628 chandransh 971
    elif order.status == OrderStatus.DOA_CERT_INVALID:
972
        new_order = __clone_order(order, True)
973
        order.status = OrderStatus.DOA_INVALID_RESHIPPED
974
        order.statusDescription = "Order Reshipped"
975
        session.commit()
976
    elif order.status == OrderStatus.DOA_CERT_VALID:
977
        new_order = __clone_order(order, False)
978
        ret_order = __create_return_order(order)
979
        order.status = OrderStatus.DOA_RESHIPPED
980
        order.statusDescription = "Order Reshipped"
981
        session.commit()
982
    else:
983
        raise TransactionServiceException(112, "This order can't be reshipped")
984
 
2764 chandransh 985
    order.reship_timestamp = datetime.datetime.now()
2628 chandransh 986
    order.new_order_id = new_order.id
987
    session.commit()
988
 
989
    return new_order.id
990
 
3226 chandransh 991
def refund_order(order_id, refunded_by, reason):
2628 chandransh 992
    """
993
    If the order is in SALES_RET_RECEIVED, DOA_CERT_VALID or DOA_CERT_INVALID state, it does the following:
994
        1. Creates a refund request for batch processing.
995
        2. Creates a return order for the warehouse executive to return the shipped material.
996
        3. Marks the current order as SALES_RET_REFUNDED, DOA_VALID_REFUNDED or DOA_INVALID_REFUNDED final states.
997
 
998
    If the order is in SUBMITTED_FOR_PROCESSING or INVENTORY_LOW state, it does the following:
999
        1. Creates a refund request for batch processing.
3226 chandransh 1000
        2. Cancels the reservation of the item in the warehouse.
1001
        3. Marks the current order as the REFUNDED final state.
2628 chandransh 1002
 
3226 chandransh 1003
    For all COD orders, if the order is in INIT, SUBMITTED_FOR_PROCESSING or INVENTORY_LOW state, it does the following:
1004
        1. Cancels the reservation of the item in the warehouse.
1005
        2. Marks the current order as CANCELED.
1006
 
1007
    In all cases, it updates the reason for cancellation or refund and the person who performed the action.
1008
 
1009
    Returns True if it is successful, False otherwise.
2628 chandransh 1010
 
1011
    Throws an exception if the order with the given id couldn't be found.
1012
 
1013
    Parameters:
3226 chandransh 1014
     - order_id
1015
     - refunded_by
1016
     - reason
2628 chandransh 1017
    """
3414 chandransh 1018
    logging.info("Refunding order id: " + str(order_id))
2628 chandransh 1019
    order = get_order(order_id)
3186 chandransh 1020
 
1021
 
3366 chandransh 1022
 
3226 chandransh 1023
    if order.cod:
3414 chandransh 1024
        logging.info("Refunding COD order with status " + str(order.status))
3366 chandransh 1025
        status_transition = {OrderStatus.SALES_RET_RECEIVED : OrderStatus.SALES_RET_REFUNDED,
1026
                     OrderStatus.DOA_CERT_INVALID : OrderStatus.DOA_INVALID_REFUNDED,
1027
                     OrderStatus.DOA_CERT_VALID : OrderStatus.DOA_VALID_REFUNDED,
1028
                     OrderStatus.INIT : OrderStatus.CANCELED,
1029
                     OrderStatus.SUBMITTED_FOR_PROCESSING : OrderStatus.CANCELED,
1030
                     OrderStatus.INVENTORY_LOW : OrderStatus.CANCELED,
1031
                     OrderStatus.ACCEPTED : OrderStatus.CANCELED,
3731 chandransh 1032
                     OrderStatus.BILLED : OrderStatus.CANCELED
3366 chandransh 1033
                     }
1034
        if order.status not in status_transition.keys():
1035
            raise TransactionServiceException(114, "This order can't be refunded")
1036
 
3413 chandransh 1037
        if order.status < OrderStatus.BILLED:
3226 chandransh 1038
            __update_inventory_reservation(order)
1039
            order.statusDescription = "Order Cancelled"
3415 chandransh 1040
        elif order.status == OrderStatus.BILLED:
3413 chandransh 1041
            __create_return_order(order)
1042
            order.statusDescription = "Order Cancelled"
4078 chandransh 1043
        elif order.status == OrderStatus.SALES_RET_RECEIVED:
3226 chandransh 1044
            __create_return_order(order)
4078 chandransh 1045
            order.statusDescription = "Order Returned to origin"
1046
        elif order.status in [OrderStatus.DOA_CERT_INVALID, OrderStatus.DOA_CERT_VALID] :
1047
            __create_return_order(order)
3226 chandransh 1048
            __create_refund(order)
1049
            order.statusDescription = "Order Refunded"
1050
    else:
3366 chandransh 1051
        status_transition = {OrderStatus.SALES_RET_RECEIVED : OrderStatus.SALES_RET_REFUNDED,
1052
                     OrderStatus.DOA_CERT_INVALID : OrderStatus.DOA_INVALID_REFUNDED,
1053
                     OrderStatus.DOA_CERT_VALID : OrderStatus.DOA_VALID_REFUNDED,
1054
                     OrderStatus.SUBMITTED_FOR_PROCESSING : OrderStatus.REFUNDED,
3731 chandransh 1055
                     OrderStatus.INVENTORY_LOW : OrderStatus.REFUNDED,
1056
                     OrderStatus.ACCEPTED : OrderStatus.REFUNDED,
1057
                     OrderStatus.BILLED : OrderStatus.REFUNDED
3366 chandransh 1058
                     }
1059
        if order.status not in status_transition.keys():
1060
            raise TransactionServiceException(114, "This order can't be refunded")
1061
 
3226 chandransh 1062
        if order.status in [OrderStatus.SALES_RET_RECEIVED, OrderStatus.DOA_CERT_INVALID, OrderStatus.DOA_CERT_VALID] :
1063
            __create_return_order(order)
1064
            __create_refund(order)
1065
            order.statusDescription = "Order Refunded"
1066
        elif order.status in [OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW]:
3191 chandransh 1067
            __create_cancellation(order)
3226 chandransh 1068
            __update_inventory_reservation(order)
1069
            order.statusDescription = "Order Refunded"
3195 chandransh 1070
 
1071
    order.status = status_transition[order.status]
1072
    order.refund_timestamp = datetime.datetime.now()
3226 chandransh 1073
    order.refunded_by = refunded_by
1074
    order.refund_reason = reason
2628 chandransh 1075
 
1076
    session.commit()
1077
    return True
1078
 
3186 chandransh 1079
def __update_inventory_reservation(order):
3191 chandransh 1080
    '''
1081
    Reduce the reservation count for all line items of the given order.
1082
    '''
3186 chandransh 1083
    try:
1084
        catalog_client = CatalogClient().get_client()
1085
        for lineitem in order.lineitems:
1086
            catalog_client.reduceReservationCount(lineitem.item_id, order.warehouse_id, lineitem.quantity);
1087
    except:
1088
        print "Unable to reduce reservation count"
1089
 
2628 chandransh 1090
def __clone_order(order, should_copy_billing_info):
1091
    current_time = datetime.datetime.now()
1092
    new_order = Order()
1093
    new_order.customer_id = order.customer_id
1094
    new_order.customer_name = order.customer_name
1095
    new_order.customer_city = order.customer_city
1096
    new_order.customer_state = order.customer_state
1097
    new_order.customer_mobilenumber = order.customer_mobilenumber
1098
    new_order.customer_pincode = order.customer_pincode
1099
    new_order.customer_address1 = order.customer_address1
1100
    new_order.customer_address2 = order.customer_address2
1101
    new_order.customer_email = order.customer_email
1102
    new_order.total_amount = order.total_amount
1103
    new_order.total_weight = order.total_weight
1104
    new_order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
1105
    new_order.statusDescription = 'Submitted for Processing'
1106
    new_order.created_timestamp = current_time
1107
 
1108
    new_order.transaction = order.transaction
3239 chandransh 1109
    new_order.cod = False
2628 chandransh 1110
 
1111
    for line_item in order.lineitems:
1112
        litem = LineItem()
1113
        litem.item_id = line_item.item_id
1114
        litem.productGroup = line_item.productGroup
1115
        litem.brand = line_item.brand
1116
        if line_item.model_number:
1117
            litem.model_number = line_item.model_number
1118
        if line_item.model_name:    
1119
            litem.model_name = line_item.model_name
1120
        if line_item.color:
1121
            litem.color = line_item.color
1122
        if line_item.extra_info:
1123
            litem.extra_info = line_item.extra_info
1124
        litem.quantity = line_item.quantity
1125
        litem.unit_price = line_item.unit_price
1126
        litem.unit_weight = line_item.unit_weight
1127
        litem.total_price = line_item.total_price
1128
        litem.total_weight = line_item.total_weight
1129
        litem.transfer_price = line_item.transfer_price
1130
        litem.order = new_order
1131
 
1132
    logistics_client = LogisticsClient().get_client()
1133
    item_id = new_order.lineitems[0].item_id
3239 chandransh 1134
    logistics_info = logistics_client.getLogisticsInfo(new_order.customer_pincode, item_id, DeliveryType.PREPAID) #TODO: We should be able to pass another flag to suggest ignoring the inventory situation.
2628 chandransh 1135
    logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
1136
 
1137
    new_order.warehouse_id = logistics_info.warehouseId
1138
    new_order.logistics_provider_id = logistics_info.providerId
1139
    new_order.airwaybill_no = logistics_info.airway_billno
1140
    new_order.tracking_id = new_order.airwaybill_no
1141
    new_order.expected_delivery_time = current_time + datetime.timedelta(days=logistics_info.deliveryTime)
3986 chandransh 1142
    new_order.promised_delivery_time = new_order.expected_delivery_time
2628 chandransh 1143
 
1144
    if should_copy_billing_info:
1145
        new_order.invoice_number = order.invoice_number
1146
        new_order.billed_by = order.billed_by
1147
        new_order.warehouse_id = order.warehouse_id
1148
        new_order.accepted_timestamp = current_time
1149
        new_order.billing_timestamp = current_time    
1150
        new_order.status = OrderStatus.BILLED
1151
        new_order.statusDescription = 'Order Billed'
1152
    else:       
3133 rajveer 1153
        catalog_client = CatalogClient().get_client()
2628 chandransh 1154
        catalog_client.reserveItemInWarehouse(item_id, logistics_info.warehouseId, new_order.lineitems[0].quantity)
1155
 
1156
        item_pricing = catalog_client.getItemPricing(item_id, order.warehouse_id)
1157
        new_order.lineitems[0].transfer_price = item_pricing.transferPrice
1158
 
1159
    return new_order
1160
 
1161
def __create_return_order(order):
2687 chandransh 1162
    ret_order = ReturnOrder(order)
2628 chandransh 1163
    return ret_order
1164
 
1165
def __create_refund(order):
4078 chandransh 1166
    payment_client = PaymentClient().get_client()
1167
    payment_client.createRefund(order.id, order.transaction.id, order.total_amount)
2747 chandransh 1168
    return
2628 chandransh 1169
 
3035 chandransh 1170
def __create_cancellation(order):
1171
    return
1172
 
2536 chandransh 1173
def __get_order_address(order):
1174
    address = order.customer_name + "\n" + order.customer_address1 + "\n"
1175
    if order.customer_address2:
1176
        address = address + order.customer_address2 + "\n"
1177
    address = address + order.customer_city + "\n"
1178
    address = address + order.customer_state + "\n"
1179
    address = address + "PIN " + order.customer_pincode + "\n"
1180
    address = address + "Phone: " + order.customer_mobilenumber
1181
    return address
1182
 
1183
def __generate_return_advice(order, warehouse, provider, filename):    
1184
    pdf = Canvas(filename)
1185
    pdf.setFont('Times-Bold',16)
1186
    address_text = pdf.beginText(inch, PAGE_HEIGHT - inch)
1187
    address_text.textLine("To")
1188
    address_text.textLine("Parmod Kumar")
1189
    for line in warehouse.location.split("\n"):
1190
        address_text.textLine(line)
1191
    address_text.textLine("PIN " + warehouse.pincode)
1192
    address_text.textLine("")
1193
    address_text.textLine("Phone: 9971573026")
1194
    pdf.drawText(address_text)
1195
 
1196
    pdf.setFont('Times-Roman',12)
1197
    order_text = pdf.beginText(inch, PAGE_HEIGHT - 4 * inch)
3051 chandransh 1198
    order_text.textLine("Pickup CODE: " + provider.details[DeliveryType.PREPAID].accountNo)
2536 chandransh 1199
    lineitem = order.lineitems[0] 
1200
    order_text.textLine("Content : " + lineitem.brand + " " + lineitem.model_number + " " + lineitem.color)
1201
    order_text.textLine("Declared Value: Rs. " + str(order.total_amount))
1202
    order_text.textLine("Order ID : " + str(order.id))
1203
    pdf.drawText(order_text)
1204
    pdf.showPage()
1205
    pdf.save()
1206
    return filename
1207
 
2697 chandransh 1208
def get_return_orders(warehouse_id, from_date, to_date):
1209
    query = ReturnOrder.query.filter_by(processedStatus = False)
1210
    if warehouse_id != -1:
1211
        query = query.filter_by(warehouseId = warehouse_id)
1212
    if from_date:
4118 chandransh 1213
        query = query.filter(ReturnOrder.createdAt >from_date)
2697 chandransh 1214
    if to_date:
4118 chandransh 1215
        query = query.filter(ReturnOrder.createdAt < to_date)
2697 chandransh 1216
    return [return_order.to_thrift_object() for return_order in query.all()]
1217
 
2700 chandransh 1218
def get_return_order(id):
1219
    ret_order = ReturnOrder.get_by(orderId = id)
1220
    if ret_order is None:
1221
        raise TransactionServiceException(116, "No return order found for the given order id")
1222
    return ret_order.to_thrift_object()
1223
 
2697 chandransh 1224
def process_return(ret_order_id):
1225
    ret_order = ReturnOrder.get_by(orderId = ret_order_id)
1226
    if ret_order is None:
1227
        raise TransactionServiceException(116, "No return order found for the given order id")
1228
    ret_order.processedStatus = True
2701 chandransh 1229
    ret_order.processedAt = datetime.datetime.now()
2697 chandransh 1230
    session.commit()
1231
 
2819 chandransh 1232
def create_purchase_order(warehouseId):
1233
    if not warehouseId:
1234
        raise TransactionServiceException(101, "bad warehouse id")
1235
 
3451 chandransh 1236
    query = Order.query.with_lockmode("update").filter_by(warehouse_id=warehouseId)
2819 chandransh 1237
    query = query.filter_by(status=OrderStatus.SUBMITTED_FOR_PROCESSING)
1238
    query = query.filter_by(purchase_order_id=None)
1239
    query = query.order_by(Order.created_timestamp)
1240
    pending_orders = query.all()
1241
 
1242
    if not pending_orders:
1243
        return -1
1244
 
1245
    t_purchase_order = PurchaseOrder()
2832 chandransh 1246
    t_purchase_order.supplierId = warehouseId
2819 chandransh 1247
    t_purchase_order.warehouseId = warehouseId
1248
    t_purchase_order.lineitems = []
1249
 
1250
    lineitems = {}
1251
 
1252
    for order in pending_orders:
1253
        for lineitem in order.lineitems:
1254
            item_id = lineitem.item_id
1255
            if lineitems.has_key(item_id):
1256
                lineitems[item_id].quantity = lineitems[item_id].quantity + lineitem.quantity
1257
            else:
1258
                t_po_lineitem = POLineItem()
1259
                t_po_lineitem.productGroup = lineitem.productGroup
1260
                t_po_lineitem.brand = lineitem.brand
1261
                t_po_lineitem.modelNumber = lineitem.model_number
1262
                t_po_lineitem.modelName = lineitem.model_name
1263
                t_po_lineitem.color = lineitem.color
1264
                t_po_lineitem.itemId = lineitem.item_id
1265
                t_po_lineitem.quantity = lineitem.quantity
1266
                t_po_lineitem.unitPrice = lineitem.transfer_price
1267
                lineitems[item_id] = t_po_lineitem
1268
                t_purchase_order.lineitems.append(t_po_lineitem)
1269
 
1270
    warehouse_client = WarehouseClient().get_client()
1271
    po_id = warehouse_client.createPurchaseOrder(t_purchase_order)
1272
 
1273
    for order in pending_orders:
1274
        order.purchase_order_id = po_id
1275
    session.commit()
1276
    return po_id
1277
 
3451 chandransh 1278
def update_weight(order_id, weight):
3469 chandransh 1279
    '''
1280
    Update the weight of order
1281
    '''
3451 chandransh 1282
    order = get_order(order_id)
1283
    order.total_weight = weight
3469 chandransh 1284
    lineitem = order.lineitems[0]
1285
    lineitem.total_weight = weight
1286
    lineitem.unit_weight = weight
3451 chandransh 1287
 
3469 chandransh 1288
    session.commit()
1289
    return order
1290
 
1291
def change_product(order_id, item_id):
1292
    '''
1293
    Ship a product of a different color to the customer.
1294
    '''
1295
    order = get_order(order_id)
1296
    if order.status not in [OrderStatus.INIT, OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW]:
1297
        raise TransactionServiceException(120, "This order has already been processed. Please seek help from engineering.")
1298
 
1299
    lineitem = order.lineitems[0]
3451 chandransh 1300
 
3469 chandransh 1301
    catalog_client = CatalogClient().get_client()
1302
 
1303
    old_item = catalog_client.getItem(lineitem.item_id)
1304
    item = catalog_client.getItem(item_id)
1305
    if old_item.catalogItemId != item.catalogItemId:
1306
        raise TransactionServiceException(121, "You can't ship a different item. You can only ship the same item in a different color.")
1307
 
1308
    catalog_client.reserveItemInWarehouse(item_id, order.warehouse_id, lineitem.quantity)
1309
    catalog_client.reduceReservationCount(lineitem.item_id, order.warehouse_id, lineitem.quantity)
1310
    #TODO: Check that this new item has the same price
1311
 
1312
    lineitem.item_id = item_id
1313
    lineitem.color = item.color
1314
 
3451 chandransh 1315
    session.commit()
3469 chandransh 1316
 
1317
    order = get_order(order_id)
3451 chandransh 1318
    return order
3469 chandransh 1319
 
1320
def change_warehouse(order_id, warehouse_id):
1321
    '''
1322
    Update the warehouse which will be used to fulfil this order.
1323
    '''
1324
    order = get_order(order_id)
1325
    if order.status not in [OrderStatus.INIT, OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW]:
1326
        raise TransactionServiceException(117, "This order has already been processed. Please seek help from engineering.")
1327
 
1328
    if warehouse_id == order.warehouse_id:
1329
        raise TransactionServiceException(118, "You have selected the current warehouse again. Nothing to do")
1330
 
1331
    lineitem = order.lineitems[0]
1332
    catalog_client = CatalogClient().get_client()
1333
    try:
1334
        warehouse = catalog_client.getWarehouse(warehouse_id)
1335
    except:
1336
        raise TransactionServiceException(119, "No warehouse with id" + str(warehouse_id))
1337
 
1338
    catalog_client.reserveItemInWarehouse(lineitem.item_id, warehouse_id, lineitem.quantity)
1339
    catalog_client.reduceReservationCount(lineitem.item_id, order.warehouse_id, lineitem.quantity)
3451 chandransh 1340
 
3469 chandransh 1341
    order.warehouse_id = warehouse_id
1342
    session.commit()
1343
    return order
3553 chandransh 1344
 
3986 chandransh 1345
def add_delay_reason(order_id, reason, further_delay=0):
3553 chandransh 1346
    '''
3994 chandransh 1347
    Adds a delay reason to the order and updates the expected delivery time.
3553 chandransh 1348
    '''
1349
    order = get_order(order_id)
1350
    try:
3581 chandransh 1351
        order.delay_reason = DelayReason._VALUES_TO_NAMES[reason]
4009 chandransh 1352
        actual_delivery_delay = adjust_delivery_time(order.expected_delivery_time, further_delay)
1353
        order.expected_delivery_time = order.expected_delivery_time + datetime.timedelta(days=actual_delivery_delay)
4102 chandransh 1354
 
1355
        if order.status < OrderStatus.SHIPPED_FROM_WH:
1356
            actual_shipping_delay = adjust_delivery_time(order.expected_shipping_time, further_delay)
1357
            order.expected_shipping_time = order.expected_shipping_time + datetime.timedelta(days=actual_shipping_delay)
1358
 
3553 chandransh 1359
        session.commit()
4008 mandeep.dh 1360
 
1361
        try:
1362
            transaction_requiring_extra_processing = TransactionRequiringExtraProcessing()
1363
            transaction_requiring_extra_processing.category = 'DELAYED_DELIVERY'
1364
            transaction_requiring_extra_processing.transaction_id = order.transaction_id
1365
            session.commit()
1366
        except Exception as e:
4065 mandeep.dh 1367
            print 'Could not persist transaction id: ' + str(order.transaction_id) + ' for further processing due to: ' + str(e)
4008 mandeep.dh 1368
 
3553 chandransh 1369
        return True
1370
    except:
3994 chandransh 1371
        print sys.exc_info()[0]
3553 chandransh 1372
        return False
3956 chandransh 1373
 
1374
def reconcile_cod_collection(collected_amount_map, xferBy, xferTxnId, xferDate):
1375
    unprocessed_awbs = {}
1376
    for awb, amount in collected_amount_map.iteritems():
1377
        try:
1378
            order = Order.query.filter_by(airwaybill_no=awb).one()
1379
        except NoResultFound:
1380
            unprocessed_awbs[awb] = "No order was found for the given AWB: " + awb
1381
            continue
1382
        except MultipleResultsFound:
1383
            unprocessed_awbs[awb] = "Multiple orders were found for the given AWB:" + awb
1384
            continue
1385
 
1386
        if order.cod_reconciliation_timestamp:
1387
            #This order has been processed already! This may be a re-run. Let's allow other orders to be processed.
1388
            continue
1389
 
1390
        if order.status < OrderStatus.DELIVERY_SUCCESS:
1391
            #Order has not been delivered yet. No way we can receive the payment.
1392
            unprocessed_awbs[awb] = "Payment has been received for order: " + str(order.id) + " before delivery reconciliation"
1393
            continue
1394
 
1395
        if amount != order.total_amount:
1396
            #Received amount is less than or more than the order amount. Mustn't let the user proceed.
1397
            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)
1398
            continue
1399
 
1400
        try:
1401
            payment_client = PaymentClient().get_client()
1402
            payment_client.partiallyCapturePayment(order.transaction.id, amount, xferBy, xferTxnId, xferDate)
1403
        except Exception:
1404
            unprocessed_awbs[awb] = "We were unable to partially capture payment for order id " + str(order.id) + ", AWB: " + awb
1405
            continue
1406
 
1407
        #Payment has been recorded now. We can update the order peacefully.
1408
        order.cod_reconciliation_timestamp = datetime.datetime.now()
1409
        session.commit()
3469 chandransh 1410
 
3956 chandransh 1411
    return unprocessed_awbs
4008 mandeep.dh 1412
 
1413
def get_transactions_requiring_extra_processing(category):
4065 mandeep.dh 1414
    """
1415
    Returns the list of transaction ids that require some extra processing and
1416
    which belong to a particular category. This is currently used by CRM
1417
    application. If no such transaction ids are present, it returns an empty list.
1418
    """
1419
    query = TransactionRequiringExtraProcessing.query
4008 mandeep.dh 1420
 
4065 mandeep.dh 1421
    if category is not None:
1422
        query = query.filter_by(category = ExtraTransactionProcessingType._VALUES_TO_NAMES.get(category))
4008 mandeep.dh 1423
 
4065 mandeep.dh 1424
    return [a.transaction_id for a in query.all()]
4008 mandeep.dh 1425
 
1426
def mark_transaction_as_processed(transactionId, category):
4065 mandeep.dh 1427
    """
1428
    Marks a particular transaction as processed for a particular cateogory.
1429
    It essentially deletes the transaction id record for a particular
1430
    processing type category (if present) from DB.
1431
    This is currently used by CRM application.
1432
    """
4008 mandeep.dh 1433
    TransactionRequiringExtraProcessing.query.filter_by(transaction_id = transactionId).filter_by(category = ExtraTransactionProcessingType._VALUES_TO_NAMES.get(category)).delete()
1434
    session.commit()
1435
 
4018 chandransh 1436
def get_item_wise_risky_orders_count():
1437
    """
1438
    Returns a map containing the number of risky orders keyed by item id. A risky order
1439
    is defined as one whose shipping date is about to expire.
1440
    """
1441
    item_wise_risky_orders_count = {}
4019 chandransh 1442
    shipping_cutoff_time = (datetime.datetime.now() + datetime.timedelta(days = 1)).replace(hour=PREPAID_SHIPPING_CUTOFF_TIME, minute=0, second=0)
4018 chandransh 1443
    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()
1444
    for order in orders:
1445
        for lineitem in order.lineitems:
1446
            quantity = lineitem.quantity
1447
            if item_wise_risky_orders_count.has_key(lineitem.item_id):
1448
                quantity = quantity + item_wise_risky_orders_count[lineitem.item_id]
1449
 
1450
            item_wise_risky_orders_count[lineitem.item_id] = quantity
1451
    return item_wise_risky_orders_count
1452
 
766 rajveer 1453
def close_session():
1454
    if session.is_active:
1455
        print "session is active. closing it."
2783 chandransh 1456
        session.close()
3376 rajveer 1457
 
1458
def is_alive():
1459
    try:
1460
        session.query(Transaction.id).limit(1).one()
1461
        return True
1462
    except:
1463
        return False
3413 chandransh 1464