Subversion Repositories SmartDukaan

Rev

Rev 2700 | Rev 2747 | 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
import sys
8
import os
9
import datetime 
10
import time
11
from datetime import date
12
from textwrap import dedent
1262 varun.gupt 13
from string import Template
14
 
2536 chandransh 15
from sqlalchemy.sql.expression import and_, or_, desc
16
from sqlalchemy.sql import func
17
 
18
from elixir import *
19
 
20
from reportlab.pdfgen.canvas import Canvas
21
from reportlab.rl_config import defaultPageSize
22
from reportlab.lib.units import inch
23
PAGE_HEIGHT=defaultPageSize[1]
24
PAGE_WIDTH=defaultPageSize[0]
25
 
2687 chandransh 26
from shop2020.model.v1.order.impl.model.ReturnOrder import ReturnOrder
104 ashish 27
from shop2020.model.v1.order.impl.DataService import Transaction, LineItem,\
2687 chandransh 28
    Alerts, Order, BatchNoGenerator
104 ashish 29
from shop2020.thriftpy.model.v1.order.ttypes import Transaction as T_Transaction,\
690 chandransh 30
    TransactionServiceException, TransactionStatus, OrderStatus
855 rajveer 31
from shop2020.utils.Utils import to_py_date, to_java_date
483 rajveer 32
from shop2020.model.v1 import order
743 rajveer 33
from shop2020.clients.LogisticsClient import LogisticsClient
871 chandransh 34
from shop2020.clients.InventoryClient import InventoryClient
1262 varun.gupt 35
from shop2020.clients.UserClient import UserClient
1351 varun.gupt 36
from shop2020.clients.HelperClient import HelperClient
2536 chandransh 37
from shop2020.utils.EmailAttachmentSender import mail, get_attachment_part
104 ashish 38
 
39
def get_new_transaction():
40
    transaction = Transaction()
41
    transaction.createdOn = datetime.datetime.now()
738 chandransh 42
    transaction.status = TransactionStatus.INIT
104 ashish 43
    transaction.status_message = "New transaction"
483 rajveer 44
    return transaction
45
 
46
def create_order(t_order):
47
    order = Order()
48
    if t_order.warehouse_id:
49
        order.warehouse_id = t_order.warehouse_id
509 rajveer 50
    if t_order.logistics_provider_id:    
483 rajveer 51
        order.logistics_provider_id = t_order.logistics_provider_id
52
        order.airwaybill_no = t_order.airwaybill_no
53
        order.tracking_id = t_order.tracking_id
54
    if t_order.expected_delivery_time:    
55
        order.expected_delivery_time = to_py_date(t_order.expected_delivery_time)
56
    if t_order.customer_id:    
57
        order.customer_id = t_order.customer_id
58
        order.customer_name = t_order.customer_name
860 rajveer 59
        order.customer_city = t_order.customer_city
60
        order.customer_state = t_order.customer_state
483 rajveer 61
        order.customer_mobilenumber = t_order.customer_mobilenumber
62
        order.customer_pincode = t_order.customer_pincode
738 chandransh 63
        order.customer_address1 = t_order.customer_address1
64
        order.customer_address2 = t_order.customer_address2
483 rajveer 65
        order.customer_email = t_order.customer_email
66
    #new status and status description to be added    
716 rajveer 67
    order.status = t_order.status  
483 rajveer 68
    order.statusDescription = t_order.statusDescription
69
    order.total_amount = t_order.total_amount
70
    order.total_weight = t_order.total_weight
71
    if t_order.created_timestamp:
72
        order.created_timestamp = to_py_date(t_order.created_timestamp)
73
    else:
685 chandransh 74
        order.created_timestamp = datetime.datetime.now()
483 rajveer 75
    return order
76
 
77
def create_transaction(t_transaction):
78
    t_orders = t_transaction.orders
79
    if not t_orders:
80
        raise TransactionServiceException(101, "Orders missing from the transaction")
81
    transaction = get_new_transaction()
82
    transaction.customer_id = t_transaction.customer_id 
83
    transaction.shopping_cart_id = t_transaction.shoppingCartid
2219 varun.gupt 84
    transaction.coupon_code = t_transaction.coupon_code
483 rajveer 85
 
86
    for t_order in t_orders:
87
        order = create_order(t_order)
88
        order.transaction = transaction 
89
        for line_item in t_order.lineitems:
90
            litem = LineItem()
716 rajveer 91
            litem.item_id = line_item.item_id
963 chandransh 92
            litem.productGroup = line_item.productGroup
483 rajveer 93
            litem.brand = line_item.brand
94
            if line_item.model_number:
95
                litem.model_number = line_item.model_number
96
            if line_item.model_name:    
97
                litem.model_name = line_item.model_name
908 chandransh 98
            if line_item.color:
99
                litem.color = line_item.color
483 rajveer 100
            if line_item.extra_info:
101
                litem.extra_info = line_item.extra_info
102
            litem.quantity = line_item.quantity
103
            litem.unit_price = line_item.unit_price
104
            litem.unit_weight = line_item.unit_weight
105
            litem.total_price = line_item.total_price
106
            litem.total_weight = line_item.total_weight
1262 varun.gupt 107
            litem.transfer_price = line_item.transfer_price
1976 varun.gupt 108
 
483 rajveer 109
            """
110
            if line_item.addedOn:
111
                litem.added_on = to_py_date(line_item.addedOn)
112
            else:
113
                litem.added_on = datetime.datetime.now()
114
            """
115
            litem.order = order
116
    session.commit()
117
    return transaction.id
118
 
