public static void Add(Asset producedAsset)
 {
     long? producedAssetID = 0;
     _tableAdapter.New(producedAsset.OwnerID, producedAsset.CorpAsset, producedAsset.ItemID, DateTime.UtcNow,
         producedAsset.UnitBuyPricePrecalculated ? producedAsset.UnitBuyPrice : 0,
         Math.Abs(producedAsset.Quantity), ref producedAssetID);
 }
Example #2
0
 public Asset(EMMADataSet.AssetsRow dataRow, Asset container)
 {
     if (dataRow != null)
     {
         _id = dataRow.ID;
         _ownerID = dataRow.OwnerID;
         if (dataRow.CorpAsset)
         {
             _corpAsset = true;
             _ownerID = UserAccount.CurrentGroup.GetCharacter(_ownerID).CorpID;
         }
         _locationID = dataRow.LocationID;
         _itemID = dataRow.ItemID;
         _quantity = dataRow.Quantity;
         _autoConExclude = dataRow.AutoConExclude;
         _reprocExclude = dataRow.ReprocExclude;
         _processed = dataRow.Processed;
         _statusID = dataRow.Status;
         _isContainer = dataRow.IsContainer;
         _container = container;
         _containerID = dataRow.ContainerID;
         _regionID = dataRow.RegionID;
         _systemID = dataRow.SystemID;
         _contents = new AssetList();
         _unitBuyPrice = dataRow.Cost;
         _pureUnitBuyPrice = _unitBuyPrice;
         _gotUnitBuyPrice = dataRow.CostCalc;
         _unitBuyPricePrecalc = dataRow.CostCalc;
         _eveItemInstanceID = dataRow.EveItemID;
     }
 }
 public static void Add(Asset lostAsset)
 {
     long? lostAssetID = 0;
     lock (_tableAdapter)
     {
         _tableAdapter.New(lostAsset.OwnerID, lostAsset.CorpAsset, lostAsset.ItemID, DateTime.UtcNow,
             Math.Abs(lostAsset.Quantity), lostAsset.UnitBuyPrice, lostAsset.UnitValue, ref lostAssetID);
     }
 }
