/// <summary> /// Find the oldest holdings that still have UnitsRemaining, and decrement them by the /// number of units we are selling. This might have to sell from multiple SecurityPurchases /// in order to cover the requested number of units. If there are not enough units to cover /// the sale then we have a problem and we return a SecuritySale containing the Error information. /// </summary> /// <param name="dateSold">The date of the sale</param> /// <param name="units">The number of units sold</param> /// <param name="amount">The total amount we received from the sale</param> /// <returns></returns> public IEnumerable <SecuritySale> Sell(DateTime dateSold, decimal units, decimal amount) { decimal salePricePerUnit = amount / units; foreach (var purchase in list) { SecuritySale sale = purchase.Sell(dateSold, units, salePricePerUnit); if (sale != null) { sale.Account = this.Account; units -= sale.UnitsSold; yield return(sale); if (units <= 0) { // done! break; } } } if (Math.Floor(units) > 0) { // Generate an error item so we can report this problem later. pending.Add(new SecuritySale() { Security = this.Security, Account = this.Account, DateSold = dateSold, UnitsSold = units, SalePricePerUnit = salePricePerUnit }); } }
/// <summary> /// For a roll-up report where individual SecuritySale is too much detail we /// can consolidate here, but only if the SalePricePerUnit and CostBasisPerUnit /// match. If they do not match then we set them to zero so they are reported /// as "unknown". /// </summary> /// <param name="cg">The other sale to consolidate</param> internal void Consolidate(SecuritySale cg) { this.UnitsSold += cg.UnitsSold; if (this.DateAcquired != cg.DateAcquired) { // will be reported to IRS as "VARIOUS" this.DateAcquired = null; this.CostBasisPerUnit = 0; } if (this.SalePricePerUnit != cg.SalePricePerUnit) { this.SalePricePerUnit = 0; } if (this.CostBasisPerUnit != cg.CostBasisPerUnit) { this.CostBasisPerUnit = 0; } }