119
def get_transaction(transaction_id):
120
    transaction = Transaction.get_by(id=transaction_id)
121
    if not transaction:
122
        raise TransactionServiceException(108, "no such transaction")
123
 
124
    return transaction
125
 
126
def get_transactions_for_customer(customer_id, from_date, to_date, status):
127
    if not customer_id:
128
        raise TransactionServiceException(101, "bad customer id")
129
    query = Transaction.query.filter(Transaction.customer_id == customer_id)
1493 vikas 130
    if status is not None:
483 rajveer 131
        query = query.filter(Transaction.status == status)
132
    if from_date:
133
        query = query.filter(Transaction.createdOn >from_date)
134
    if to_date:
135
        query = query.filter(Transaction.createdOn < to_date)
136
    return query.all()
137
 
138
def get_transactions_for_shopping_cart_id(shopping_cart_id):
139
    transactions = Transaction.query.filter_by(shopping_cart_id=shopping_cart_id).all()
140
    return transactions
141
 
142
def get_transaction_status(transaction_id):
143
    if not transaction_id:
144
        raise TransactionServiceException(101, "bad transaction id")
145
 
146
    transaction = get_transaction(transaction_id)
147
 
148
    return transaction.status
149
 
150
def change_transaction_status(transaction_id, new_status, description):
151
    transaction = get_transaction(transaction_id)
152
    transaction.status = new_status
153
    transaction.status_message = description
690 chandransh 154
    if new_status == TransactionStatus.FAILED:
155
        for order in transaction.orders:
156
            order.status = OrderStatus.PAYMENT_FAILED
2339 chandransh 157
            order.statusDescription = "Payment Failed"
690 chandransh 158
    elif new_status == TransactionStatus.IN_PROCESS:
159
        for order in transaction.orders:
160
            order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
1219 chandransh 161
            order.statusDescription = "Submitted to warehouse"
743 rajveer 162
            #After we got payment success, we will set logistics info also 
163
            logistics_client = LogisticsClient().get_client()
164
            #FIXME line item is only one now. If multiple will come, need to fix.
871 chandransh 165
            item_id = order.lineitems[0].item_id
166
            logistics_info = logistics_client.getLogisticsInfo(order.customer_pincode, item_id)
743 rajveer 167
 
1730 ankur.sing 168
            current_time = datetime.datetime.now()
169
            logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
170
 
743 rajveer 171
            order.warehouse_id = logistics_info.warehouseId
172
            order.logistics_provider_id = logistics_info.providerId
173
            order.airwaybill_no = logistics_info.airway_billno
174
            order.tracking_id = order.airwaybill_no
1730 ankur.sing 175
            order.expected_delivery_time = current_time + datetime.timedelta(days=logistics_info.deliveryTime)
871 chandransh 176
 
177
            catalog_client = InventoryClient().get_client()
178
            catalog_client.reserveItemInWarehouse(item_id, logistics_info.warehouseId, order.lineitems[0].quantity)
1351 varun.gupt 179
 
1341 chandransh 180
            item_pricing = catalog_client.getItemPricing(item_id, order.warehouse_id)
181
            order.lineitems[0].transfer_price = item_pricing.transferPrice
1262 varun.gupt 182
 
483 rajveer 183
    session.commit()
184
    return True
185
 
1730 ankur.sing 186
def adjust_delivery_time(order_time, delivery_days):
187
    order_date = order_time.date()
188
 
189
    delivery_date = order_date + datetime.timedelta(days = delivery_days)
190
    final_delivery_date = delivery_date
191
 
192
    time_format = "%Y-%m-%d %H:%M:%S.%f"
193
    t = time.strptime(str(order_time), time_format)
194
    midnightTime = datetime.datetime(*t[:3])
195
    fromDate = to_java_date(midnightTime)
196
    toDate = -1L
197
 
198
    logistics_client = LogisticsClient().get_client()
199
    holiday_dates = logistics_client.getHolidays(fromDate, toDate)
200
    holiday_dates = [(to_py_date(h_date)).date() for h_date in holiday_dates]
201
 
202
    while order_date <= final_delivery_date:
203
        if order_date.weekday() == 6 or is_holiday(holiday_dates, order_date):
204
            delivery_days = delivery_days + 1
205
            final_delivery_date = final_delivery_date + datetime.timedelta(days = 1)
206
        order_date = order_date + datetime.timedelta(days = 1)
207
    return delivery_days
208
 
209
 
210
 
211
def is_holiday(holidays, date):
212
    try:
213
        holidays.index(date)
214
        return 1
215
    except:
216
        return 0
217
 
1398 varun.gupt 218
def enqueue_transaction_info_email(transaction_id):
1262 varun.gupt 219
    transaction = get_transaction(transaction_id)
220
 
221
    html_header = """
222
<html>
223
<body>
224
<div>
225
    <p>
226
        Hello,<br /><br />
1742 rajveer 227
        Thanks for placing order with us. Following are the details of your order:
1262 varun.gupt 228
    </p>
229
    <div>
230
        Order Date: $order_date
1569 varun.gupt 231
    </div>
1262 varun.gupt 232
    <div>
233
        <table>
1569 varun.gupt 234
        <tr><td colspan="5"><hr /></td></tr>
235
        <tr><td colspan="5" align="left"><b>Order Details</b></td></tr>
236
        <tr><td colspan="5"><hr /></td></tr>
1262 varun.gupt 237
        <tr>
2050 varun.gupt 238
            <th width="100">Order No.</th>
239
            <th>Product</th>
240
            <th width="100">Quantity</th>
241
            <th width="100">Unit Price</th>
242
            <th width="100">Amount</th>
1262 varun.gupt 243
        </tr>
244
    """