Example #4
0
        public Asset(XmlNode apiAssetData, long ownerID, bool corpAsset, Asset container)
        {
            _id = 0;
            _ownerID = ownerID;
            _corpAsset = corpAsset;
            XmlNode locationNode = apiAssetData.SelectSingleNode("@locationID");
            if (locationNode != null)
            {
                _locationID = long.Parse(locationNode.Value);

                // Translate location ID from a corporate office to a station ID if required.
                if (_locationID >= 66000000 && _locationID < 67000000)
                {
                    // NPC station.
                    _locationID -= 6000001;
                }
                if (_locationID >= 67000000 && _locationID < 68000000)
                {
                    // Conquerable station.
                    _locationID -= 6000000;
                }
            }
            _itemID = int.Parse(apiAssetData.SelectSingleNode("@typeID").Value);
            _eveItemInstanceID = long.Parse(apiAssetData.SelectSingleNode("@itemID").Value);
            _quantity = int.Parse(apiAssetData.SelectSingleNode("@quantity").Value);
            if (apiAssetData.LastChild != null && apiAssetData.LastChild.Name.Equals("rowset"))
            {
                _isContainer = true;
            }
            _autoConExclude = false;
            _reprocExclude = false;
            _processed = false;
            _statusID = 1;
            _contents = new AssetList();
            _container = container;
            _containerID = container.ID;
            _contents = new AssetList();
            _unitBuyPrice = 0;
            _pureUnitBuyPrice = _unitBuyPrice;
            _gotUnitBuyPrice = false;
            _unitBuyPricePrecalc = false;

            if (_isContainer)
            {
                XmlNodeList contents = apiAssetData.SelectNodes("rowset/row");
                foreach (XmlNode asset in contents)
                {
                    _contents.Add(new Asset(asset, ownerID, corpAsset, this));
                }
            }
        }
        /// <summary>
        /// Recursive method to update the supplied assets data table based upon the supplied xml node list.
        /// </summary>
        /// <param name="assetData"></param>
        /// <param name="assetList"></param>
        /// <param name="locationID"></param>
        /// <param name="corc"></param>
        /// <param name="containerID"></param>
        /// <param name="expectedChanges"></param>
        private void UpdateAssets(EMMADataSet.AssetsDataTable assetData, XmlNodeList assetList, long locationID,
            CharOrCorp corc, long containerID, AssetList changes)
        {
            int counter = 0;
            if (containerID == 0)
            {
                UpdateStatus(counter, assetList.Count, "Getting asset data from file", "", false);
            }
            else
            {
                UpdateStatus(-1, -1, "Getting asset data from file", "", false,
                    counter, assetList.Count, "Container progress");
            }

            foreach (XmlNode asset in assetList)
            {
                int itemID;
                long assetID = 0, eveInstanceID, quantity;
                bool isContainer = false, needNewRow = false;

                XmlNode locationNode = asset.SelectSingleNode("@locationID");
                if (locationNode != null)
                {
                    locationID = long.Parse(locationNode.Value);

                    // Translate location ID from a corporate office to a station ID if required.
                    if (locationID >= 66000000 && locationID < 67000000)
                    {
                        // NPC station.
                        locationID -= 6000001;
                    }
                    if (locationID >= 67000000 && locationID < 68000000)
                    {
                        // Conquerable station.
                        locationID -= 6000000;
                    }
                }
                itemID = int.Parse(asset.SelectSingleNode("@typeID").Value,
                    System.Globalization.CultureInfo.InvariantCulture.NumberFormat);
                eveInstanceID = long.Parse(asset.SelectSingleNode("@itemID").Value,
                    System.Globalization.CultureInfo.InvariantCulture.NumberFormat);
                quantity = long.Parse(asset.SelectSingleNode("@quantity").Value,
                    System.Globalization.CultureInfo.InvariantCulture.NumberFormat);
                if (asset.LastChild != null && asset.LastChild.Name.Equals("rowset"))
                {
                    isContainer = true;
                }

                EMMADataSet.AssetsRow assetRow;
                needNewRow = true;

                // Note that if a match is not found for the specific eve instance ID we pass in then
                // EMMA will automatically search for an asset matching all the other parameters.
                if (Assets.AssetExists(assetData, corc == CharOrCorp.Corp ? _corpID : _charID, locationID,
                    itemID, (int)AssetStatus.States.Normal, containerID != 0, containerID, isContainer,
                    false, !isContainer, false, true, eveInstanceID, ref assetID))
                {
                    needNewRow = false;
                }
                else if(!isContainer)
                {
                    // We havn't actually updated the database with anything yet so we may already have a
                    // matching item stack in memory but not in the database. Check for that here.
                    DataRow[] data =
                        assetData.Select("ItemID = " + itemID + " AND OwnerID = " + _charID + " AND CorpAsset = " +
                        (corc == CharOrCorp.Corp ? 1 : 0) + " AND LocationID = " + locationID +
                        " AND Status = " + (int)AssetStatus.States.Normal + " AND ContainerID = " + containerID +
                        " AND EveItemID = " + eveInstanceID);
                    if (data != null && data.Length > 0)
                    {
                        needNewRow = false;
                        assetID = ((EMMADataSet.AssetsRow)data[0]).ID;
                    }
                }

                Asset change = null;
                if (!needNewRow)
                {
                    assetRow = assetData.FindByID(assetID);

                    if (assetRow.Processed)
                    {
                        // Row is already in the database but has been processed so just add the current
                        // quantity to the row.
                        // (i.e. there are multiple stacks of the same item in the same location in-game
                        // EMMA merges these since we don't care how things are stacked and it makes
                        // things a little easier.)
                        assetRow.Quantity = assetRow.Quantity + quantity;
                        // We're stacking multiple eve item instances so just set the eve item ID to zero.
                        assetRow.EveItemID = 0;

                        // Store the changes that are being made to the quantity of
                        // items here.
                        // This means that once the update processing is complete, we
                        // can try and work out where these items came from.
                        #region Remember changes to item quantities
                        changes.ItemFilter = "ID = " + assetRow.ID;
                        if (changes.FiltredItems.Count > 0)
                        {
                            change = (Asset)changes.FiltredItems[0];
                            change.Quantity += quantity;
                            change.EveItemInstanceID = 0;
                            if (change.Quantity == 0) { changes.ItemFilter = ""; changes.Remove(change); }
                        }
                        else
                        {
                            change = new Asset(assetRow);
                            change.Quantity = quantity;
                            change.Processed = false;
                            changes.Add(change);
                        }
                        #endregion
                    }
                    else
                    {
                        if (assetRow.Quantity == quantity)
                        {
                            // The row already exists in the database and quantity is the same so
                            // set the processed flag on the database directly and remove the row
                            // from the dataset without setting it to be deleted when the database
                            // is updated.
                            // Note the processed flag MUST be set on the database for later routines
                            // to work correctly. (e.g. Assets.ProcessSellOrders)
                            if (assetRow.EveItemID != 0)
                            {
                                Assets.SetProcessedFlag(assetID, true);
                                assetData.RemoveAssetsRow(assetRow);
                            }
                            else
                            {
                                // If Eve instance ID is not yet set then set it.
                                Assets.SetProcessedFlag(assetID, true);
                                assetRow.Processed = true;
                                assetRow.EveItemID = eveInstanceID;
                            }
                        }
                        else if (assetRow.Quantity != quantity)
                        {
                            // The row already exists in the database, has not yet been processed
                            // and the quantity does not match what we've got from the XML.

                            // Store the changes that are being made to the quantity of
                            // items here.
                            // This means that once the update processing is complete, we
                            // can try and work out where these items came from.
                            #region Remember changes to item quantities
                            change = new Asset(assetRow);
                            change.Quantity = quantity - assetRow.Quantity;
                            change.EveItemInstanceID = eveInstanceID;
                            change.Processed = false;
                            changes.Add(change);
                            #endregion

                            // All we need to do is update the quantity and set the processed flag.
                            assetRow.Quantity = quantity;
                            assetRow.Processed = true;
                            assetRow.EveItemID = eveInstanceID;
                            // Also set the processed flag on the database directly. This will
                            // stop us from picking up this row later on (e.g. Assets.ProcessSellOrders)
                            Assets.SetProcessedFlag(assetID, true);
                        }
                    }
                }
                else
                {
                    // The row does not currently exist in the database so we need to create it.
                    assetRow = assetData.NewAssetsRow();
                    //assetRow.OwnerID = _charID;
                    assetRow.OwnerID = corc == CharOrCorp.Corp ? _corpID : _charID;
                    assetRow.CorpAsset = corc == CharOrCorp.Corp;
                    assetRow.ItemID = itemID;
                    assetRow.EveItemID = eveInstanceID;
                    assetRow.LocationID = locationID;
                    assetRow.Status = 1;
                    assetRow.Processed = true;
                    assetRow.AutoConExclude = false;
                    assetRow.ReprocExclude = false;
                    assetRow.Cost = 0;
                    assetRow.CostCalc = false;
                    assetRow.BoughtViaContract = false;

                    long systemID = 0, regionID = 0;
                    if (locationID >= 30000000 && locationID < 40000000)
                    {
                        systemID = locationID;
                        EveDataSet.mapSolarSystemsRow system = SolarSystems.GetSystem(locationID);
                        if (system != null)
                        {
                            regionID = system.regionID;
                        }
                        else
                        {
                            new EMMAEveAPIException(ExceptionSeverity.Warning, "Asset row added with unknown " +
                                "solar system ID (" + locationID + ")");
                        }
                    }
                    else
                    {
                        EveDataSet.staStationsRow station = null;
                        try
                        {
                            station = Stations.GetStation(locationID);
                        }
                        catch (EMMADataMissingException) { }

                        if (station != null)
                        {
                            systemID = station.solarSystemID;
                            regionID = station.regionID;
                        }
                        else
                        {
                            new EMMAEveAPIException(ExceptionSeverity.Warning, "Asset row added with unknown " +
                                "station ID (" + locationID + ")");
                        }
                    }
                    assetRow.SystemID = systemID;
                    assetRow.RegionID = regionID;
                    assetRow.Quantity = quantity;
                    assetRow.ContainerID = containerID;
                    assetRow.IsContainer = isContainer;
                    if (isContainer)
                    {
                        // If this asset is a container and has child assets then we must add it to the
                        // database now and get the correct ID number.
                        // (Because IDs are assigned by the database itself)
                        assetID = Assets.AddRowToDatabase(assetRow);
                    }
                    else
                    {
                        // Otherwise, we can just add it to the data table to be stored later along with
                        // everything else.
                        assetData.AddAssetsRow(assetRow);
                    }

                    // Store the changes that are being made to the quantity of
                    // items here.
                    // This means that once the update processing is complete, we
                    // can try and work out where these items came from.
                    #region Remember changes to item quantities
                    change = new Asset(assetRow);
                    if (isContainer) { change.ID = assetID; }
                    change.Quantity = quantity;
                    change.Processed = false;
                    changes.Add(change);
                    #endregion
                }

                if (isContainer)
                {
                    XmlNodeList contained = asset.SelectNodes("rowset/row");
                    UpdateAssets(assetData, contained, locationID, corc, assetID, changes);
                }

                counter++;
                if (containerID == 0)
                {
                    UpdateStatus(counter, assetList.Count, "Getting asset data from file", "", false);
                }
                else
                {
                    UpdateStatus(-1, -1, "Getting asset data from file", "", false,
                        counter, assetList.Count, "Container progress");
                }
            }
        }
        /// <summary>
        /// This is used for calculating per unit profit when adding sell transactions from the API. 
        /// It should not be used outside of that context.
        /// </summary>
        /// <param name="transData"></param>
        /// <param name="newRow"></param>
        /// <returns></returns>
        public static decimal CalcProfit(long ownerID, EMMADataSet.TransactionsDataTable transData,
            EMMADataSet.TransactionsRow newRow, DateTime assetsEffectiveDate)
        {
            decimal retVal = 0;
            EMMADataSet.AssetsDataTable existingAssets = new EMMADataSet.AssetsDataTable();
            long stationID = newRow.StationID;

            //int ownerID = corp ? UserAccount.CurrentGroup.GetCharacter(charID).CorpID : charID;
            bool exDiag = UserAccount.Settings.ExtendedDiagnostics;

            StringBuilder process = new StringBuilder("");

            try
            {
                if (assetsEffectiveDate.CompareTo(newRow.DateTime) > 0)
                {
                    // If assets have been updated from the API after this transaction
                    // occured then the assets are already gone and we cannot work out
                    // the profit.

                    // Note: in future, we could try and work it out from 'AssetsLost'
                    if (exDiag)
                    {
                        process.Append("Effective date of last assets update is after this transaction's date/time.");
                        process.Append(assetsEffectiveDate);
                        process.Append(" / ");
                        process.Append(newRow.DateTime);
                    }
                }
                else
                {

                    // If there are matching assets for the specified character or corp at the
                    // transaction location then use the cost of those assets to calculate profit.
                    List<AssetAccessParams> assetAccessParams = new List<AssetAccessParams>();
                    assetAccessParams.Add(new AssetAccessParams(ownerID));
                    Assets.GetAssets(existingAssets, assetAccessParams, stationID,
                        Stations.GetStation(stationID).solarSystemID, newRow.ItemID);
                    if (existingAssets != null)
                    {
                        decimal totalBuyPrice = 0;
                        long qToFind = newRow.Quantity;
                        foreach (EMMADataSet.AssetsRow existingAsset in existingAssets)
                        {
                            // If possible, use data from assets that are currently for sale via the market.
                            if (existingAsset.Status == (int)AssetStatus.States.ForSaleViaMarket &&
                                existingAsset.Quantity > 0)
                            {
                                Asset asset = new Asset(existingAsset, null);
                                long q = Math.Min(qToFind, asset.Quantity);
                                qToFind -= q;
                                totalBuyPrice += asset.UnitBuyPrice * q;

                                // Adjust assets data in accordance with items that were sold.
                                long deltaQuantity = -1 * q;
                                // Note, since we're removing assets, the cost and costcalc parameters
                                // will be ignored.
                                Assets.ChangeAssets(ownerID, newRow.StationID, newRow.ItemID,
                                    existingAsset.ContainerID, existingAsset.Status, existingAsset.AutoConExclude,
                                    deltaQuantity, 0, false);
                            }
                        }
                        // If we could not find enough assets 'ForSaleViaMarket' to match the
                        // sell transaction then look at assets that are in transit or just sat
                        // in the hanger.
                        // (Don't use assets that are containers!)
                        if (qToFind > 0)
                        {
                            foreach (EMMADataSet.AssetsRow existingAsset in existingAssets)
                            {
                                if (existingAsset.Status != (int)AssetStatus.States.ForSaleViaMarket &&
                                    existingAsset.Status != (int)AssetStatus.States.ForSaleViaContract &&
                                    existingAsset.Quantity > 0 &&
                                    !existingAsset.IsContainer)
                                {
                                    Asset asset = new Asset(existingAsset, null);
                                    long q = Math.Min(qToFind, asset.Quantity);
                                    qToFind -= q;
                                    totalBuyPrice += asset.UnitBuyPrice * q;

                                    // Adjust assets data in accordance with items that were sold.
                                    long deltaQuantity = -1 * q;
                                    // Note, since we're removing assets, the cost and costcalc parameters
                                    // will be ignored.
                                    Assets.ChangeAssets(ownerID, newRow.StationID, newRow.ItemID,
                                        existingAsset.ContainerID, existingAsset.Status, existingAsset.AutoConExclude,
                                        deltaQuantity, 0, false);
                                }
                            }
                        }
                        if (qToFind < newRow.Quantity)
                        {
                            decimal unitBuyPrice = totalBuyPrice / (newRow.Quantity - qToFind);
                            retVal = newRow.Price - unitBuyPrice;
                        }
                        if (qToFind > 0)
                        {
                            // If any of the transaction quantity could not be accounted for then simply send
                            // the 'normal' asset stack at this location to a negative quantity.
                            Assets.ChangeAssets(ownerID, newRow.StationID, newRow.ItemID,
                                 0, (int)AssetStatus.States.Normal, false, qToFind * -1, 0, false);
                        }
                    }
                    else
                    {
                        if (exDiag)
                        {
                            process.Append(Names.GetName(ownerID));
                            process.Append(" has no ");
                            process.Append(Items.GetItemName(newRow.ItemID));
                            process.Append("'s at ");
                            process.Append(Stations.GetStationName(newRow.StationID));
                            process.Append(". Consquently, no profit value can be calculated right now. This transaction has been flagged to have it's profit calculated when the next assets update occurs.");
                        }
                        // If there are no assets at the station where the sell took place then flag
                        // the transaction to have it's profit calculated when the next assets
                        // update is performed.
                        // Also, set the quantity of assets at this location negative.
                        newRow.CalcProfitFromAssets = true;

                        Assets.ChangeAssets(ownerID, newRow.StationID, newRow.ItemID, 0,
                            (int)AssetStatus.States.Normal, false, newRow.Quantity * -1, 0, false);
                    }
                }
            }
            catch (Exception ex)
            {
                new EMMADataException(ExceptionSeverity.Error,
                    "Problem calculating profit for new sell transaction.", ex);
            }

            return retVal;
        }
