// GET: CloudFiles/Download/5
        public async Task <ActionResult> Download(Guid?id)
        {
            auditResult = audit.LogEvent(UserContact, (Guid)id, this.ENTITY, this.Request.UserHostAddress, EVENT_DOWNLOAD_FILE);

            if (id == null)
            {
                return(new HttpStatusCodeResult(HttpStatusCode.BadRequest));
            }

            GNCloudFile cloudFile = await db.GNCloudFiles.FindAsync(id);

            if (cloudFile == null)
            {
                return(HttpNotFound());
            }

            InitCloudServices();

            string contentDisposition = "attachment; filename=" +
                                        ((CloudFileService)entityService).GetCloudFileName(cloudFile);

            int cloudFileSignURLTimeOutMins = 15;

            int.TryParse(ConfigurationManager.AppSettings["CloudFileSignURLTimeOutMins"],
                         out cloudFileSignURLTimeOutMins);

            Uri signedURL = ((CloudFileService)entityService)
                            .cloudStorageService
                            .GetSignedUrl(new Uri(cloudFile.FileURL), TimeSpan.FromMinutes(cloudFileSignURLTimeOutMins), "GET", contentDisposition);

            //record transaction
            if (cloudFile != null)
            {
                int s3BucketMatchCount = UserContact.GNOrganization.AWSConfig.AWSResources.Count(r => r.ARN == cloudFile.Volume);

                if (s3BucketMatchCount != 0)
                {
                    string txnTypeKey  = "STORAGE_S3_DOWNLOAD";
                    string description = cloudFile.Description;
                    double valueUsed   = ((double)cloudFile.FileSize / (double)(1024 * 1024 * 1024));
                    string valueUnits  = "GB";

                    GNTransaction txn =
                        await this.transactionService.CreateTransaction(
                            UserContact, txnTypeKey, description, valueUsed, valueUnits);

                    if (txn != null)
                    {
                        bool success = await this.transactionService.ApplyTransactionTotalToBestPaymentMethod(
                            UserContact, txn, UserContact.GNOrganization.Account.BillingMode);
                    }
                }
            }
            else
            {
                LogUtil.Error(logger, "Unable to record transaction for File Download due to a NULL Cloud File / Entity object.");
            }

            return(Redirect(signedURL.AbsoluteUri));
        }
        public override async Task <GNCloudFile> Insert(GNContact userContact, object entity)
        {
            bool isExternallyHosted = ((GNCloudFile)entity).IsExternallyHosted;

            GNCloudFile cloudFile = await base.Insert(userContact, entity);

            if (cloudFile == null && entity != null)
            {
                cloudFile = (GNCloudFile)entity;
            }

            //record transaction
            if (cloudFile != null && !isExternallyHosted)
            {
                string txnTypeKey  = "STORAGE_S3_UPLOAD";
                string description = cloudFile.Description;
                double valueUsed   = ((double)cloudFile.FileSize / (double)(1024 * 1024 * 1024));
                string valueUnits  = "GB";

                GNTransaction txn =
                    await this.transactionService.CreateTransaction(
                        userContact, txnTypeKey, description, valueUsed, valueUnits);

                if (txn != null)
                {
                    bool success = await this.transactionService.ApplyTransactionTotalToBestPaymentMethod(
                        userContact, txn, userContact.GNOrganization.Account.BillingMode);
                }
            }
            else
            {
                LogUtil.Error(logger, "Unable to record transaction for File Upload due to a NULL Cloud File / Entity object.");
            }

            return(cloudFile);
        }
        private async Task <int> ProcessStorageCarryOverFees()
        {
            int result = 1;

            if (DateTime.Now.Day == DAY_TO_PROCESS_STORAGE_CARRYOVER_FEES)
            {
                LogUtil.Info(logger, "ProcessStorageCarryOverFees()...");
                System.Console.WriteLine("\nProcessStorageCarryOverFees()...");

                var                  db                   = new GNEntityModelContainer();
                InvoiceService       invoiceService       = new InvoiceService(db);
                InvoiceDetailService invoiceDetailService = new InvoiceDetailService(db);
                TransactionService   transactionService   = new TransactionService(db);
                AccountService       orgAccountService    = new AccountService(db);

                foreach (var orgAccount in await orgAccountService.FindAll())
                {
                    try
                    {
                        LogUtil.Info(logger, "Account = " + orgAccount.Organization.Name);
                        System.Console.WriteLine("\nAccount = " + orgAccount.Organization.Name);

                        //get user contact
                        GNContact userContact = orgAccount.AccountOwner;
                        if (userContact == null)
                        {
                            userContact = db.GNContacts.Where(c => c.GNOrganizationId == orgAccount.Organization.Id).FirstOrDefault();
                        }

                        if (userContact != null)
                        {
                            //get last month invoice
                            GNInvoice lastMonthInvoice = invoiceService.GetInvoiceForLastMonth(userContact);

                            if (lastMonthInvoice != null)
                            {
                                string txnKey = "STORAGE_S3_CARRYOVER";

                                //get invoice to update
                                GNInvoice invoiceToUpdate = null;
                                if (lastMonthInvoice.Status != GNInvoice.InvoiceStatus.PAID.ToString() &&
                                    lastMonthInvoice.Status != GNInvoice.InvoiceStatus.VOID.ToString())
                                {
                                    invoiceToUpdate = lastMonthInvoice;
                                }
                                else
                                {
                                    invoiceToUpdate = await invoiceService.GetInvoiceForCurrentMonth(orgAccount.AccountOwner);
                                }

                                if (invoiceToUpdate != null)
                                {
                                    //get storage carryover detail
                                    GNInvoiceDetail storageCarryOverInvoiceDetail =
                                        db.GNInvoiceDetails
                                        .Where(invd => (invd.GNInvoiceId == invoiceToUpdate.Id && invd.Description == txnKey))
                                        .FirstOrDefault();

                                    //add invoice detail, if missing
                                    if (storageCarryOverInvoiceDetail == null)
                                    {
                                        storageCarryOverInvoiceDetail =
                                            db.GNInvoiceDetails.Add(new GNInvoiceDetail
                                        {
                                            Id             = Guid.NewGuid(),
                                            Description    = txnKey,
                                            GNInvoiceId    = invoiceToUpdate.Id,
                                            Quantity       = 0.0,
                                            SubTotal       = 0.0,
                                            DiscountAmount = orgAccount.DefaultDiscountAmount,
                                            DiscountType   = orgAccount.DefaultDiscountType,
                                            Total          = 0.0,
                                            UnitCost       = 0.0,
                                            UnitPrice      = 0.0,
                                            CreateDateTime = DateTime.Now,
                                            CreatedBy      = orgAccount.AccountOwner.Id
                                        });

                                        await db.SaveChangesAsync();

                                        storageCarryOverInvoiceDetail = db.GNInvoiceDetails.Find(storageCarryOverInvoiceDetail.Id);
                                    }

                                    if (storageCarryOverInvoiceDetail != null)
                                    {
                                        //get txn count
                                        int txnCount =
                                            db.GNTransactions.Count(t =>
                                                                    (t.GNInvoiceDetailId == storageCarryOverInvoiceDetail.Id &&
                                                                     t.TransactionType.Name == txnKey));

                                        if (txnCount == 0)
                                        {
                                            //get storage balance for month
                                            //all uploads minus all downloads up until end of last month
                                            var storageUsed = orgAccountService.CalcStorageUsed(orgAccount.Id, lastMonthInvoice.InvoiceEndDate.AddDays(1));

                                            //get storage carryover product
                                            GNProduct storageCarryOverProduct = db.GNProducts.Where(p => p.Name == txnKey).FirstOrDefault();

                                            //calc storage carryover cost
                                            var totalCarryOverCost = storageUsed * storageCarryOverProduct.Price;

                                            //add storage cost transaction
                                            string txnTypeKey  = txnKey;
                                            string description = storageUsed + "GB";
                                            double valueUsed   = storageUsed;
                                            string valueUnits  = "GB";

                                            int updateResult = 0;

                                            GNTransaction txn =
                                                await transactionService.CreateTransaction(
                                                    userContact, txnTypeKey, description, valueUsed, valueUnits,
                                                    targetInvoice : invoiceToUpdate);

                                            if (txn != null)
                                            {
                                                updateResult = 1;
                                            }
                                            //update invoice totals
                                            //int updateResult = await invoiceDetailService.UpdateInvoiceDetailTotals(
                                            //    invDetailToUpdate.Id, invDetailToUpdate.GNInvoiceId, invDetailToUpdate.Invoice.GNAccountId);

                                            LogUtil.Info(logger, "Update result = " + updateResult);
                                            System.Console.WriteLine("\nUpdate result = " + updateResult);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        result = 0;
                        LogUtil.Warn(logger, ex.Message, ex);
                        System.Console.WriteLine(ex.Message);
                    }
                }
            }

            return(result);
        }
        public async Task <int> Delete(GNContact userContact, string sampleId, params object[] keys)
        {
            LogUtil.LogMethod(logger, MethodBase.GetCurrentMethod());
            int result = 0;

            GNCloudFile cloudFile = db.GNCloudFiles.Find(keys);

            if (cloudFile != null)
            {
                int s3BucketMatchCount = userContact.GNOrganization.AWSConfig.AWSResources.Count(r => r.ARN == cloudFile.Volume);

                bool s3DeleteSuccess = true;

                //Perform Physical Delete of File on S3, if in bucket owned by GenomeNext
                if (s3BucketMatchCount != 0)
                {
                    s3DeleteSuccess = cloudStorageService.DeleteS3File(cloudFile.Volume, cloudFile.FileName);

                    if (s3DeleteSuccess)
                    {
                        //record transaction
                        if (cloudFile != null)
                        {
                            string txnTypeKey  = "STORAGE_S3_DELETE";
                            string description = cloudFile.Description;
                            double valueUsed   = -1.0 * ((double)cloudFile.FileSize / (double)(1024 * 1024 * 1024));
                            string valueUnits  = "GB";

                            GNTransaction txn =
                                await this.transactionService.CreateTransaction(
                                    userContact, txnTypeKey, description, valueUsed, valueUnits);
                        }
                        else
                        {
                            LogUtil.Error(logger, "Unable to record transaction for File Delete due to a NULL Cloud File / Entity object.");
                        }
                    }
                }

                //Perform Logical Delete of File in DB
                if (s3DeleteSuccess && !string.IsNullOrEmpty(sampleId))
                {
                    var tx = db.Database.BeginTransaction();

                    result = db.Database.ExecuteSqlCommand(
                        "DELETE FROM [gn].[GNSampleGNCloudFile] " +
                        "WHERE [GNSampleGNCloudFile_GNCloudFile_Id] = @sampleId " +
                        "AND [CloudFiles_Id] = @cloudFileId",
                        new SqlParameter("@sampleId", Guid.Parse(sampleId)),
                        new SqlParameter("@cloudFileId", cloudFile.Id));

                    if (result != 0)
                    {
                        result = db.Database.ExecuteSqlCommand(
                            "DELETE FROM [gn].[GNCloudFiles] " +
                            "WHERE [Id] = @cloudFileId",
                            new SqlParameter("@cloudFileId", cloudFile.Id));
                    }

                    tx.Commit();
                }
                else
                {
                    Exception e = new Exception("S3 Delete Object Failed and/or Sample ID is empty");
                    LogUtil.Error(logger, e.Message, e);
                    throw e;
                }
            }

            return(result);
        }