1398 varun.gupt 245
    user_email = ""
1262 varun.gupt 246
    total_amount = 0.0
247
    html_table = ""
1569 varun.gupt 248
    order_date = datetime.datetime.now()
1262 varun.gupt 249
 
250
    for order in transaction.orders:
251
        order_date = order.created_timestamp
1398 varun.gupt 252
        user_email = order.customer_email
1569 varun.gupt 253
        html_tr = "<tr><td align='center'>" + str(order.id) + "</td>"
1262 varun.gupt 254
 
255
        for lineitem in order.lineitems:
2050 varun.gupt 256
            lineitem_total_price = round(lineitem.total_price, 2)
257
 
1276 chandransh 258
            html_tr += "<td>" + str(lineitem) + "</td>"
2050 varun.gupt 259
            html_tr += "<td align='center'>" + ("%.0f" % lineitem.quantity) + "</td>"
260
            html_tr += "<td align='center'> Rs. " + ("%.2f" % lineitem.unit_price) + "</td>"
261
            html_tr += "<td align='center'> Rs. " + ("%.2f" % lineitem_total_price) + "</td></tr>"
262
            total_amount += lineitem_total_price
1262 varun.gupt 263
            html_table += html_tr
2050 varun.gupt 264
 
1262 varun.gupt 265
    html_footer = """
266
        <tr><td colspan=5>&nbsp;</td></tr>
1565 varun.gupt 267
        <tr><td colspan=5><hr /></td></tr>
1262 varun.gupt 268
        <tr>
269
            <td colspan=4>Total Amount</td>
2050 varun.gupt 270
            <td> Rs. $total_amount</td>
1262 varun.gupt 271
        </tr>
1569 varun.gupt 272
        <tr><td colspan=5><hr /></td></tr>
1262 varun.gupt 273
        </table>
1569 varun.gupt 274
    </div>
1262 varun.gupt 275
    <p>
276
        Best Wishes,<br />
277
        Saholic Team
278
    </p>
279
</div>
280
</body>
281
</html>
282
    """
1398 varun.gupt 283
 
1569 varun.gupt 284
    dt = datetime.datetime.strptime(str(order_date), "%Y-%m-%d %H:%M:%S")
1565 varun.gupt 285
    formated_order_date = dt.strftime("%A, %d. %B %Y %I:%M%p")
286
 
1262 varun.gupt 287
    email_header = Template(html_header).substitute(dict(order_date = formated_order_date))
2050 varun.gupt 288
    email_footer = Template(html_footer).substitute(dict(total_amount = "%.2f" % total_amount))
1262 varun.gupt 289
 
1351 varun.gupt 290
    try:
291
        helper_client = HelperClient().get_client()
1398 varun.gupt 292
        helper_client.saveUserEmailForSending(user_email, "", "Saholic - Order Details", email_header + html_table + email_footer, str(transaction_id), "TransactionInfo")
1351 varun.gupt 293
        return True
294
    except Exception as e:
295
        print e
296
        return False
1262 varun.gupt 297
 
483 rajveer 298
def get_order(order_id):
299
    order = Order.get_by(id=order_id)
300
    if not order:
301
        raise TransactionServiceException(108, "no such order")
302
 
303
    return order
304
 
305
def get_orders_for_customer(customer_id, from_date, to_date, status):
306
    if not customer_id:
307
        raise TransactionServiceException(101, "bad customer id")
308
    query = Order.query.filter(Order.customer_id == customer_id)
309
    if status:
310
        query = query.filter(Order.status == status)
311
    if from_date:
312
        query = query.filter(Order.created_timestamp >from_date)
313
    if to_date:
314
        query = query.filter(Order.created_timestamp < to_date)
315
    return query.all()
316
 
1528 ankur.sing 317
def get_order_for_customer(order_id, customer_id):
318
    if not customer_id:
319
        raise TransactionServiceException(101, "bad customer id")
320
    order = get_order(order_id)
321
    if order.customer_id != customer_id:
322
        raise TransactionServiceException(108, "order: " + str(order_id) + " does not belong to customer: " + str(customer_id))
323
    return order
324
 
483 rajveer 325
def get_all_orders(status, from_date, to_date, warehouse_id):
326
    if not warehouse_id:
327
        raise TransactionServiceException(101, "bad warehouse id")
328
    query = Order.query.filter(Order.warehouse_id == warehouse_id)
329
    if status:
330
        query = query.filter(Order.status == status)
331
    if from_date:
332
        query = query.filter(Order.created_timestamp >from_date)
333
    if to_date:
334
        query = query.filter(Order.created_timestamp < to_date)
335
    return query.all()
336
 
1382 varun.gupt 337
def get_returnable_orders_for_customer(customer_id, limit = None):
338
    if not customer_id:
339
        raise TransactionServiceException(101, "bad customer id")
340
 
341
    query = Order.query.filter(Order.customer_id == customer_id)
342
    query = query.filter(Order.status != OrderStatus.PAYMENT_FAILED)
343
    query = query.filter(Order.status != OrderStatus.REJECTED)
344
    query = query.filter(Order.status > OrderStatus.SHIPPED_FROM_WH)
345
    query = query.filter(or_(Order.status < OrderStatus.DELIVERY_SUCCESS, Order.delivery_timestamp < datetime.datetime.now() + datetime.timedelta(hours = 48)))
346
    orders = query.all()
347
    order_ids = [order.id for order in orders]
348
    return order_ids
349
 
350
def get_cancellable_orders_for_customer(customer_id, limit = None):
351
    if not customer_id:
