| Line 14... |
Line 14... |
| 14 |
to_t_vendor_item_pricing, to_t_source
|
14 |
to_t_vendor_item_pricing, to_t_source
|
| 15 |
from shop2020.model.v1.catalog.impl.DataService import Item, Warehouse, \
|
15 |
from shop2020.model.v1.catalog.impl.DataService import Item, Warehouse, \
|
| 16 |
ItemInventoryHistory, CurrentInventorySnapshot, ItemInfo, ItemChangeLog, \
|
16 |
ItemInventoryHistory, CurrentInventorySnapshot, ItemInfo, ItemChangeLog, \
|
| 17 |
Category, EntityIDGenerator, VendorItemPricing, VendorItemMapping, Vendor, \
|
17 |
Category, EntityIDGenerator, VendorItemPricing, VendorItemMapping, Vendor, \
|
| 18 |
SimilarItems, ProductNotification, Source, SourceItemPricing, AuthorizationLog, \
|
18 |
SimilarItems, ProductNotification, Source, SourceItemPricing, AuthorizationLog, \
|
| 19 |
MissedInventoryUpdate, VendorItemProcurementDelay, VendorHolidays
|
19 |
MissedInventoryUpdate, BadInventorySnapshot, VendorItemProcurementDelay, \
|
| - |
|
20 |
VendorHolidays
|
| 20 |
from shop2020.thriftpy.model.v1.catalog.ttypes import InventoryServiceException, \
|
21 |
from shop2020.thriftpy.model.v1.catalog.ttypes import InventoryServiceException, \
|
| 21 |
status, ItemShippingInfo, HolidayType
|
22 |
status, ItemShippingInfo, HolidayType, InventoryType, WarehouseType
|
| 22 |
from shop2020.thriftpy.model.v1.order.ttypes import AlertType
|
23 |
from shop2020.thriftpy.model.v1.order.ttypes import AlertType
|
| 23 |
from shop2020.utils import EmailAttachmentSender
|
24 |
from shop2020.utils import EmailAttachmentSender
|
| 24 |
from shop2020.utils.EmailAttachmentSender import mail
|
25 |
from shop2020.utils.EmailAttachmentSender import mail
|
| 25 |
from shop2020.utils.Utils import log_entry, to_py_date, log_risky_flag
|
26 |
from shop2020.utils.Utils import log_entry, to_py_date, log_risky_flag
|
| 26 |
from sqlalchemy import desc, asc
|
27 |
from sqlalchemy import desc, asc
|
| 27 |
from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound
|
28 |
from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound
|
| 28 |
from sqlalchemy.sql.expression import and_, or_, distinct, func
|
29 |
from sqlalchemy.sql.expression import and_, or_, distinct, func
|
| 29 |
from string import Template
|
30 |
from string import Template
|
| 30 |
from urllib2 import HTTPBasicAuthHandler
|
31 |
from urllib2 import HTTPBasicAuthHandler
|
| - |
|
32 |
import calendar
|
| 31 |
import datetime
|
33 |
import datetime
|
| 32 |
import sys
|
34 |
import sys
|
| 33 |
import urllib2
|
35 |
import urllib2
|
| 34 |
import calendar
|
- |
|
| 35 |
from functools import partial
|
36 |
from functools import partial
|
| 36 |
|
37 |
|
| 37 |
import threading
|
38 |
import threading
|
| 38 |
|
39 |
|
| 39 |
to_addresses = ["cnc.center@shop2020.in", "ashutosh.saxena@shop2020.in"]
|
40 |
to_addresses = ["cnc.center@shop2020.in", "ashutosh.saxena@shop2020.in"]
|
| Line 365... |
Line 366... |
| 365 |
|
366 |
|
| 366 |
def update_inventory_history(warehouse_id, timestamp, availability):
|
367 |
def update_inventory_history(warehouse_id, timestamp, availability):
|
| 367 |
warehouse = get_Warehouse(warehouse_id)
|
368 |
warehouse = get_Warehouse(warehouse_id)
|
| 368 |
if not warehouse:
|
369 |
if not warehouse:
|
| 369 |
raise InventoryServiceException(107, "Warehouse? Where?")
|
370 |
raise InventoryServiceException(107, "Warehouse? Where?")
|
| 370 |
vendors = get_vendors_for_warehouse(warehouse_id)
|
- |
|
| 371 |
if len(vendors) > 1:
|
- |
|
| 372 |
raise InventoryServiceException(110, "Multiple vendors found for warehouse !")
|
- |
|
| 373 |
vendor = vendors[0]
|
371 |
vendor = warehouse.vendor_id
|
| 374 |
time = datetime.datetime.now()
|
372 |
time = datetime.datetime.now()
|
| 375 |
for item_key, quantity in availability.iteritems():
|
373 |
for item_key, quantity in availability.iteritems():
|
| 376 |
try:
|
374 |
try:
|
| 377 |
vendor_item_mapping = VendorItemMapping.query.filter_by(vendor=vendor, item_key=item_key).one();
|
375 |
vendor_item_mapping = VendorItemMapping.query.filter_by(vendor=vendor, item_key=item_key).one();
|
| 378 |
item = vendor_item_mapping.item
|
376 |
item = vendor_item_mapping.item
|
| Line 394... |
Line 392... |
| 394 |
raise InventoryServiceException(107, "Warehouse? Where?")
|
392 |
raise InventoryServiceException(107, "Warehouse? Where?")
|
| 395 |
|
393 |
|
| 396 |
time = datetime.datetime.now()
|
394 |
time = datetime.datetime.now()
|
| 397 |
warehouse.lastCheckedOn = time
|
395 |
warehouse.lastCheckedOn = time
|
| 398 |
warehouse.vendorString = timestamp
|
396 |
warehouse.vendorString = timestamp
|
| 399 |
vendors = get_vendors_for_warehouse(warehouse_id)
|
- |
|
| 400 |
if len(vendors) > 1:
|
- |
|
| 401 |
raise InventoryServiceException(110, "Multiple vendors found for warehouse !")
|
- |
|
| 402 |
vendor = vendors[0]
|
397 |
vendor = warehouse.vendor_id
|
| 403 |
session.commit()
|
398 |
session.commit()
|
| 404 |
for item_key, quantity in availability.iteritems():
|
399 |
for item_key, quantity in availability.iteritems():
|
| 405 |
try:
|
400 |
try:
|
| 406 |
vendor_item_mapping = VendorItemMapping.query.filter_by(vendor=vendor, item_key=item_key).one();
|
401 |
vendor_item_mapping = VendorItemMapping.query.filter_by(vendor=vendor, item_key=item_key).one();
|
| 407 |
item = vendor_item_mapping.item
|
402 |
item = vendor_item_mapping.item
|
| Line 458... |
Line 453... |
| 458 |
|
453 |
|
| 459 |
def __send_mail_for_missing_key(item_key, quantity, warehouse_id):
|
454 |
def __send_mail_for_missing_key(item_key, quantity, warehouse_id):
|
| 460 |
missedInventoryUpdate = MissedInventoryUpdate.get_by(itemKey = item_key, warehouseId = warehouse_id)
|
455 |
missedInventoryUpdate = MissedInventoryUpdate.get_by(itemKey = item_key, warehouseId = warehouse_id)
|
| 461 |
# One email per product key mismatch
|
456 |
# One email per product key mismatch
|
| 462 |
if not missedInventoryUpdate:
|
457 |
if not missedInventoryUpdate:
|
| 463 |
EmailAttachmentSender.mail('cnc.center@shop2020.in', '5h0p2o2o', ['mandeep.dhir@shop2020.in', 'chaitnaya.vats@shop2020.in'], 'Skipped inventory update for ' + item_key + ' quantity ' + str(quantity) + ' warehouse id: ' + str(warehouse_id), None)
|
458 |
EmailAttachmentSender.mail('cnc.center@shop2020.in', '5h0p2o2o', ['mandeep.dhir@shop2020.in', 'chaitnaya.vats@shop2020.in', 'asghar.bilgrami@shop2020.in'], 'Skipped inventory update for ' + item_key + ' quantity ' + str(quantity) + ' warehouse id: ' + str(warehouse_id), None)
|
| 464 |
missedInventoryUpdate = MissedInventoryUpdate()
|
459 |
missedInventoryUpdate = MissedInventoryUpdate()
|
| 465 |
missedInventoryUpdate.itemKey = item_key
|
460 |
missedInventoryUpdate.itemKey = item_key
|
| 466 |
missedInventoryUpdate.quantity = quantity
|
461 |
missedInventoryUpdate.quantity = quantity
|
| 467 |
missedInventoryUpdate.isIgnored = 1
|
462 |
missedInventoryUpdate.isIgnored = 1
|
| 468 |
missedInventoryUpdate.timestamp = datetime.datetime.now()
|
463 |
missedInventoryUpdate.timestamp = datetime.datetime.now()
|
| Line 484... |
Line 479... |
| 484 |
current_inventory_snapshot.availibility = current_inventory_snapshot.availibility + quantity
|
479 |
current_inventory_snapshot.availibility = current_inventory_snapshot.availibility + quantity
|
| 485 |
session.commit()
|
480 |
session.commit()
|
| 486 |
if current_inventory_snapshot.availibility < 0:
|
481 |
if current_inventory_snapshot.availibility < 0:
|
| 487 |
__send_alert_for_negative_availability(get_item(itemId), current_inventory_snapshot.availibility, get_Warehouse(warehouseId))
|
482 |
__send_alert_for_negative_availability(get_item(itemId), current_inventory_snapshot.availibility, get_Warehouse(warehouseId))
|
| 488 |
check_risky_item(get_item(itemId))
|
483 |
check_risky_item(get_item(itemId))
|
| 489 |
|
- |
|
| 490 |
'''
|
484 |
|
| 491 |
def get_item_inventoy(item_id):
|
485 |
def add_bad_inventory(itemId, warehouseId, quantity):
|
| 492 |
|
- |
|
| 493 |
inventory = Item.get_by(id=item_id).currentInventory
|
486 |
bad_inventory_snapshot = BadInventorySnapshot.get_by(item_id=itemId, warehouse_id=warehouseId)
|
| 494 |
if not inventory:
|
487 |
if not bad_inventory_snapshot:
|
| - |
|
488 |
bad_inventory_snapshot = BadInventorySnapshot()
|
| - |
|
489 |
bad_inventory_snapshot.item_id = itemId
|
| - |
|
490 |
bad_inventory_snapshot.warehouse_id = warehouseId
|
| - |
|
491 |
bad_inventory_snapshot.availability = 0
|
| 495 |
raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
|
492 |
# added the difference in the current inventory
|
| - |
|
493 |
bad_inventory_snapshot.availability += quantity
|
| 496 |
return inventory
|
494 |
session.commit()
|
| 497 |
'''
|
- |
|
| - |
|
495 |
if bad_inventory_snapshot.availability < 0:
|
| - |
|
496 |
__send_alert_for_negative_availability(get_item(itemId), bad_inventory_snapshot.availability, get_Warehouse(warehouseId))
|
| 498 |
|
497 |
|
| 499 |
def get_item_inventory_by_item_id(item_id):
|
498 |
def get_item_inventory_by_item_id(item_id):
|
| 500 |
inventory = Item.get_by(id=item_id).currentInventory
|
499 |
inventory = Item.get_by(id=item_id).currentInventory
|
| 501 |
if not inventory:
|
500 |
if not inventory:
|
| 502 |
raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
|
501 |
raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
|
| Line 732... |
Line 731... |
| 732 |
return True
|
731 |
return True
|
| 733 |
|
732 |
|
| 734 |
def get_item_availability_for_location(warehouse_loc, item_id):
|
733 |
def get_item_availability_for_location(warehouse_loc, item_id):
|
| 735 |
"""
|
734 |
"""
|
| 736 |
Determines the warehouse that should be used to fulfil an order for the given item.
|
735 |
Determines the warehouse that should be used to fulfil an order for the given item.
|
| - |
|
736 |
Algorithm explained at https://sites.google.com/a/shop2020.in/virtual-w-h-and-inventory/technical-details
|
| - |
|
737 |
|
| 737 |
It first checks whether the preferred warehouse for that item is set or not. If set
|
738 |
If item's Preferred warehouse is present
|
| - |
|
739 |
If item marked sticky
|
| 738 |
and preference is sticky then that warehouse is used for fulfilment.
|
740 |
use GOOD type warehouse at preferred warehouse with maximum availability.
|
| 739 |
If preference is not sticky then we see if item is available in the preferred WH,
|
741 |
If not available at any, then use THIRD_PARTY warehouse without billing support
|
| 740 |
in which case that warehouse is used otherwise we use that warehouse which has the max
|
742 |
corresponding to preferred warehouse where available.
|
| 741 |
availability. And if there is no inventory for that item in any warehouses then we use
|
743 |
If still not available, then use any GOOD type warehouse with billing support.
|
| 742 |
default warehouse.
|
744 |
else
|
| - |
|
745 |
if availability > 0 at least one of GOOD type warehouses in preferred warehouse
|
| 743 |
If preference is not set in that case we just find the warehouse with max availability
|
746 |
use GOOD type warehouse at preferred warehouse with maximum availability
|
| - |
|
747 |
|
| - |
|
748 |
If available at no warehouse
|
| 744 |
and in case of zero inventory we use default warehouse
|
749 |
use any GOOD type warehouse at default warehouse
|
| 745 |
|
750 |
else
|
| - |
|
751 |
if available at any warehouse of type GOOD with billing support
|
| - |
|
752 |
use warehouse of type GOOD with billing support with maximum availability
|
| - |
|
753 |
else
|
| - |
|
754 |
if preferred warehouse is present and availability at preferred warehouse's corresponding ThirdPartyWarehouse without billing support > 0
|
| - |
|
755 |
preferred warehouse's corresponding ThirdPartyWarehouse without billing support with maximum availability
|
| - |
|
756 |
else
|
| - |
|
757 |
use ThirdPartyWarehouse without billing support with maximum availability
|
| - |
|
758 |
|
| 746 |
Returns an ordered list of size 4 with following elements in the given order:
|
759 |
Returns an ordered list of size 4 with following elements in the given order:
|
| 747 |
1. Logistics location of the warehouse which was finally picked up to ship the order.
|
760 |
1. Logistics location of the warehouse which was finally picked up to ship the order.
|
| 748 |
2. Id of the warehouse which was finally picked up.
|
761 |
2. Id of the warehouse which was finally picked up.
|
| 749 |
3. Inventory size in the selected warehouse.
|
762 |
3. Inventory size in the selected warehouse.
|
| 750 |
4. Expected delay added by the category manager.
|
763 |
4. Expected delay added by the category manager.
|
| 751 |
|
764 |
|
| 752 |
Parameters:
|
765 |
Parameters:
|
| 753 |
- warehouse_loc
|
766 |
- warehouse_loc
|
| 754 |
- item_id
|
767 |
- item_id
|
| 755 |
"""
|
768 |
"""
|
| 756 |
if warehouse_loc is None:
|
769 |
if warehouse_loc is None:
|
| Line 758... |
Line 771... |
| 758 |
if not item_id:
|
771 |
if not item_id:
|
| 759 |
raise InventoryServiceException(101, "Bad Item id")
|
772 |
raise InventoryServiceException(101, "Bad Item id")
|
| 760 |
|
773 |
|
| 761 |
item = Item.get_by(id=item_id)
|
774 |
item = Item.get_by(id=item_id)
|
| 762 |
logisticsLocation = warehouse_loc
|
775 |
logisticsLocation = warehouse_loc
|
| - |
|
776 |
warehouse_ids = []
|
| - |
|
777 |
goodBillableWarehouses = []
|
| - |
|
778 |
goodBillableWarehousesAtPreferredShippingLocation = []
|
| - |
|
779 |
goodBillableWarehousesAtDefaultShippingLocation = []
|
| - |
|
780 |
nonBillableWarehouses = []
|
| - |
|
781 |
nonBillableWarehousesCorrespondingToPreferredShippingLocation = []
|
| - |
|
782 |
for warehouse in Warehouse.query.all():
|
| - |
|
783 |
if (warehouse.inventoryType == InventoryType._VALUES_TO_NAMES[InventoryType.BAD]):
|
| - |
|
784 |
continue
|
| - |
|
785 |
if warehouse.shippingWarehouseId == item.defaultWarehouse and warehouse.inventoryType == InventoryType._VALUES_TO_NAMES[InventoryType.GOOD] and warehouse.billingWarehouseId:
|
| - |
|
786 |
goodBillableWarehousesAtDefaultShippingLocation.append(warehouse.id)
|
| - |
|
787 |
if warehouse.billingWarehouseId is None:
|
| - |
|
788 |
nonBillableWarehouses.append(warehouse.id)
|
| 763 |
warehouses = Warehouse.query.filter_by(logisticsLocation=logisticsLocation).all()
|
789 |
if warehouse.logisticsLocation == logisticsLocation:
|
| 764 |
warehouse_ids = [warehouse.id for warehouse in warehouses]
|
790 |
warehouse_ids.append(warehouse.id)
|
| - |
|
791 |
if warehouse.billingWarehouseId and warehouse.inventoryType == InventoryType._VALUES_TO_NAMES[InventoryType.GOOD]:
|
| - |
|
792 |
goodBillableWarehouses.append(warehouse.id)
|
| - |
|
793 |
if item.preferredWarehouse and item.preferredWarehouse == warehouse.shippingWarehouseId:
|
| - |
|
794 |
goodBillableWarehousesAtPreferredShippingLocation.append(warehouse.id)
|
| - |
|
795 |
nonBillableWarehousesCorrespondingToPreferredShippingLocation.extend([w.id for w in Warehouse.query.filter_by(logisticsLocation=logisticsLocation, vendor_id = warehouse.vendor_id, billingWarehouseId = None).all()])
|
| - |
|
796 |
|
| 765 |
warehouse_retid = -1
|
797 |
warehouse_retid = -1
|
| 766 |
|
- |
|
| 767 |
total_availability = 0
|
798 |
total_availability = 0
|
| - |
|
799 |
|
| 768 |
'''
|
800 |
'''
|
| 769 |
If warehouse preference is set and it is sticky then we should fulfil this order from this warehouse only.
|
801 |
If warehouse preference is set and it is sticky then we should fulfil this order from this warehouse only.
|
| 770 |
But we still need to calculate total availability across warehouses.
|
802 |
But we still need to calculate total availability across warehouses.
|
| 771 |
'''
|
803 |
'''
|
| 772 |
if (item.isWarehousePreferenceSticky and item.preferredWarehouse is not None) :
|
804 |
if (item.isWarehousePreferenceSticky and item.preferredWarehouse):
|
| - |
|
805 |
[warehouse_retid, total_availability] = __get_warehouse_with_max_availability(goodBillableWarehousesAtPreferredShippingLocation, item)
|
| 773 |
warehouse_retid = item.preferredWarehouse
|
806 |
if warehouse_retid == -1:
|
| 774 |
warehouse = Warehouse.get_by(id=warehouse_retid)
|
807 |
[warehouse_retid, total_availability] = __get_warehouse_with_max_availability(nonBillableWarehousesCorrespondingToPreferredShippingLocation, item)
|
| 775 |
logisticsLocation = warehouse.logisticsLocation
|
808 |
if warehouse_retid == -1:
|
| 776 |
total_availability = __get_item_availability(item, [warehouse_retid])
|
809 |
warehouse_retid = goodBillableWarehousesAtPreferredShippingLocation[0]
|
| 777 |
|
- |
|
| 778 |
#If preference is not sticky then this order should be fulfilled from preferred WH if inventory available
|
810 |
elif (not item.isWarehousePreferenceSticky and item.preferredWarehouse):
|
| 779 |
#otherwise we should check for its availability elsewhere and fulfil this order from there, but if it is not available anywhere
|
811 |
[warehouse_retid, total_availability] = __get_warehouse_with_max_availability(goodBillableWarehousesAtPreferredShippingLocation, item)
|
| 780 |
#then we should fulfil this order from its default warehouse.
|
- |
|
| 781 |
|
812 |
|
| 782 |
elif (not item.isWarehousePreferenceSticky and item.preferredWarehouse is not None):
|
- |
|
| 783 |
try:
|
813 |
if warehouse_retid == -1:
|
| 784 |
current_inventory_snapshot = CurrentInventorySnapshot.query.filter_by(warehouse_id = item.preferredWarehouse, item_id = item_id).one()
|
- |
|
| 785 |
availability = current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
|
814 |
[warehouse_retid, total_availability] = __get_warehouse_with_max_availability(warehouse_ids, item)
|
| 786 |
except Exception as e:
|
815 |
if warehouse_retid == -1:
|
| - |
|
816 |
warehouse_retid = goodBillableWarehousesAtDefaultShippingLocation[0]
|
| 787 |
print e
|
817 |
else:
|
| 788 |
availability = 0
|
818 |
[warehouse_retid, total_availability] = __get_warehouse_with_max_availability(goodBillableWarehouses, item)
|
| 789 |
if availability > 0:
|
819 |
if warehouse_retid == -1:
|
| 790 |
warehouse_retid = item.preferredWarehouse
|
820 |
if item.preferredWarehouse:
|
| 791 |
total_availability = availability
|
821 |
[warehouse_retid, total_availability] = __get_warehouse_with_max_availability(nonBillableWarehousesCorrespondingToPreferredShippingLocation, item)
|
| 792 |
else :
|
- |
|
| 793 |
[logisticsLocation, warehouse_retid, total_availability] = \
|
822 |
if warehouse_retid == -1:
|
| 794 |
__get_warehouse_with_max_availability(warehouse_loc = warehouse_loc, \
|
823 |
# Availability at Good Billable warehouses is Zero, so can safely use all warehouse_ids to capture the thirdparty virtual/good one
|
| 795 |
warehouse_ids = warehouse_ids, item = item)
|
824 |
[warehouse_retid, total_availability] = __get_warehouse_with_max_availability(warehouse_ids, item)
|
| 796 |
|
- |
|
| 797 |
else :
|
825 |
|
| 798 |
[logisticsLocation, warehouse_retid, total_availability] = \
|
826 |
warehouse = Warehouse.get_by(id=warehouse_retid)
|
| 799 |
__get_warehouse_with_max_availability(warehouse_loc = warehouse_loc, \
|
827 |
billingWarehouseId = warehouse.billingWarehouseId
|
| 800 |
warehouse_ids = warehouse_ids, item = item)
|
- |
|
| 801 |
|
828 |
|
| 802 |
## FIXME Assign warehouse 5 (9D2) for all the hotspot products.
|
829 |
# Fetching billing warehouse of a Good billable warehouse corresponding to the virtual one
|
| 803 |
#if warehouse_retid in [warehouse.id for warehouse in get_warehouses_for_vendor(1)]:
|
830 |
if warehouse.billingWarehouseId is None:
|
| 804 |
if int(warehouse_retid) in [1,2,3,4,5]:
|
831 |
for warehouse in Warehouse.query.filter_by(vendor_id = warehouse.vendor_id, inventoryType = InventoryType._VALUES_TO_NAMES[InventoryType.GOOD]).all():
|
| 805 |
warehouse_retid = 5
|
832 |
if warehouse.billingWarehouseId:
|
| 806 |
warehouse = Warehouse.get_by(id=warehouse_retid)
|
833 |
billingWarehouseId = warehouse.billingWarehouseId
|
| - |
|
834 |
break
|
| - |
|
835 |
|
| 807 |
logisticsLocation = warehouse.logisticsLocation
|
836 |
logisticsLocation = warehouse.logisticsLocation
|
| 808 |
|
837 |
|
| 809 |
expectedDelay = item.expectedDelay
|
838 |
expectedDelay = item.expectedDelay
|
| 810 |
if expectedDelay is None:
|
839 |
if expectedDelay is None:
|
| 811 |
print 'expectedDelay field for this item was Null. Resetting it to 0'
|
840 |
print 'expectedDelay field for this item was Null. Resetting it to 0'
|
| 812 |
expectedDelay = 0
|
841 |
expectedDelay = 0
|
| Line 815... |
Line 844... |
| 815 |
|
844 |
|
| 816 |
if total_availability <= 0:
|
845 |
if total_availability <= 0:
|
| 817 |
expectedDelay = expectedDelay + __get_expected_procurement_delay(item)
|
846 |
expectedDelay = expectedDelay + __get_expected_procurement_delay(item)
|
| 818 |
expectedDelay = expectedDelay + __get_vendor_holiday_delay(item, expectedDelay)
|
847 |
expectedDelay = expectedDelay + __get_vendor_holiday_delay(item, expectedDelay)
|
| 819 |
|
848 |
|
| 820 |
return [logisticsLocation, int(warehouse_retid), total_availability, expectedDelay]
|
849 |
return [logisticsLocation, int(warehouse_retid), total_availability, expectedDelay, billingWarehouseId]
|
| 821 |
|
850 |
|
| 822 |
def __get_warehouse_with_max_availability(warehouse_loc, warehouse_ids, item):
|
851 |
def __get_warehouse_with_max_availability(warehouse_ids, item):
|
| 823 |
|
- |
|
| 824 |
warehouse_retid = -1
|
852 |
warehouse_retid = -1
|
| 825 |
max_availability = 0
|
853 |
max_availability = 0
|
| 826 |
total_availability = 0
|
854 |
total_availability = 0
|
| 827 |
|
855 |
|
| 828 |
for warehouse_id in warehouse_ids:
|
- |
|
| 829 |
try:
|
856 |
if item.currentInventory:
|
| 830 |
current_inventory_snapshot = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item.id).one()
|
- |
|
| 831 |
availability = current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
|
- |
|
| 832 |
except Exception as e:
|
857 |
for entry in item.currentInventory:
|
| 833 |
print e
|
858 |
if entry.warehouse_id in warehouse_ids:
|
| 834 |
availability = 0
|
859 |
availability = entry.availibility - entry.reserved
|
| 835 |
if availability > max_availability:
|
860 |
if availability > max_availability:
|
| 836 |
warehouse_retid = warehouse_id
|
861 |
warehouse_retid = entry.warehouse_id
|
| 837 |
max_availability = availability
|
862 |
max_availability = availability
|
| 838 |
total_availability = total_availability + availability
|
- |
|
| 839 |
|
- |
|
| 840 |
#If no warehouse could be found, use the default warehouse for this item
|
- |
|
| 841 |
if warehouse_retid == -1:
|
- |
|
| 842 |
# This is the case when all warehouses have exhausted their
|
- |
|
| 843 |
# inventory of this item or no warehouse is available in this
|
- |
|
| 844 |
# location.
|
- |
|
| 845 |
warehouse_retid = int(item.defaultWarehouse)
|
- |
|
| 846 |
warehouse = Warehouse.get_by(id=warehouse_retid)
|
- |
|
| 847 |
warehouse_loc = warehouse.logisticsLocation
|
- |
|
| 848 |
try:
|
- |
|
| 849 |
current_inventory_snapshot = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_retid, item_id = item.id).one()
|
- |
|
| 850 |
max_availability = current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
|
- |
|
| 851 |
except Exception as e:
|
- |
|
| 852 |
print e
|
- |
|
| 853 |
max_availability = 0
|
- |
|
| 854 |
total_availability = max_availability
|
863 |
total_availability += availability
|
| 855 |
|
864 |
|
| 856 |
return [warehouse_loc, warehouse_retid, total_availability]
|
865 |
return [warehouse_retid, total_availability]
|
| 857 |
'''
|
- |
|
| 858 |
def calculate_total_availability(warehouse_ids, item_id):
|
- |
|
| 859 |
total_availability = 0
|
- |
|
| 860 |
for warehouse_id in warehouse_ids:
|
- |
|
| 861 |
try:
|
- |
|
| 862 |
current_inventory_snapshot = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id).one()
|
- |
|
| 863 |
availability = current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
|
- |
|
| 864 |
except Exception as e:
|
- |
|
| 865 |
print e
|
- |
|
| 866 |
availability = 0
|
- |
|
| 867 |
total_availability = total_availability + availability
|
- |
|
| 868 |
return total_availability
|
- |
|
| 869 |
'''
|
- |
|
| 870 |
|
866 |
|
| 871 |
def __get_expected_procurement_delay(item):
|
867 |
def __get_expected_procurement_delay(item):
|
| 872 |
procurementDelay = 2
|
868 |
procurementDelay = 2
|
| 873 |
try:
|
869 |
try:
|
| 874 |
if item.preferredVendor:
|
870 |
if item.preferredVendor:
|
| Line 1456... |
Line 1452... |
| 1456 |
|
1452 |
|
| 1457 |
def send_product_notifications():
|
1453 |
def send_product_notifications():
|
| 1458 |
product_notifications = ProductNotification.query.all()
|
1454 |
product_notifications = ProductNotification.query.all()
|
| 1459 |
for product_notification in product_notifications:
|
1455 |
for product_notification in product_notifications:
|
| 1460 |
item = product_notification.item
|
1456 |
item = product_notification.item
|
| 1461 |
availability = __get_item_availability(item, None)
|
- |
|
| 1462 |
if availability > 0 and item.status == status.ACTIVE:
|
1457 |
if item.status == status.ACTIVE:
|
| 1463 |
__enque_product_notification_email(product_notification.email, __get_product_name(item) , product_notification.addedOn, __get_product_url(item), item.id)
|
1458 |
__enque_product_notification_email(product_notification.email, __get_product_name(item) , product_notification.addedOn, __get_product_url(item), item.id)
|
| 1464 |
product_notification.delete()
|
1459 |
product_notification.delete()
|
| 1465 |
session.commit()
|
1460 |
session.commit()
|
| 1466 |
return True
|
1461 |
return True
|
| 1467 |
|
1462 |
|
| Line 1665... |
Line 1660... |
| 1665 |
def get_pending_orders_inventory(vendor_id=1):
|
1660 |
def get_pending_orders_inventory(vendor_id=1):
|
| 1666 |
"""
|
1661 |
"""
|
| 1667 |
Returns a list of inventory stock for items for which there are pending orders.
|
1662 |
Returns a list of inventory stock for items for which there are pending orders.
|
| 1668 |
"""
|
1663 |
"""
|
| 1669 |
|
1664 |
|
| 1670 |
warehouse_ids = [warehouse.id for warehouse in get_warehouses_for_vendor(vendor_id)]
|
1665 |
warehouse_ids = [warehouse.id for warehouse in Warehouse.query.filter_by(vendor_id = vendor_id)]
|
| 1671 |
pending_items_inventory = []
|
1666 |
pending_items_inventory = []
|
| 1672 |
if warehouse_ids:
|
1667 |
if warehouse_ids:
|
| 1673 |
pending_items_inventory = session.query(CurrentInventorySnapshot.item_id, func.sum(CurrentInventorySnapshot.availibility), func.sum(CurrentInventorySnapshot.reserved)).filter(CurrentInventorySnapshot.warehouse_id.in_(warehouse_ids)).group_by(CurrentInventorySnapshot.item_id).having(func.sum(CurrentInventorySnapshot.reserved) > 0).all()
|
1668 |
pending_items_inventory = session.query(CurrentInventorySnapshot.item_id, func.sum(CurrentInventorySnapshot.availibility), func.sum(CurrentInventorySnapshot.reserved)).filter(CurrentInventorySnapshot.warehouse_id.in_(warehouse_ids)).group_by(CurrentInventorySnapshot.item_id).having(func.sum(CurrentInventorySnapshot.reserved) > 0).all()
|
| 1674 |
return pending_items_inventory
|
1669 |
return pending_items_inventory
|
| 1675 |
|
1670 |
|
| Line 1724... |
Line 1719... |
| 1724 |
return ds_vendor.id
|
1719 |
return ds_vendor.id
|
| 1725 |
|
1720 |
|
| 1726 |
def add_warehouse_vendor_mapping(warehouse_id, VendorId):
|
1721 |
def add_warehouse_vendor_mapping(warehouse_id, VendorId):
|
| 1727 |
return True
|
1722 |
return True
|
| 1728 |
|
1723 |
|
| 1729 |
def get_vendors_for_warehouse(warehouse_id):
|
- |
|
| 1730 |
try:
|
- |
|
| 1731 |
warehouse = Warehouse.get_by(id=warehouse_id)
|
- |
|
| 1732 |
return warehouse.vendors
|
- |
|
| 1733 |
except:
|
- |
|
| 1734 |
raise InventoryServiceException(108, "Bad Warehouse Id")
|
- |
|
| 1735 |
|
- |
|
| 1736 |
def get_warehouses_for_vendor(vendorId):
|
- |
|
| 1737 |
try:
|
- |
|
| 1738 |
vendor = get_Vendor(vendorId)
|
- |
|
| 1739 |
return vendor.warehouses
|
- |
|
| 1740 |
except:
|
- |
|
| 1741 |
raise InventoryServiceException(108, "Bad Vendor Id")
|
- |
|
| 1742 |
|
- |
|
| 1743 |
def add_authorization_log_for_item(itemId, username, reason):
|
1724 |
def add_authorization_log_for_item(itemId, username, reason):
|
| 1744 |
if not itemId or not username:
|
1725 |
if not itemId or not username:
|
| 1745 |
raise InventoryServiceException(101, "Bad itemId or Invalid username in request")
|
1726 |
raise InventoryServiceException(101, "Bad itemId or Invalid username in request")
|
| 1746 |
authorize_log = AuthorizationLog()
|
1727 |
authorize_log = AuthorizationLog()
|
| 1747 |
authorize_log.item_id = itemId
|
1728 |
authorize_log.item_id = itemId
|