Example #7
0
        public static decimal GetAssetsValue(long ownerID, List<int> excludedStates)
        {
            decimal retVal = 0;
            List<AssetAccessParams> accessParams = new List<AssetAccessParams>();
            accessParams.Add(new AssetAccessParams(ownerID));
            EMMADataSet.AssetsDataTable assets = GetAssets(accessParams);
            if (excludedStates == null) { excludedStates = new List<int>(); }
            //StreamWriter log = File.CreateText("C:\\NAVAssets.txt");
            //try
            //{
                foreach (EMMADataSet.AssetsRow asset in assets)
                {
                    // Use The forge to value items if possible.
                    //decimal value = UserAccount.CurrentGroup.ItemValues.GetItemValue(asset.ItemID, 10000002, true);
                    //retVal += value * asset.Quantity;
                    if (!excludedStates.Contains(asset.Status))
                    {
                        retVal += new Asset(asset).TotalValue;
                    }
                    //log.WriteLine(Items.GetItemName(asset.ItemID) + ", " + asset.Quantity + ", " + value);
                }
            //}
            //finally
            //{
            //    log.Close();
            //}

            return retVal;
        }
Example #8
0
        /// <summary>
        /// This is called after an import of XML asset data but before the changes are commited
        /// to the database.
        /// The aim is to try to work out which assets have simply moved location and which have 
        /// been added or lost. Additionally, if items have moved, update the cost of the item 
        /// stack appropriately.
        /// </summary>
        /// <param name="assetData">The datatable containing the changes that will be applied to the assets database</param>
        /// <param name="charID"></param>
        /// <param name="corp"></param>
        /// <param name="changes">Contains changes in quantities of item stacks that were in the XML.</param>
        /// <param name="gained">A list of items that have been gained from 'nowhere'</param>
        /// <param name="lost">A list of items that have been totally lost from the owner's asset data.</param>
        public static void AnalyseChanges(EMMADataSet.AssetsDataTable assetData, long ownerID,
            AssetList changes, out AssetList gained, out AssetList lost)
        {
            // Note that 'changes' will only include items that exist in the XML from the API. i.e. Any
            // stacks that have been completely removed from a location will not show up.
            // To get these removed assets, we need to retrieve any 'unprocessed' assets from the
            // assetData table.
            gained = new AssetList();
            lost = new AssetList();

            // Add any unprocessed asset stacks to the 'changes' collection.
            // Although the main data changes have not yet been supplied to the database,
            // the processed flags have been set for the relevant asset rows.
            // This means that we can get the list of unprocessed assets direct from
            // the database.
            List<AssetAccessParams> accessParams = new List<AssetAccessParams>();
            accessParams.Add(new AssetAccessParams(ownerID));
            EMMADataSet.AssetsDataTable unprocMatches = new EMMADataSet.AssetsDataTable();
            Assets.GetAssets(unprocMatches, accessParams, 0, 0, 0, 0, false);

            foreach (EMMADataSet.AssetsRow unprocMatch in unprocMatches)
            {
                Asset change = new Asset(unprocMatch);
                // Ignore any assets 'for sale via contract' or 'in transit'
                if (change.Quantity != 0 && change.StatusID != (int)AssetStatus.States.ForSaleViaContract &&
                    change.StatusID != (int)AssetStatus.States.InTransit)
                {
                    change.Quantity *= -1; // These assets are effectively missing so invert the quantity.
                    changes.Add(change);
                }
            }

            // Note 'changes2' is a list of the same items as 'changes'.
            // It is needed because the filter functionallity changes the list which we cannot
            // do within the main foreach loop.
            AssetList changes2 = new AssetList();
            foreach (Asset change in changes)
            {
                changes2.Add(change);
            }

            // See if any of our 'missing' assets match transactions that are marked to have thier profit
            // calculated during an assets update.
            #region Update transactions with CalcProfitFromAssets flag
            EMMADataSet.TransactionsDataTable transData = new EMMADataSet.TransactionsDataTable();
            Transactions.AddTransByCalcProfitFromAssets(transData,
                UserAccount.CurrentGroup.GetFinanceAccessParams(APIDataType.Transactions), 0, true);

            foreach (EMMADataSet.TransactionsRow trans in transData)
            {
                long quantityRemaining = trans.Quantity;
                decimal totalBuyPrice = 0;

                changes.ItemFilter = "ItemID = " + trans.ItemID + " AND Quantity < 0";
                foreach (Asset change in changes.FiltredItems)
                {
                    // If we get a match then use the missing items's cost to calculate the
                    // transaction's profit.
                    // Note that we don't need to adjust any item quantities since either the
                    // changes have already been made or the item stack is 'unprocessed' and will
                    // be cleared out anyway.
                    long deltaQ = Math.Min(Math.Abs(change.Quantity), quantityRemaining);
                    // Adjust the quantity of the 'missing' items.
                    change.Quantity += deltaQ;
                    quantityRemaining -= deltaQ;
                    // Because this transaction's asset quantity change will have been made
                    // back when the transaction was processed, we will have some unexpected
                    // added items as well.
                    //
                    // E.g. Consider station A and B. At A, there are 2 units of item X, at B
                    // there is nothing.
                    // At a later date, the player moves 2 of X from A to B and sells it.
                    // When the sell transaction is processed, station B will be set to -2
                    // units of X and the transaction will be set as 'CalcProfitFromAssets'.
                    // When the asset update occurs, it will show zero for both locations so
                    // they will be unprocessed.
                    // This will result in 2 unexplained units gained at station B and 2 lost
                    // at station A. (We've gone from A=2,B=-2 to A=0 B=0)
                    changes2.ItemFilter = "ItemID = " + trans.ItemID + " AND LocationID = " + trans.StationID +
                        " AND Status = 1";
                    if (changes2.FiltredItems.Count > 0)
                    {
                        // We've already accounted for the cost of items, etc so just reduce the
                        // quantity.
                        changes2[0].Quantity -= deltaQ;
                    }

                    totalBuyPrice += (change.UnitBuyPrice * deltaQ);

                    if (quantityRemaining != trans.Quantity)
                    {
                        // We've found enough missing items to match this transaction either completely
                        // or partially so calculate it's profit and set it as completed.
                        trans.CalcProfitFromAssets = false;
                        trans.SellerUnitProfit = trans.Price - (totalBuyPrice / trans.Quantity);
                    }
                }
            }
            /*
            foreach (Asset change in changes)
            {
                // Note: because we are changing quantity within the foreach loop
                // we don't use the filter on the AssetList.
                // Instead, just use this if condition each time around.
                if (change.Quantity < 0 && !noTransItemIDs.Contains(change.ItemID))
                {
                    // If we get a match then use the missing items's cost to calculate the
                    // transaction's profit.
                    // Note that we don't need to adjust any item quantities since either the
                    // changes have already been made or the item stack is 'unprocessed' and will
                    // be cleared out anyway.
                    Transactions.AddTransByCalcProfitFromAssets(transData,
                        UserAccount.CurrentGroup.GetFinanceAccessParams(APIDataType.Transactions),
                        change.ItemID, true);
                    if (transData.Count == 0) { noTransItemIDs.Add(change.ItemID); }
                    foreach (EMMADataSet.TransactionsRow trans in transData)
                    {
                        if (trans.ItemID == change.ItemID && !completedTrans.Contains(trans.ID))
                        {
                            long quantityRemaining = trans.Quantity;
                            TransProcessData data = new TransProcessData();
                            if (processData.ContainsKey(trans.ID))
                            {
                                data = processData[trans.ID];
                                quantityRemaining = data.QuantityRemaining;
                            }
                            else
                            {
                                data.QuantityMatched = 0;
                                data.QuantityRemaining = trans.Quantity;
                                data.TotalBuyPrice = 0;
                                processData.Add(trans.ID, data);
                            }

                            long deltaQ = Math.Min(Math.Abs(change.Quantity), quantityRemaining);
                            // Adjust the quantity of the 'missing' items.
                            change.Quantity += deltaQ;
                            // Because this transaction's asset quantity change will have been made
                            // back when the transaction was processed, we will have some unexpected
                            // added items as well.
                            //
                            // E.g. Consider station A and B. At A, there are 2 units of item X, at B
                            // there is nothing.
                            // At a later date, the player moves 2 of X from A to B and sells it.
                            // When the sell transaction is processed, station B will be set to -2
                            // units of X and the transaction will be set as 'CalcProfitFromAssets'.
                            // When the asset update occurs, it will show zero for both locations so
                            // they will be unprocessed.
                            // This will result in 2 unexplained units gained at station B and 2 lost
                            // at station A. (We've gone from A=2,B=-2 to A=0 B=0)
                            changes2.ItemFilter = "ItemID = " + trans.ItemID + " AND LocationID = " + trans.StationID;
                            foreach (Asset change2 in changes2)
                            {
                                if (change2.Quantity > 0)
                                {
                                    // We've already accounted for the cost of items, etc so just reduce the
                                    // quantity.
                                    change2.Quantity -= deltaQ;
                                }
                            }

                            data.QuantityRemaining = data.QuantityRemaining - deltaQ;
                            data.QuantityMatched = data.QuantityMatched + deltaQ;
                            data.TotalBuyPrice = data.TotalBuyPrice + (change.UnitBuyPrice * deltaQ);

                            if (data.QuantityRemaining == 0)
                            {
                                // We've found enough missing items to match this transaction completely
                                // so calculate it's profit and set it as completed.
                                trans.CalcProfitFromAssets = false;
                                trans.SellerUnitProfit = trans.Price - (data.TotalBuyPrice / data.QuantityMatched);
                                completedTrans.Add(trans.ID);
                                if (uncompletedTrans.Contains(trans.ID)) { uncompletedTrans.Remove(trans.ID); }
                            }
                            else
                            {
                                // We havn't found enough missing items to completely match this transaction
                                // yet so add to to the list of uncompleted transactions.
                                uncompletedTrans.Add(trans.ID);
                            }
                        }
                    }
                }
            }

            // Calculate profits as best we can for any 'uncompleted' transactions.
            // i.e. those that we did not have enough missing items to match completely.
            foreach (long transID in uncompletedTrans)
            {
                EMMADataSet.TransactionsRow trans = transData.FindByID(transID);
                if (trans != null && processData.ContainsKey(transID))
                {
                    TransProcessData data = processData[transID];
                    trans.CalcProfitFromAssets = false;
                    trans.SellerUnitProfit = trans.Price - (data.TotalBuyPrice / data.QuantityMatched);
                }
            }
             * */
            // Update transactions database
            Transactions.Store(transData);
            #endregion

            // Work through the list of changes.
            //
            // If items have been added then see if there is a matching quantity that has been removed
            // somwhere. If so, use the old asset stack cost to set the cost for the new asset stack.
            // If we can't find a match for any added items then add them to the 'gained' list.
            //
            // By definititon, any items that have been removed and match stacks added elsewhere will
            // be matched by the above process. Any removed items that are left over are added to the
            // 'lost' list of assets.
            changes.ItemFilter = "";

            // If we're in manufacturing mode then we don't want to try and match
            // lost assets with gained assets until after the user has selected
            // what has been built, etc.
            if (!UserAccount.Settings.ManufacturingMode)
            {
                #region Try and match gains in one place against losses in another.
                List<int> zeroLossItemIDs = new List<int>();
                foreach (Asset change in changes)
                {
                    if (change.Quantity > 0 && !zeroLossItemIDs.Contains(change.ItemID))
                    {
                        int itemID = change.ItemID;
                        long locationID = change.LocationID;

                        changes2.ItemFilter = "ItemID = " + itemID + " AND Quantity < 0";
                        if (changes2.FiltredItems.Count == 0)
                        {
                            if (!zeroLossItemIDs.Contains(change.ItemID)) { zeroLossItemIDs.Add(change.ItemID); }
                        }

                        foreach (Asset change2 in changes2.FiltredItems)
                        {
                            if (change.Quantity > 0 && change2.Quantity < 0)
                            {
                                // Get the asset data lines associated with the two changes in asset quantities
                                // that we have found.
                                //bool got1 = Assets.AssetExists(assetData, charID, corp, locationID, itemID,
                                //    change.StatusID, change.ContainerID != 0, change.ContainerID, change.IsContainer,
                                //    true, true, change.AutoConExclude, ref assetID1);
                                //bool got2 = Assets.AssetExists(assetData, charID, corp, change2.LocationID, itemID,
                                //    change2.StatusID, change2.ContainerID != 0, change2.ContainerID, change2.IsContainer,
                                //    true, true, change2.AutoConExclude, ref assetID2);
                                Assets.AddAssetToTable(assetData, change.ID);
                                Assets.AddAssetToTable(assetData, change2.ID);

                                EMMADataSet.AssetsRow row1 = assetData.FindByID(change.ID);
                                EMMADataSet.AssetsRow row2 = assetData.FindByID(change2.ID);
                                Asset a1 = new Asset(row1, null);
                                Asset a2 = new Asset(row2, null);
                                long thisAbsDeltaQ = Math.Min(Math.Abs(change.Quantity), Math.Abs(change2.Quantity));

                                // If the rows are processed then the actual movement of items has already happened
                                // so we don't need to adjust quantities.
                                // If they are not processed then we need to adjust the quantities now.
                                if (!row1.Processed) { row1.Quantity += thisAbsDeltaQ; }
                                if (!row2.Processed) { row2.Quantity -= thisAbsDeltaQ; }

                                // If the stack we're adding to now has zero items in it then we can just
                                // remove it. Otherwise we need to work out the value of the new stack.
                                if (row1.Quantity > 0)
                                {
                                    // Calculate the cost of items in the new stack based on the
                                    // cost of items from the old stack.
                                    decimal newCost = 0;
                                    newCost = ((a1.TotalBuyPrice) + (a2.UnitBuyPrice * thisAbsDeltaQ)) /
                                        (a1.Quantity + thisAbsDeltaQ);
                                    row1.Cost = newCost;
                                    row1.CostCalc = true;
                                }
                                else if (row1.Quantity == 0) { row1.Delete(); }
                                if (row2.Quantity == 0) { row2.Delete(); }

                                change.Quantity -= thisAbsDeltaQ;
                                change2.Quantity += thisAbsDeltaQ;
                            }
                        }

                    }
                }
                #endregion
            }

            // We have some items left over that could not be accounted for from losses/gains
            // elsewhere. Add these to the appropriate 'lost' or 'gained' list.
            #region Add remaining unexplained changes to the appropriate lost/gained list
            foreach (Asset change in changes)
            {
                if (change.Quantity != 0)
                {
                    Asset unexplained = new Asset();
                    unexplained.ID = change.ID;
                    unexplained.ItemID = change.ItemID;
                    unexplained.LocationID = change.LocationID;
                    unexplained.Quantity = change.Quantity;
                    unexplained.StatusID = change.StatusID;
                    unexplained.IsContainer = change.IsContainer;
                    unexplained.Container = change.Container;
                    unexplained.AutoConExclude = change.AutoConExclude;
                    unexplained.OwnerID = change.OwnerID;
                    if (change.UnitBuyPricePrecalculated)
                    {
                        unexplained.UnitBuyPrice = change.UnitBuyPrice;
                        unexplained.UnitBuyPricePrecalculated = true;
                    }
                    else
                    {
                        unexplained.UnitBuyPrice = 0;
                        unexplained.UnitBuyPricePrecalculated = false;
                    }
                    if (change.Quantity > 0)
                    {
                        // If the unexplained assets are for sale via contract or in transit then we
                        // would expect them not to show up if they are in the same state as before.
                        // This being the case, we do not need to add them to the list of unexplained items.
                        if (change.StatusID != (int)AssetStatus.States.ForSaleViaContract &&
                            change.StatusID != (int)AssetStatus.States.InTransit) { gained.Add(unexplained); }
                    }
                    else
                    {
                        // If the unexplained assets are for sale via contract or in transit then we
                        // would expect them not to show up if they are in the same state as before.
                        // This being the case, we do not need to add them to the list of unexplained items.
                        if (change.StatusID != (int)AssetStatus.States.ForSaleViaContract &&
                            change.StatusID != (int)AssetStatus.States.InTransit) { lost.Add(unexplained); }
                    }
                }
            }
            #endregion
        }