352
        raise TransactionServiceException(101, "bad customer id")
353
 
354
    query = Order.query.filter(Order.customer_id == customer_id)
355
    query = query.filter(Order.status != OrderStatus.REJECTED)
1483 varun.gupt 356
    query = query.filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING)
1382 varun.gupt 357
    query = query.filter(Order.status < OrderStatus.BILLED)
358
    orders = query.all()
359
    return [order.id for order in orders]
360
 
995 varun.gupt 361
def get_orders_by_billing_date(status, start_billing_date, end_billing_date, warehouse_id):
362
    if not warehouse_id:
363
        raise TransactionServiceException(101, "bad warehouse id")
364
 
365
    query = Order.query.filter(Order.warehouse_id == warehouse_id)
366
 
367
    if status:
368
        query = query.filter(Order.status == status)
369
 
370
    if start_billing_date:
371
        query = query.filter(Order.billing_timestamp >= start_billing_date)
372
 
373
    if end_billing_date:
374
        query = query.filter(Order.billing_timestamp <= end_billing_date)
375
 
376
    return query.all()
377
 
1528 ankur.sing 378
def get_orders_for_transaction(transaction_id, customer_id):
379
    orders = Order.query.filter_by(transaction_id=transaction_id, customer_id=customer_id).all()
380
 
1208 chandransh 381
    if not orders:
382
        raise TransactionServiceException(101, "No order for the transaction")
383
    return orders
384
 
1405 ankur.sing 385
def get_undelivered_orders(provider_id, warehouse_id):
386
    query = Order.query
387
    if provider_id != -1:
388
        query = query.filter_by(Order.logistics_provider_id == provider_id)
389
    if warehouse_id != -1:
390
        query = query.filter(Order.warehouse_id == warehouse_id)
391
    query = query.filter(and_(Order.status != OrderStatus.DELIVERY_SUCCESS, Order.status != OrderStatus.FAILED, \
392
                              Order.status > OrderStatus.SHIPPED_FROM_WH))
1479 ankur.sing 393
    #Get last midnight time instead of current time as courier company would have sent the 
394
    #delivery records updated at least till midnight and not by the current time.
395
    time_format = "%Y-%m-%d %H:%M:%S.%f"
396
    t = time.strptime(str(datetime.datetime.now()), time_format)
397
    midnightTime = datetime.datetime(*t[:3])
398
    query = query.filter(Order.expected_delivery_time < midnightTime)
1405 ankur.sing 399
    orders = query.all()
400
    return orders
401
 
1208 chandransh 402
def get_line_items_for_order(order_id):
403
    query = LineItem.query.filter(LineItem.order_id == order_id)
404
    return query.all()
405
 
483 rajveer 406
def change_order_status(self, orderId, status, description):
407
    order = get_order(orderId)
408
    order.status = status
409
    order.statusDescription = description
410
    session.commit()
411
    return True
412
 
921 rajveer 413
def accept_order(self, orderId):
414
    order = get_order(orderId)
415
    order.status = OrderStatus.ACCEPTED
416
    order.statusDescription = "Order Accepted"
417
    order.accepted_timestamp = datetime.datetime.now()
418
    session.commit()
419
    return True
420
 
421
def bill_order(self, orderId):
422
    order = get_order(orderId)
423
    order.status = OrderStatus.BILLED
424
    order.statusDescription = "Order Billed"
425
    order.billing_timestamp = datetime.datetime.now()
426
    session.commit()
1208 chandransh 427
    return True
921 rajveer 428
 
1149 chandransh 429
def add_billing_details(orderId, invoice_number, billed_by):
494 rajveer 430
    order = Order.get_by(id=orderId)
431
    if not order:
432
        raise TransactionServiceException(101, "No order found for the givem orderid")
433
    order.invoice_number = invoice_number
434
    order.billed_by = billed_by
435
    session.commit()
436
    return True
759 chandransh 437
 
1149 chandransh 438
def add_jacket_number(orderId, jacket_number):
439
    order = Order.get_by(id=orderId)
440
    if not order:
441
        raise TransactionServiceException(101, "No order found for the givem orderid")
442
    order.jacket_number = jacket_number 
443
    session.commit()
444
    return True
445
 
1220 chandransh 446
def batch_orders(warehouseId):
447
    if not warehouseId:
448
        raise TransactionServiceException(101, "bad warehouse id")
1225 chandransh 449
 
450
    batchno_generator = BatchNoGenerator()
451
    session.commit()
1220 chandransh 452
    query = Order.query.filter_by(warehouse_id=warehouseId)
453
    query = query.filter_by(status=OrderStatus.SUBMITTED_FOR_PROCESSING)
454
    query = query.order_by(Order.created_timestamp)
455
    pending_orders = query.all()
1225 chandransh 456
 
1220 chandransh 457
    serial_no = 1
458
    for order in pending_orders:
1276 chandransh 459
        order.batchNo = batchno_generator.id
1220 chandransh 460
        order.serialNo = serial_no
461
        serial_no += 1
462
    session.commit() 
463
    pending_orders = query.all()
464
    return pending_orders
465
 
466
def order_outofstock(orderId):
1911 chandransh 467
    '''
468
    Mark order as out of stock
469
    '''
1220 chandransh 470
    order = get_order(orderId)
471
    order.status = OrderStatus.INVENTORY_LOW
472
    order.statusDescription = "Low Inventory"
473
    order.outofstock_timestamp = datetime.datetime.now()
474
    session.commit()
475
    return True
476
 
759 chandransh 477
def mark_orders_as_manifested(warehouse_id, provider_id):
478
    try:
