/// <summary>
        /// Gets the oldest lot in a facility of the specified <paramref name="gtin"/>
        /// </summary>
        /// <param name="facility">The facility in which the oldest lot should be found</param>
        /// <param name="gtin">The GTIN of the item to be found</param>
        /// <returns>The <see cref="T:GIIS.DataLayer.ItemLot"/> with the earliest expiry date</returns>
        public ItemLot GetOldestLot(HealthFacility facility, String gtin)
        {
            var oldestLot = from l in
                            (from v in HealthFacilityBalance.GetHealthFacilityBalanceByHealthFacilityCode(facility.Code)
                             where gtin == v.Gtin
                             select new { il = ItemLot.GetItemLotByGtinAndLotNo(gtin, v.LotNumber), hfb = v })
                            where l.il != null
                            orderby l.il.ExpireDate
                            select l;
            var candidateLot = (oldestLot.FirstOrDefault(o => o.hfb.Balance > 0) ?? oldestLot.FirstOrDefault());

            // Candidate lot is null when there is demand (from a kit item) with no lot available!
            if (candidateLot == null)
            {
                // Is it becaues there is no lot in existence?
                var itemLot = ItemLot.GetItemLotByGtin(gtin);
                if (itemLot == null)
                {
                    itemLot = new ItemLot()
                    {
                        Gtin      = gtin,
                        LotNumber = String.Format("N/A-{0}", gtin),
                        Notes     = "Automatically inserted by order system",
                        ItemId    = ItemManufacturer.GetItemManufacturerByGtin(gtin).ItemId
                    };
                    itemLot.Id = ItemLot.Insert(itemLot);
                }

                // Is there no balance?
                var balanceLot = HealthFacilityBalance.GetHealthFacilityBalanceByLotNumber(itemLot.LotNumber);
                if (balanceLot == null)
                {
                    HealthFacilityBalance.Insert(new HealthFacilityBalance()
                    {
                        Gtin = gtin,
                        HealthFacilityCode = facility.Code,
                        LotNumber          = itemLot.LotNumber
                    });
                }
                return(itemLot);
            }
            else
            {
                return(candidateLot.il);
            }
        }