Example #9
0
        /// <summary>
        /// Update the assets table based on the transactions meeting the specified criteria.
        /// </summary>
        /// <param name="charID"></param>
        /// <param name="corpID"></param>
        /// <param name="useCorp"></param>
        /// <param name="minimumTransID"></param>
        /// <param name="includeTransAfter"></param>
        /// <returns></returns>
        private static long UpdateFromTransactions(EMMADataSet.AssetsDataTable assetsData,
            AssetList changes, long charID, long corpID, bool useCorp, long minimumTransID,
            DateTime includeTransAfter)
        {
            long maxID = 0;
            long ownerID = useCorp ? corpID : charID;

            EMMADataSet.TransactionsDataTable transactions = new EMMADataSet.TransactionsDataTable();
            transactions = GetTransactions(charID, corpID, useCorp, minimumTransID, includeTransAfter);

            foreach (EMMADataSet.TransactionsRow trans in transactions)
            {
                // If the ID is greater than 9000000000000000000 then it must have been created by EMMA as part of
                // an item exchange contract. These should be ignored here.
                if (trans.ID < 9000000000000000000)
                {
                    int deltaQuantity = trans.Quantity;
                    if (trans.SellerID == ownerID) { deltaQuantity *= -1; }

                    // Change this to not actually make the change in the database. Instead, use the
                    // asset data table passed in and record the changes made in the 'changes' list.

                    /*ChangeAssets(charID, useCorp, trans.StationID, trans.ItemID, 0, (int)AssetStatus.States.Normal,
                        false, deltaQuantity, (deltaQuantity > 0 ? trans.Price : 0), deltaQuantity > 0);*/
                    long assetID = 0;
                    EMMADataSet.AssetsRow asset = null;

                    AssetExists(assetsData, ownerID, trans.StationID, trans.ItemID,
                        (int)AssetStatus.States.Normal, false, 0, false, false, true, false, true, 0, ref assetID);

                    if (assetID != 0)
                    {
                        // Asset stack already exists in database and/or datatable, modify it
                        // based upon the transaction data.
                        asset = assetsData.FindByID(assetID);
                        asset.Quantity += deltaQuantity;
                        if (deltaQuantity > 0)
                        {
                            Asset logicalAsset = new Asset(asset);
                            asset.CostCalc = true;
                            asset.Cost = (logicalAsset.TotalBuyPrice + (trans.Price * trans.Quantity)) /
                                (logicalAsset.Quantity + trans.Quantity);
                        }
                        Asset chg = new Asset(asset);
                        chg.Quantity = deltaQuantity;
                        changes.Add(chg);
                    }
                    else
                    {
                        // Asset does not exist in database so add it to the datatable.
                        asset = assetsData.NewAssetsRow();
                        asset.Quantity = deltaQuantity;
                        asset.AutoConExclude = false;
                        asset.ContainerID = 0;
                        asset.CorpAsset = useCorp;
                        asset.Cost = trans.Price;
                        asset.CostCalc = true;
                        asset.IsContainer = false;
                        asset.ItemID = trans.ItemID;
                        asset.EveItemID = 0;
                        asset.LocationID = trans.StationID;
                        asset.OwnerID = charID;
                        asset.Processed = true;
                        asset.RegionID = trans.RegionID;
                        asset.ReprocExclude = false;
                        asset.Status = (int)AssetStatus.States.Normal;
                        asset.SystemID = Stations.GetStation(trans.StationID).solarSystemID;
                        asset.BoughtViaContract = false;
                        assetsData.AddAssetsRow(asset);
                        changes.Add(new Asset(asset));
                    }

                    if (trans.ID > maxID) { maxID = trans.ID; }
                }
            }

            return maxID;
        }