986 chandransh 479
        current_timestamp = datetime.datetime.now()
852 chandransh 480
        orders = Order.query.filter_by(warehouse_id = warehouse_id, logistics_provider_id = provider_id, status = OrderStatus.BILLED).all()
759 chandransh 481
        for order in orders:
482
            order.status = OrderStatus.SHIPPED_FROM_WH
987 chandransh 483
            order.statusDescription = "Order shipped from warehouse"
986 chandransh 484
            order.shipping_timestamp = current_timestamp
759 chandransh 485
        session.commit()
486
        return True
487
    except:
488
        return False
1113 chandransh 489
 
490
def mark_orders_as_picked_up(provider_id, pickup_details):
491
    for awb, pickup_timestamp in pickup_details.iteritems():
1135 chandransh 492
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
2684 chandransh 493
        if order == None or order.status != OrderStatus.SHIPPED_FROM_WH:
2220 chandransh 494
            #raise TransactionServiceException(102, "No order found for the awb: " + awb)
495
            continue
1113 chandransh 496
        order.status = OrderStatus.SHIPPED_TO_LOGST
497
        order.statusDescription = "Order picked up by Courier Company"
1246 chandransh 498
        order.pickup_timestamp = pickup_timestamp
1113 chandransh 499
    session.commit()
1217 chandransh 500
 
1132 chandransh 501
    current_time = datetime.datetime.now()
502
    to_datetime = datetime.datetime(current_time.year, current_time.month, current_time.day)
1246 chandransh 503
    from_datetime = to_datetime - datetime.timedelta(2)
1132 chandransh 504
    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 505
    return orders_not_picked_up
506
 
1132 chandransh 507
def mark_orders_as_delivered(provider_id, delivered_orders):
508
    for awb, detail in delivered_orders.iteritems():
1135 chandransh 509
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
2684 chandransh 510
        if order == None or order.status not in [OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST]:
1911 chandransh 511
            continue
512
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
1132 chandransh 513
        order.status = OrderStatus.DELIVERY_SUCCESS
514
        order.statusDescription = "Order delivered"
515
        order.delivery_timestamp, order.receiver = detail.split('|')
516
    session.commit()
517
 
1135 chandransh 518
def mark_orders_as_failed(provider_id, returned_orders):
519
    for awb, detail in returned_orders.iteritems():
520
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
2684 chandransh 521
        if order == None or order.status not in [OrderStatus.SHIPPED_FROM_WH, OrderStatus.SHIPPED_TO_LOGST]:
522
            continue
523
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
524
        order.status = OrderStatus.SALES_RETURN_IN_TRANSIT
1135 chandransh 525
        order.delivery_timestamp, reason = detail.split('|')
526
        order.statusDescription = "Order Returned to Origin:" + reason
1911 chandransh 527
    session.commit()
1135 chandransh 528
 
1246 chandransh 529
def update_non_delivery_reason(provider_id, undelivered_orders):
530
    for awb, reason in undelivered_orders.iteritems():
531
        order = Order.query.filter_by(airwaybill_no=awb, logistics_provider_id = provider_id).first()
532
        if order == None:
2684 chandransh 533
            continue
534
            #raise TransactionServiceException(103, "No order found for the awb:" + awb)
1246 chandransh 535
        order.statusDescription = reason
536
    session.commit()
537
 
483 rajveer 538
def get_alerts(order_id, all):
539
    query = Alerts.query.filter_by(order_id=order_id)
540
    if not all:
541
        query = query.filter_by(valid=True)
542
    return query.all()
543
 
544
def set_alert(order_id, unset, type, comment):
545
    #get existing alert
546
    if unset:
547
        query = Alerts.query.filter_by(order_id=order_id)
548
        query = query.filter_by(type=type)
549
        alerts = query.all()
550
        for alert in alerts:
551
            if alert.valid:
552
                alert.valid = False
553
                alert.comment = comment
554
                alert.time_unset = datetime.datetime.now()
555
    else:
556
        alert = Alerts()
557
        alert.order_id = order_id
558
        alert.valid = True
559
        alert.type = type
560
        alert.comment = comment
561
        alert.time_set = datetime.datetime.now()
766 rajveer 562
    session.commit()    
563
 
1596 ankur.sing 564
def get_valid_order_count():
565
    return Order.query.filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING).count()
566
 
1627 ankur.sing 567
def get_cust_count_with_successful_txn():
568
    return session.query(Order.customer_id).filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING).distinct().count()
569
 
1730 ankur.sing 570
def get_valid_orders_amount_range():
1627 ankur.sing 571
    orders = Order.query.filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING).all()
572
    order_amounts = [o.total_amount for o in orders]
1730 ankur.sing 573
    return [min(order_amounts), max(order_amounts)]
1627 ankur.sing 574
 
1886 ankur.sing 575
def get_valid_orders(limit):
576
    query = Order.query.filter(Order.status >= OrderStatus.SUBMITTED_FOR_PROCESSING)
577
    query = query.order_by(desc(Order.created_timestamp))
578
    if limit > 0:
579
        query = query.limit(limit)
580
    elif limit < 0:
581
        raise TransactionServiceException(101, "Invalid argument limit " + limit)
582
    return query.all()
583
 
2536 chandransh 584
def toggle_doa_flag(order_id):
585
    order = get_order(order_id)
586
    if(order.doaFlag):
587
        order.doaFlag = False
588
    else:
589
        order.doaFlag = True
590
    session.commit()
591
    return order.doaFlag
592
 
593
def request_pickup_number(order_id):
594
    order = get_order(order_id)