Example #2
0
        /// <summary>
        /// Initialize the test data
        /// </summary>
        public static void InitializeTestDataset()
        {
            /// Transaction type 999 = ID
            var transactionTypes = TransactionType.GetTransactionTypeList();

            if (!transactionTypes.Exists(o => o.Name == "Allocation"))
            {
                TransactionType.Insert(new TransactionType()
                {
                    Name = "Allocation"
                });
            }
            if (!transactionTypes.Exists(o => o.Name == "Transfer"))
            {
                TransactionType.Insert(new TransactionType()
                {
                    Name = "Transfer"
                });
            }


            // GTIN 12345 - PHARMACO OPV
            if (ItemManufacturer.GetItemManufacturerByGtin(GTIN_UNDER_TEST) == null)
            {
                // Item Category 999 = Vaccine
                if (ItemCategory.GetItemCategoryById(VACCINE_CATEGORY_ID) == null)
                {
                    VACCINE_CATEGORY_ID = ItemCategory.Insert(new ItemCategory()
                    {
                        Id         = VACCINE_CATEGORY_ID,
                        Code       = "VACCINE",
                        IsActive   = true,
                        ModifiedBy = 1,
                        ModifiedOn = DateTime.Now,
                        Name       = "Vaccine"
                    });
                }

                // Item 999 - OPV
                if (Item.GetItemById(OPV_ITEM_ID) == null)
                {
                    OPV_ITEM_ID = Item.Insert(new Item()
                    {
                        Code           = "OPV",
                        EntryDate      = DateTime.Now,
                        Id             = OPV_ITEM_ID,
                        ItemCategoryId = VACCINE_CATEGORY_ID,
                        IsActive       = true,
                        ModifiedBy     = 1,
                        ModifiedOn     = DateTime.Now,
                        Name           = "OPV"
                    });
                }

                // Unit of Measure
                if (Uom.GetUomById(DOSE_UOM_ID) == null)
                {
                    DOSE_UOM_ID = Uom.Insert(new Uom()
                    {
                        Id   = DOSE_UOM_ID,
                        Name = "DOSE"
                    });
                }

                // Manufacturer 999 - PHARMACO
                if (Manufacturer.GetManufacturerById(PHARMACO_MANUFACTURER_ID) == null)
                {
                    PHARMACO_MANUFACTURER_ID = Manufacturer.Insert(new Manufacturer()
                    {
                        Id         = PHARMACO_MANUFACTURER_ID,
                        Code       = "PHX",
                        IsActive   = true,
                        ModifiedBy = 1,
                        ModifiedOn = DateTime.Now,
                        Name       = "PHARMACO INC."
                    });
                }

                ItemManufacturer.Insert(new ItemManufacturer()
                {
                    Alt1QtyPer = 20,
                    BaseUom    = "DOSE",
                    BaseUomChildPerBaseUomParent = 10,
                    Gtin           = GTIN_UNDER_TEST,
                    IsActive       = true,
                    ItemId         = OPV_ITEM_ID,
                    ManufacturerId = PHARMACO_MANUFACTURER_ID,
                    ModifiedBy     = 1,
                    ModifiedOn     = DateTime.Now,
                    Price          = 9.99,
                    StorageSpace   = 1,
                    Alt1Uom        = "DOSE",
                    Alt2QtyPer     = 30,
                    Alt2Uom        = "DOSE"
                });
            }

            if (ItemLot.GetItemLotByGtin(GTIN_UNDER_TEST) == null)
            {
                // Item 999 - OPV
                if (Item.GetItemById(OPV_ITEM_ID) == null)
                {
                    OPV_ITEM_ID = Item.Insert(new Item()
                    {
                        Code           = "OPV",
                        EntryDate      = DateTime.Now,
                        Id             = OPV_ITEM_ID,
                        ItemCategoryId = VACCINE_CATEGORY_ID,
                        IsActive       = true,
                        ModifiedBy     = 1,
                        ModifiedOn     = DateTime.Now,
                        Name           = "OPV"
                    });
                }

                ItemLot.Insert(new ItemLot()
                {
                    ExpireDate = DateTime.Now.AddDays(10),
                    Gtin       = GTIN_UNDER_TEST,
                    ItemId     = OPV_ITEM_ID,
                    LotNumber  = GTIN_LOT_USE_FIRST
                });

                // Item Lot 2 - Will be more stock and expires later
                ItemLot.Insert(new ItemLot()
                {
                    ExpireDate = DateTime.Now.AddDays(40),
                    Gtin       = GTIN_UNDER_TEST,
                    ItemId     = OPV_ITEM_ID,
                    LotNumber  = GTIN_LOT_USE_LAST
                });

                // Item Lot 3 - Will trigger low stock
                ItemLot.Insert(new ItemLot()
                {
                    ExpireDate = DateTime.Now.AddDays(80),
                    Gtin       = GTIN_UNDER_TEST,
                    ItemId     = OPV_ITEM_ID,
                    LotNumber  = GTIN_LOT_LOW_BAL
                });
            }

            // Type 3 = DISTRICT
            if (HealthFacilityType.GetHealthFacilityTypeById(6) == null)
            {
                HealthFacilityType.Insert(new HealthFacilityType()
                {
                    Id         = 3,
                    Code       = "DISTRICT",
                    IsActive   = true,
                    ModifiedBy = 1,
                    ModifiedOn = DateTime.Now,
                    Name       = "DISTRICT LEVEL"
                });
            }

            // Type 6 = SDP
            if (HealthFacilityType.GetHealthFacilityTypeById(6) == null)
            {
                HealthFacilityType.Insert(new HealthFacilityType()
                {
                    Id         = 6,
                    Code       = "SDP",
                    IsActive   = true,
                    ModifiedBy = 1,
                    ModifiedOn = DateTime.Now,
                    Name       = "SDP"
                });
            }

            // HF888 = DISTRICT
            if (HealthFacility.GetHealthFacilityByCode("HF888") == null)
            {
                HealthFacility.Insert(new HealthFacility()
                {
                    Id   = 888,
                    Code = "HF888",
                    ColdStorageCapacity = 1000,
                    IsActive            = true,
                    Leaf             = false,
                    ParentId         = HealthFacility.GetHealthFacilityByParentId(0)[0].Id,
                    TopLevel         = false,
                    TypeId           = 3,
                    VaccinationPoint = false,
                    VaccineStore     = true,
                    ModifiedBy       = 1,
                    ModifiedOn       = DateTime.Now
                });
            }

            // GIVE HEALTH FACILITY SOME BALANCE
            var hf888Balances = HealthFacilityBalance.GetHealthFacilityBalanceByHealthFacilityCode("HF888");
            HealthFacilityBalance useFirst = hf888Balances.Find(o => o.Gtin == GTIN_UNDER_TEST && o.LotNumber == GTIN_LOT_USE_FIRST),
                                  useLast  = hf888Balances.Find(o => o.Gtin == GTIN_UNDER_TEST && o.LotNumber == GTIN_LOT_USE_LAST),
                                  lowStock = hf888Balances.Find(o => o.Gtin == GTIN_UNDER_TEST && o.LotNumber == GTIN_LOT_LOW_BAL);

            if (useFirst == null)
            {
                useFirst = new HealthFacilityBalance()
                {
                    Allocated          = 0,
                    Balance            = 500,
                    Distributed        = 0,
                    Gtin               = GTIN_UNDER_TEST,
                    HealthFacilityCode = "HF888",
                    LotNumber          = GTIN_LOT_USE_FIRST,
                    Received           = 0,
                    StockCount         = 500,
                    Used               = 0,
                    Wasted             = 0
                };
                hf888Balances.Add(useFirst);
                HealthFacilityBalance.Insert(useFirst);
            }
            else
            {
                useFirst.Balance    = 500;
                useFirst.StockCount = 500;
                HealthFacilityBalance.Update(useFirst);
            }

            if (useLast == null)
            {
                useLast = new HealthFacilityBalance()
                {
                    Allocated          = 0,
                    Balance            = 1000,
                    Distributed        = 0,
                    Gtin               = GTIN_UNDER_TEST,
                    HealthFacilityCode = "HF888",
                    LotNumber          = GTIN_LOT_USE_LAST,
                    Received           = 0,
                    StockCount         = 1000,
                    Used               = 0,
                    Wasted             = 0
                };
                hf888Balances.Add(useLast);
                HealthFacilityBalance.Insert(useLast);
            }
            else
            {
                useLast.Balance    = 1000;
                useLast.StockCount = 1000;
                HealthFacilityBalance.Update(useLast);
            }

            if (lowStock == null)
            {
                lowStock = new HealthFacilityBalance()
                {
                    Allocated          = 0,
                    Balance            = 10,
                    Distributed        = 0,
                    Gtin               = GTIN_UNDER_TEST,
                    HealthFacilityCode = "HF888",
                    LotNumber          = GTIN_LOT_LOW_BAL,
                    Received           = 0,
                    StockCount         = 10,
                    Used               = 0,
                    Wasted             = 0
                };
                hf888Balances.Add(lowStock);
                HealthFacilityBalance.Insert(lowStock);
            }
            else
            {
                useLast.Balance    = 10;
                useLast.StockCount = 10;
                HealthFacilityBalance.Update(lowStock);
            }

            // HF999 = SDP
            if (HealthFacility.GetHealthFacilityByCode("HF999") == null)
            {
                HealthFacility.Insert(new HealthFacility()
                {
                    Id   = 999,
                    Code = "HF999",
                    ColdStorageCapacity = 100,
                    IsActive            = true,
                    Leaf             = true,
                    ParentId         = HealthFacility.GetHealthFacilityByCode("HF888").Id,
                    TopLevel         = false,
                    TypeId           = 6,
                    VaccinationPoint = true,
                    VaccineStore     = true,
                    ModifiedOn       = DateTime.Now,
                    ModifiedBy       = 1
                });
            }
        }
        /// <summary>
        /// Add an order line to the order defined by <paramref name="order"/>
        /// </summary>
        /// <param name="order">The order to which the line should be added</param>
        /// <param name="gtin">The global trade identification number of the item in the line</param>
        /// <param name="lot">(Optional) The lot number to be used. Note if null is passed in <paramref name="lot"/> then the oldest lot is used first</param>
        /// <param name="qty">The quantity of the item to be added to the order</param>
        /// <param name="uom">(Optional) The base unit of measure. If <paramref name="uom"/> is null then the default UOM for the item described by <paramref name="gtin"/> is used</param>
        /// <returns>The constructed and saved <see cref="T:GIIS.DataLayer.TransferOrderDetail"/></returns>
        /// <remarks>
        /// The add order line function is responsible for adding a new order line to the order detail. This function operates in the following manner:
        /// <list type="ordered">
        /// <item>
        ///     <description>[Guard Condition] If the order passed into the function IS in the “Packed” or “Shipped” state then throw an invalid state exception (sanity check)</description>
        /// </item>
        /// <item>
        ///     <description>Lookup the item by the GTIN provided in the function call.</description>
        /// </item>
        /// <item>
        ///     <description>[Guard Condition] If the lot number is provided, and the lot number is not a valid lot number for the item provided then throw an error code</description>
        /// </item>
        /// <item>
        ///     <description>If the current status of the order to which the detail is to be attached is “Released” then
        ///         <list type="ordered">
        ///             <item>
        ///                 <description>Instantiate a StockManagementLogic BLL class</description>
        ///             </item>
        ///             <item>Allocate the stock using the Allocate method</item>
        ///         </list>
        ///     </description>
        /// </item>
        /// <item>
        ///     <description>Set the unit of measure, quantity, gtin, etc. fields of the TransferOrderDetail instance to the parameters and fields derived from loaded Item.</description>
        /// </item>
        /// <item>
        ///     <description>Save the order line.</description>
        /// </item>
        ///</list>
        /// </remarks>
        public TransferOrderDetail AddOrderLine(TransferOrderHeader order, String gtin, String lot, Int32 qty, Uom uom, Int32 modifiedBy)
        {
            if (order == null)
            {
                throw new ArgumentNullException("order");
            }
            if (String.IsNullOrEmpty(gtin))
            {
                throw new ArgumentNullException("gtin");
            }

            // Sanity check
            if (order.OrderStatus == (int)OrderStatusType.Shipped ||
                order.OrderStatus == (int)OrderStatusType.Cancelled)
            {
                throw new IllegalStateException((OrderStatusType)order.OrderStatus, "TransferOrderHeader", "AddOrderLine");
            }

            // Lookup item by GTIN and optionally lot
            ItemLot item = null;

            if (!String.IsNullOrEmpty(lot))
            {
                item = ItemLot.GetItemLotByGtinAndLotNo(gtin, lot);
            }
            if (item == null)
            {               // not found - We get the item by lot
                item = ItemLot.GetItemLotByGtin(gtin);
                lot  = "*"; // null;
            }

            // Item still null?
            if (item == null)
            {
                throw new InvalidOperationException(String.Format("Cannot locate item with GTIN {0}", gtin));
            }

            // Construct the order detail
            TransferOrderDetail retVal = new TransferOrderDetail()
            {
                ModifiedBy             = modifiedBy,
                ModifiedOn             = DateTime.Now,
                OrderCustomItem        = false,
                OrderDetailDescription = item.ItemObject.Name,
                OrderDetailStatus      = order.OrderStatus,
                OrderGtin         = gtin,
                OrderGtinLotnum   = lot,
                OrderNum          = order.OrderNum,
                OrderQty          = qty,
                OrderQtyInBaseUom = qty,
                OrderUom          = uom.Name
            };

            // HACK: Overcome lack of transaction processing we have to be careful about how we do this
            ItemTransaction allocateTransaction = null;

            // Current state of order is released? We need to allocate this line item
            if (order.OrderStatus == (int)OrderStatusType.Released)
            {
                StockManagementLogic stockLogic = new StockManagementLogic();
                // We need to release this order ... If the lot was null we'll use the oldest lot number
                if (String.IsNullOrEmpty(lot))
                {
                    item = this.GetOldestLot(order.OrderFacilityFromObject, gtin);
                }

                // Allocation of specified lot
                allocateTransaction = stockLogic.Allocate(order.OrderFacilityFromObject, gtin, item.LotNumber, qty, null, modifiedBy);

                // Update order
                retVal.OrderGtinLotnum = item.LotNumber;
            }

            // Save
            retVal.OrderDetailNum = TransferOrderDetail.Insert(retVal);

            // HACK: Update the allocate transaction. This would be cleaned up with a transaction to back out changes (basically do the order detail then allocate)
            if (allocateTransaction != null)
            {
                allocateTransaction.RefId    = retVal.OrderNum.ToString();
                allocateTransaction.RefIdNum = retVal.OrderDetailNum;
                ItemTransaction.Update(allocateTransaction);
            }

            return(retVal);
        }