Example #10
0
        /// <summary>
        /// This ensures that items in sell orders appear in the list of the player's assets.
        /// It is called just after new asset XML from the API has been processed but before
        /// the update is applied to the database.
        /// </summary>
        public static void ProcessSellOrders(EMMADataSet.AssetsDataTable assetData, AssetList changes,
            long ownerID)
        {
            List<int> itemIDs = new List<int>();
            itemIDs.Add(0);
            List<long> stationIDs = new List<long>();
            stationIDs.Add(0);
            List<AssetAccessParams> accessParams = new List<AssetAccessParams>();
            accessParams.Add(new AssetAccessParams(ownerID));
            // Get active sell orders
            OrdersList sellOrders = Orders.LoadOrders(accessParams, itemIDs, stationIDs, 999, "Sell");
            EMMADataSet.AssetsRow changedAsset = null;
            // Note that modifiedAssets is indexed first by itemID and second by stationID
            Dictionary<int, Dictionary<long, AssetInfo>> modifiedAssets = new Dictionary<int, Dictionary<long, AssetInfo>>();

            foreach (Order sellOrder in sellOrders)
            {
                bool foundMatch = false;
                long assetID = 0;

                // If there is already an asset row with a state of 'ForSaleViaMarket' in the same location,
                // and with the same item type then check quantity.
                // If it matches then just set to processed and move on.
                // If it does not then record the difference in quantities and go to the next order.
                // If we can't find a match then add a new asset row and record the items gained.
                if (Assets.AssetExists(assetData, ownerID, sellOrder.StationID, sellOrder.ItemID,
                    (int)AssetStatus.States.ForSaleViaMarket, false, 0, false, false, true, true,
                    true, 0, ref assetID))
                {
                    foundMatch = true;
                }
                else
                {
                    DataRow[] data =
                        assetData.Select("ItemID = " + sellOrder.ItemID + " AND OwnerID = " +
                        ownerID.ToString() + " AND LocationID = " + sellOrder.StationID +
                        " AND Status = " + (int)AssetStatus.States.ForSaleViaMarket);
                    if (data != null && data.Length > 0)
                    {
                        foundMatch = true;
                        assetID = ((EMMADataSet.AssetsRow)data[0]).ID;
                    }
                }

                if (foundMatch)
                {
                    changedAsset = assetData.FindByID(assetID);
                    if (changedAsset.Quantity != sellOrder.RemainingVol)
                    {
                        // If the quantities do not match then store how many units we are removing
                        // from the stack, the most likely cause is more than one sell order for
                        // this item in this location and if we know how many units we've removed
                        // We can make sure that the other order(s) quantity matches up.
                        Dictionary<long, AssetInfo> itemDeltaVol = new Dictionary<long, AssetInfo>();
                        if (modifiedAssets.ContainsKey(sellOrder.ItemID))
                        {
                            itemDeltaVol = modifiedAssets[sellOrder.ItemID];
                        }
                        else
                        {
                            modifiedAssets.Add(sellOrder.ItemID, itemDeltaVol);
                        }
                        if (itemDeltaVol.ContainsKey(sellOrder.StationID))
                        {
                            AssetInfo info = itemDeltaVol[sellOrder.StationID];
                            info.quantity += sellOrder.RemainingVol - changedAsset.Quantity;
                            itemDeltaVol[sellOrder.StationID] = info;
                            changedAsset.Quantity += sellOrder.RemainingVol;
                        }
                        else
                        {
                            AssetInfo info = new AssetInfo();
                            info.quantity = sellOrder.RemainingVol - changedAsset.Quantity;
                            info.assetID = changedAsset.ID;
                            itemDeltaVol.Add(sellOrder.StationID, info);
                            changedAsset.Quantity = sellOrder.RemainingVol;
                        }
                    }
                    changedAsset.Processed = true;
                    // Also set it to processed in the database.
                    SetProcessedFlag(changedAsset.ID, true);
                }

                // We havn't managed to match the order to an existing 'ForSaleViaMarket' stack in
                // the database or in memory.
                // As such, we need to create a new one.
                if (!foundMatch)
                {
                    // Create the new asset row..
                    changedAsset = assetData.NewAssetsRow();
                    changedAsset.AutoConExclude = true;
                    changedAsset.ContainerID = 0;
                    changedAsset.CorpAsset = false;
                    // Set cost to zero for now, it will be worked out later when gains/losses are reconciled.
                    changedAsset.Cost = 0;
                    changedAsset.CostCalc = false;
                    changedAsset.IsContainer = false;
                    changedAsset.ItemID = sellOrder.ItemID;
                    changedAsset.EveItemID = 0;
                    changedAsset.LocationID = sellOrder.StationID;
                    changedAsset.OwnerID = sellOrder.OwnerID;
                    changedAsset.Processed = true;
                    changedAsset.Quantity = sellOrder.RemainingVol;
                    changedAsset.RegionID = sellOrder.RegionID;
                    changedAsset.ReprocExclude = true;
                    changedAsset.SystemID = sellOrder.SystemID;
                    changedAsset.BoughtViaContract = false;
                    changedAsset.Status = (int)AssetStatus.States.ForSaleViaMarket;

                    assetData.AddAssetsRow(changedAsset);

                    // Store the changes we are making to quantities
                    Dictionary<long, AssetInfo> itemDeltaVol = new Dictionary<long, AssetInfo>();
                    if (modifiedAssets.ContainsKey(sellOrder.ItemID))
                    {
                        itemDeltaVol = modifiedAssets[sellOrder.ItemID];
                    }
                    else
                    {
                        modifiedAssets.Add(sellOrder.ItemID, itemDeltaVol);
                    }
                    if (itemDeltaVol.ContainsKey(sellOrder.StationID))
                    {
                        AssetInfo info = itemDeltaVol[sellOrder.StationID];
                        info.quantity += sellOrder.RemainingVol;
                        itemDeltaVol[sellOrder.StationID] = info;
                    }
                    else
                    {
                        AssetInfo info = new AssetInfo();
                        info.quantity = sellOrder.RemainingVol;
                        info.assetID = changedAsset.ID;
                        itemDeltaVol.Add(sellOrder.StationID, info);
                    }
                }

            }

            // Once we've finished processing all the orders, store the overall quantity changes.
            Dictionary<int, Dictionary<long, AssetInfo>>.Enumerator enumerator = modifiedAssets.GetEnumerator();
            while (enumerator.MoveNext())
            {
                Dictionary<long, AssetInfo>.Enumerator enumerator2 = enumerator.Current.Value.GetEnumerator();
                while(enumerator2.MoveNext())
                {
                    Asset change = new Asset();
                    change.ID = enumerator2.Current.Value.assetID;
                    change.ItemID = enumerator.Current.Key;
                    change.LocationID = enumerator2.Current.Key;
                    change.Quantity = enumerator2.Current.Value.quantity;
                    change.StatusID = (int)AssetStatus.States.ForSaleViaMarket;
                    change.IsContainer = false;
                    change.Container = null;
                    change.AutoConExclude = true;
                    change.OwnerID = ownerID;
                    change.UnitBuyPrice = 0;
                    change.UnitBuyPricePrecalculated = false;

                    changes.Add(change);
                }
            }
        }