595
    if order.status != OrderStatus.DELIVERY_SUCCESS and order.status != OrderStatus.DOA_PICKUP_REQUESTED:
596
        return False
597
    from_user = 'cnc.center@shop2020.in'
598
    from_pwd = '5h0p2o2o'
599
 
600
    subject = "Pickup request"
601
    try:
602
        catalog_client = InventoryClient().get_client()
603
        warehouse = catalog_client.getWarehouse(order.warehouse_id)
604
 
605
        logistics_client = LogisticsClient().get_client()
606
        provider = logistics_client.getProvider(order.logistics_provider_id)
607
        to_addr = provider.email
608
        raw_message = '''
609
        Dear Sir/Madam,
610
 
2559 chandransh 611
        Kindly arrange a pickup today from %(customer_city)s. Pickup and delivery addresses are mentioned below.
2536 chandransh 612
 
613
        Pickup CODE: %(provider_code)s
614
        Total Weight: %(order_weight)s kg
615
 
2559 chandransh 616
        Pickup Address:
2536 chandransh 617
 
618
        %(customer_address)s
619
 
620
        Delivery Address:
621
 
622
        %(warehouse_executive)s
623
        %(warehouse_address)s
624
        PIN %(warehouse_pin)s
625
        Phone: %(warehouse_phone)s
626
 
627
        Thanks and Regards
628
        Anand Sinha
629
        '''
2559 chandransh 630
        message = dedent(raw_message) % { 'customer_city' : order.customer_city,
631
                                          'provider_code' : provider.accountNo,
2536 chandransh 632
                                          'order_weight' : str(order.total_weight),
633
                                          'customer_address' : __get_order_address(order),
634
                                          'warehouse_executive' : 'Parmod Kumar',
635
                                          'warehouse_address' : warehouse.location,
636
                                          'warehouse_pin' : warehouse.pincode,
637
                                          'warehouse_phone': '9971573026'}
638
        mail(from_user, from_pwd, to_addr, subject, message)
639
        order.status = OrderStatus.DOA_PICKUP_REQUESTED
640
        order.statusDescription = "Pick up requested for DOA"
641
        session.commit()
642
        return True
643
    except Exception as e:
644
        print sys.exc_info()[0]
645
        return False
646
 
647
def authorize_pickup(order_id, pickup_number):
648
    order = get_order(order_id)
649
    if order.status != OrderStatus.DOA_PICKUP_REQUESTED:
650
        return False
651
    from_user = 'help@shop2020.in'
652
    from_pwd = '5h0p2o2o'
653
    subject = 'Pickup details'
654
    filename = "/tmp/" +  str(order.id) +".pdf" 
655
    try:
656
        catalog_client = InventoryClient().get_client()
657
        warehouse = catalog_client.getWarehouse(order.warehouse_id)
658
 
659
        logistics_client = LogisticsClient().get_client()
660
        provider = logistics_client.getProvider(order.logistics_provider_id)
661
        provider_name = provider.name
662
 
663
        to_addr = order.customer_email
664
        today = date.today().strftime("%d-%B-%Y (%A)")
665
 
666
        raw_message = '''
667
        Dear Mr. %(customer_name)s,
668
 
669
        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.
670
        Take a printout of the attachment in this mail which contains the delivery address and paste it on the packed parcel.
671
        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.
672
 
673
        Pickup will happen from the below mentioned address:-
674
 
675
        %(customer_address)s
676
 
677
        Do let us know in case of any concerns
678
 
679
        Thanks & Regards
680
        Saholic Team
681
        '''
682
        message = dedent(raw_message) % {'customer_name' : order.customer_name,
683
                                         'order_id' : order_id,
684
                                         'provider_name' : provider_name,
685
                                         'date': today,
686
                                         'pickup_request_no' : pickup_number,
687
                                         'customer_address' : __get_order_address(order)}
688
        print message
689
        __generate_return_advice(order, warehouse, provider, filename)
690
        mail(from_user, from_pwd, to_addr, subject, message, get_attachment_part(filename))
691
        order.pickupRequestNo = pickup_number
692
        order.status = OrderStatus.DOA_RETURN_AUTHORIZED
693
        order.statusDescription = "DOA pick up authorized"
694
        session.commit()
695
        return True
696
    except Exception as e:
697
        print sys.exc_info()[0]
698
        return False
699
    finally:
700
        if os.path.exists(filename):
701
            os.remove(filename)
702
 
2616 chandransh 703
def receive_return(order_id):
2591 chandransh 704
    order = get_order(order_id)
2616 chandransh 705
    if order.status in [OrderStatus.DOA_RETURN_AUTHORIZED, OrderStatus.DOA_RETURN_IN_TRANSIT]:
706
        order.status = OrderStatus.DOA_RECEIVED
707
        order.statusDescription = "DOA package received"
708
        session.commit()
709
    elif order.status == OrderStatus.SALES_RETURN_IN_TRANSIT :
710
        order.status = OrderStatus.SALES_RET_RECEIVED
711
        order.statusDescription = "Sales return received"
712
        session.commit()
713
    else:
2591 chandransh 714
        return False
715
    return True
716
 
717
def validate_doa(order_id, is_valid):
718
    order = get_order(order_id)
2599 chandransh 719
    if order.status != OrderStatus.DOA_RECEIVED:
2591 chandransh 720
        return False
721
    if is_valid:
2609 chandransh 722
        order.status = OrderStatus.DOA_CERT_VALID
723
        order.statusDescription = "DOA Certificate Valid"
2591 chandransh 724
    else:
725
        order.status = OrderStatus.DOA_CERT_INVALID
726
        order.statusDescription = "DOA Certificate Invalid"
727
    session.commit()
728
    return True
729
 
2628 chandransh 730
def reship_order(order_id):
731
    """
732
    If the order is in SALES_RET_RECEIVED or DOA_CERT_INVALID state, it does the following:
733
        1. Creates a new order for processing in the BILLED state. All billing information is saved.
734
        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.
735
 
736
    If the order is in DOA_CERT_VALID state, it does the following:
737
        1. Creates a new order for processing in the SUBMITTED_FOR_PROCESSING state.
738
        2. Creates a return order for the warehouse executive to return the DOA material.
739
        3. Marks the current order as the final DOA_RESHIPPED state.
740
 
741
    Returns the id of the newly created order.
742
 
743
    Throws an exception if the order with the given id couldn't be found.
744
 
745
    Parameters:
746
     - orderId
747
    """
748
    order = get_order(order_id)
749
    if order.status == OrderStatus.SALES_RET_RECEIVED:
750
        new_order = __clone_order(order, True)
751
        order.status = OrderStatus.SALES_RET_RESHIPPED
752
        order.statusDescription = "Order Reshipped"
753
        session.commit()
754
    elif order.status == OrderStatus.DOA_CERT_INVALID:
755
        new_order = __clone_order(order, True)
756
        order.status = OrderStatus.DOA_INVALID_RESHIPPED
757
        order.statusDescription = "Order Reshipped"
758
        session.commit()
759
    elif order.status == OrderStatus.DOA_CERT_VALID:
760
        new_order = __clone_order(order, False)
761
        ret_order = __create_return_order(order)
762
        order.status = OrderStatus.DOA_RESHIPPED
763
        order.statusDescription = "Order Reshipped"
764
        session.commit()
765
    else:
766
        raise TransactionServiceException(112, "This order can't be reshipped")
767
 
768
    order.new_order_id = new_order.id
769
    session.commit()
770
 
771
    return new_order.id
772
 
773
def refund_order(order_id):
774
    """
775
    If the order is in SALES_RET_RECEIVED, DOA_CERT_VALID or DOA_CERT_INVALID state, it does the following:
776
        1. Creates a refund request for batch processing.
777
        2. Creates a return order for the warehouse executive to return the shipped material.
778
        3. Marks the current order as SALES_RET_REFUNDED, DOA_VALID_REFUNDED or DOA_INVALID_REFUNDED final states.
779
 
780
    If the order is in SUBMITTED_FOR_PROCESSING or INVENTORY_LOW state, it does the following:
781
        1. Creates a refund request for batch processing.
782
        2. Marks the current order as the REFUNDED final state.
783
 
784
    Returns True if it is successful.
785
 
786
    Throws an exception if the order with the given id couldn't be found.
787
 
788
    Parameters:
789
     - orderId
790
    """
791
    status_transition = {OrderStatus.SALES_RET_RECEIVED : OrderStatus.SALES_RET_REFUNDED,
792
                         OrderStatus.DOA_CERT_INVALID : OrderStatus.DOA_INVALID_REFUNDED,
793
                         OrderStatus.DOA_CERT_VALID : OrderStatus.DOA_VALID_REFUNDED,
794
                         OrderStatus.SUBMITTED_FOR_PROCESSING : OrderStatus.REFUNDED,
795
                         OrderStatus.INVENTORY_LOW : OrderStatus.REFUNDED
796
                         }
797
    order = get_order(order_id)
798
    if order.status in [OrderStatus.SALES_RET_RECEIVED, OrderStatus.DOA_CERT_INVALID, OrderStatus.DOA_CERT_VALID] :
799
        __create_return_order(order)
800
        __create_refund(order)
801
        order.status = status_transition[order.status]
802
        order.statusDescription = "Refunded"
803
    elif order.status in [OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW]:
804
        __create_refund(order)
2687 chandransh 805
        try:
806
            #Reduce the reservation count for all lineitems.
807
            catalog_client = InventoryClient().get_client()
808
            for lineitem in order.lineitems:
809
                catalog_client.reduceReservationCount(lineitem.item_id, order.warehouse_id, lineitem.quantity);
810
        except:
811
            print "Unable to reduce reservation count"
2628 chandransh 812
        order.status = status_transition[order.status]
813
        order.statusDescription = "Refunded"
814
    else:
815
        raise TransactionServiceException(114, "This order can't be refunded")
816
 
817
    session.commit()
818
    return True
819
 
820
def __clone_order(order, should_copy_billing_info):
821
    current_time = datetime.datetime.now()
822
    new_order = Order()
823
    new_order.customer_id = order.customer_id
824
    new_order.customer_name = order.customer_name
825
    new_order.customer_city = order.customer_city
826
    new_order.customer_state = order.customer_state
827
    new_order.customer_mobilenumber = order.customer_mobilenumber
828
    new_order.customer_pincode = order.customer_pincode
829
    new_order.customer_address1 = order.customer_address1
830
    new_order.customer_address2 = order.customer_address2
831
    new_order.customer_email = order.customer_email
832
    new_order.total_amount = order.total_amount
833
    new_order.total_weight = order.total_weight
834
    new_order.status = OrderStatus.SUBMITTED_FOR_PROCESSING
835
    new_order.statusDescription = 'Submitted for Processing'
836
    new_order.created_timestamp = current_time
837
 
838
    new_order.transaction = order.transaction
839
 
840
    for line_item in order.lineitems:
841
        litem = LineItem()
842
        litem.item_id = line_item.item_id
843
        litem.productGroup = line_item.productGroup