Example #11
0
        /// <summary>
        /// Return a list of assets that meet the specified parameters.
        /// </summary>
        public static AssetList LoadReprocessableAssets(long ownerID, long stationID,
            int status, bool includeContainers, bool includeNonContainers)
        {
            AssetList retVal = new AssetList();
            EMMADataSet.AssetsDataTable table = new EMMADataSet.AssetsDataTable();

            lock (assetsTableAdapter)
            {
                assetsTableAdapter.FillByReprocessables(table, ownerID, stationID,
                    status, includeContainers, includeNonContainers);
            }

            foreach (EMMADataSet.AssetsRow row in table)
            {
                if (row.Quantity > 0)
                {
                    Asset asset = new Asset(row, null);
                    retVal.Add(asset);
                }
            }
            return retVal;
        }
Example #12
0
        /// <summary>
        /// Return a list of assets that meet the specified parameters.
        /// Note that the list does NOT include assets stored within other containers, ships, etc.
        /// </summary>
        /// <param name="accessParams"></param>
        /// <param name="regionIDs"></param>
        /// <param name="itemID"></param>
        /// <param name="locationID"></param>
        /// <returns></returns>
        public static AssetList LoadAssetsByItemAndContainersOfItem(List<AssetAccessParams> accessParams,
            List<long> regionIDs, int itemID, long locationID, long systemID, bool containersOnly,
            int status, bool excludeContainers)
        {
            AssetList retVal = new AssetList();
            EMMADataSet.AssetsDataTable table = new EMMADataSet.AssetsDataTable();
            string regionString = "";
            // Do not do this, just pass in an empty list and it'll match all regions.
            //if (regionIDs.Count == 0) { regionIDs.Add(0); }
            foreach (int region in regionIDs)
            {
                regionString = regionString + (regionString.Length == 0 ? "" : ",") + region;
            }
            lock (assetsTableAdapter)
            {
                assetsTableAdapter.FillByItemAndContainersOfItem(table,
                    AssetAccessParams.BuildAccessList(accessParams), regionString, systemID,
                    locationID, itemID, containersOnly, false, status);
            }

            foreach (EMMADataSet.AssetsRow row in table)
            {
                if (row.Quantity > 0 && (!row.IsContainer || !excludeContainers))
                {
                    Asset asset = new Asset(row, null);
                    retVal.Add(asset);
                }
            }
            return retVal;
        }
Example #13
0
        /// <summary>
        /// Retrieve assets that are stored in the specified container 
        /// </summary>
        /// <param name="container"></param>
        /// <returns></returns>
        public static AssetList LoadAssets(Asset container, int itemID)
        {
            AssetList retVal = new AssetList();
            EMMADataSet.AssetsDataTable table = new EMMADataSet.AssetsDataTable();
            lock (assetsTableAdapter)
            {
                assetsTableAdapter.FillByContainerID(table, container.ID, itemID);
            }

            foreach (EMMADataSet.AssetsRow row in table)
            {
                Asset asset = new Asset(row, container);
                retVal.Add(asset);
            }
            return retVal;
        }
Example #14
0
 /// <summary>
 /// Retrieve assets that are stored in the specified container 
 /// </summary>
 /// <param name="container"></param>
 /// <returns></returns>
 public static AssetList LoadAssets(Asset container)
 {
     return LoadAssets(container, 0);
 }
 public ContainerItem(Asset data)
 {
     if (data != null)
     {
         _text = data.Item;
     }
     else
     {
         _text = "All items not in a container";
     }
     _data = data;
 }