844
        litem.brand = line_item.brand
845
        if line_item.model_number:
846
            litem.model_number = line_item.model_number
847
        if line_item.model_name:    
848
            litem.model_name = line_item.model_name
849
        if line_item.color:
850
            litem.color = line_item.color
851
        if line_item.extra_info:
852
            litem.extra_info = line_item.extra_info
853
        litem.quantity = line_item.quantity
854
        litem.unit_price = line_item.unit_price
855
        litem.unit_weight = line_item.unit_weight
856
        litem.total_price = line_item.total_price
857
        litem.total_weight = line_item.total_weight
858
        litem.transfer_price = line_item.transfer_price
859
        litem.order = new_order
860
 
861
    logistics_client = LogisticsClient().get_client()
862
    item_id = new_order.lineitems[0].item_id
863
    logistics_info = logistics_client.getLogisticsInfo(new_order.customer_pincode, item_id) #TODO: We should be able to pass another flag to suggest ignoring the inventory situation.
864
    logistics_info.deliveryTime = adjust_delivery_time(current_time, logistics_info.deliveryTime)
865
 
866
    new_order.warehouse_id = logistics_info.warehouseId
867
    new_order.logistics_provider_id = logistics_info.providerId
868
    new_order.airwaybill_no = logistics_info.airway_billno
869
    new_order.tracking_id = new_order.airwaybill_no
870
    new_order.expected_delivery_time = current_time + datetime.timedelta(days=logistics_info.deliveryTime)
871
 
872
    if should_copy_billing_info:
873
        new_order.invoice_number = order.invoice_number
874
        new_order.billed_by = order.billed_by
875
        new_order.warehouse_id = order.warehouse_id
876
        new_order.accepted_timestamp = current_time
877
        new_order.billing_timestamp = current_time    
878
        new_order.status = OrderStatus.BILLED
879
        new_order.statusDescription = 'Order Billed'
880
    else:       
881
        catalog_client = InventoryClient().get_client()
882
        catalog_client.reserveItemInWarehouse(item_id, logistics_info.warehouseId, new_order.lineitems[0].quantity)
883
 
884
        item_pricing = catalog_client.getItemPricing(item_id, order.warehouse_id)
885
        new_order.lineitems[0].transfer_price = item_pricing.transferPrice
886
 
887
    return new_order
888
 
889
def __create_return_order(order):
2687 chandransh 890
    ret_order = ReturnOrder(order)
2628 chandransh 891
    return ret_order
892
 
893
def __create_refund(order):
894
    pass
895
 
2536 chandransh 896
def __get_order_address(order):
897
    address = order.customer_name + "\n" + order.customer_address1 + "\n"
898
    if order.customer_address2:
899
        address = address + order.customer_address2 + "\n"
900
    address = address + order.customer_city + "\n"
901
    address = address + order.customer_state + "\n"
902
    address = address + "PIN " + order.customer_pincode + "\n"
903
    address = address + "Phone: " + order.customer_mobilenumber
904
    return address
905
 
906
def __generate_return_advice(order, warehouse, provider, filename):    
907
    pdf = Canvas(filename)
908
    pdf.setFont('Times-Bold',16)
909
    address_text = pdf.beginText(inch, PAGE_HEIGHT - inch)
910
    address_text.textLine("To")
911
    address_text.textLine("Parmod Kumar")
912
    for line in warehouse.location.split("\n"):
913
        address_text.textLine(line)
914
    address_text.textLine("PIN " + warehouse.pincode)
915
    address_text.textLine("")
916
    address_text.textLine("Phone: 9971573026")
917
    pdf.drawText(address_text)
918
 
919
    pdf.setFont('Times-Roman',12)
920
    order_text = pdf.beginText(inch, PAGE_HEIGHT - 4 * inch)
921
    order_text.textLine("Pickup CODE: " + provider.accountNo)
922
    lineitem = order.lineitems[0] 
923
    order_text.textLine("Content : " + lineitem.brand + " " + lineitem.model_number + " " + lineitem.color)
924
    order_text.textLine("Declared Value: Rs. " + str(order.total_amount))
925
    order_text.textLine("Order ID : " + str(order.id))
926
    pdf.drawText(order_text)
927
    pdf.showPage()
928
    pdf.save()
929
    return filename
930
 
2697 chandransh 931
def get_return_orders(warehouse_id, from_date, to_date):
932
    query = ReturnOrder.query.filter_by(processedStatus = False)
933
    if warehouse_id != -1:
934
        query = query.filter_by(warehouseId = warehouse_id)
935
    if from_date:
936
        query = query.filter(Order.created_timestamp >from_date)
937
    if to_date:
938
        query = query.filter(Order.created_timestamp < to_date)
939
    return [return_order.to_thrift_object() for return_order in query.all()]
940
 
2700 chandransh 941
def get_return_order(id):
942
    ret_order = ReturnOrder.get_by(orderId = id)
943
    if ret_order is None:
944
        raise TransactionServiceException(116, "No return order found for the given order id")
945
    return ret_order.to_thrift_object()
946
 
2697 chandransh 947
def process_return(ret_order_id):
948
    ret_order = ReturnOrder.get_by(orderId = ret_order_id)
949
    if ret_order is None:
950
        raise TransactionServiceException(116, "No return order found for the given order id")
951
    ret_order.processedStatus = True
2701 chandransh 952
    ret_order.processedAt = datetime.datetime.now()
2697 chandransh 953
    session.commit()
954
 
766 rajveer 955
def close_session():
956
    if session.is_active:
957
        print "session is active. closing it."
958
        session.close()