Пример #1
0
        public static AjaxCallResult ResyncSatoshisInLedger(string itemId)
        {
            AuthenticationData authData = GetAuthenticationDataAndCulture();

            if (!authData.Authority.HasAccess(new Access(authData.CurrentOrganization, AccessAspect.BookkeepingDetails)))
            {
                throw new UnauthorizedAccessException();
            }

            Int64 cashSatoshisInLedger =
                authData.CurrentOrganization.FinancialAccounts.AssetsBitcoinHot.GetForeignCurrencyBalanceDeltaCents(
                    Constants.DateTimeLow, Constants.DateTimeHigh).Cents;

            Int64 cashSatoshisInHotwallet =
                HotBitcoinAddresses.GetSatoshisInHotwallet(authData.CurrentOrganization)[BitcoinChain.Cash];

            Int64 adjustment = cashSatoshisInHotwallet - cashSatoshisInLedger;  // positive if ledger needs upward adjustment

            FinancialTransaction adjustmentTx = FinancialTransaction.Create(authData.CurrentOrganization,
                                                                            DateTime.UtcNow, Resources.Pages.Ledgers.EndOfMonth_LedgerBitcoinBalanceTransactionDescription);

            adjustmentTx.AddRow(authData.CurrentOrganization.FinancialAccounts.AssetsBitcoinHot, 0, authData.CurrentUser).AmountForeignCents = new Money(adjustment, Currency.BitcoinCash);

            return(new AjaxCallResult
            {
                Success = true,
                DisplayMessage =
                    String.Format(Resources.Pages.Ledgers.EndOfMonth_Dialog_LedgerBitcoinBalanceMismatch,
                                  cashSatoshisInHotwallet / 100.0, cashSatoshisInLedger / 100.0)
            });
        }
Пример #2
0
        protected void Page_Load(object sender, EventArgs e)
        {
            this.PageAccessRequired = new Access(this.CurrentOrganization, AccessAspect.BookkeepingDetails);

            this.PageTitle =
                this.Title =
                    this.LabelHeader.Text =
                        String.Format(Resources.Pages.Ledgers.EndOfMonth_Title, DateTime.UtcNow.AddMonths(-1));

            this.InfoBoxLiteral = Resources.Pages.Ledgers.EndOfMonth_Info;

            // Check which reports are required

            ItemGroups = new List <EomItemGroup>();

            // Group I: External data & accounts

            EomItemGroup group1 = new EomItemGroup();

            group1.Header = Resources.Pages.Ledgers.EndOfMonth_Header_ExternalData;
            group1.Id     = "ExternalData";

            string lastUploadItemId = string.Empty;

            // Iterate over all Balance accounts and check for automation;
            // if so, add it to an upload sequence

            FinancialAccounts assetAccounts = FinancialAccounts.ForOrganization(this.CurrentOrganization,
                                                                                FinancialAccountType.Asset);

            DateTime lastMonthEndDate = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, 1).AddDays(-1);
            int      lastMonth        = lastMonthEndDate.Year * 100 + lastMonthEndDate.Month;
            bool     skippable        = true;

            foreach (FinancialAccount assetAccount in assetAccounts)
            {
                if (assetAccount.AutomationProfileId != 0)
                {
                    // This account has automation
                    // If automation has Bank Account Statement enabled (assume true for now):

                    FinancialAccountDocument lastBankStatement =
                        assetAccount.GetMostRecentDocument(FinancialAccountDocumentType.BankStatement);
                    int lastStatementMonth = (this.CurrentOrganization.FirstFiscalYear - 1) * 100 + 12;
                    // December of the year before

                    if (lastBankStatement != null)
                    {
                        lastStatementMonth = lastBankStatement.ConcernsPeriodStart.Year * 100 +
                                             lastBankStatement.ConcernsPeriodStart.Month;
                        skippable = false;
                    }

                    string lastId        = string.Empty;
                    int    monthIterator = lastStatementMonth;

                    while (monthIterator < lastMonth)
                    {
                        monthIterator++;
                        if (monthIterator % 100 == 13)
                        {
                            monthIterator += 88;
                        }

                        EomItem bankStatement = new EomItem();
                        bankStatement.DependsOn = lastId; // empty for first record
                        bankStatement.Id        = lastId = "BankStatement-" +
                                                           assetAccount.Identity.ToString(CultureInfo.InvariantCulture) + '-' +
                                                           monthIterator;
                        bankStatement.Name = string.Format(Resources.Pages.Ledgers.EndOfMonth_UploadBankStatementFor,
                                                           assetAccount.Name, "PDF",
                                                           new DateTime(monthIterator / 100, monthIterator % 100, 15).ToString("MMMM yyyy"));
                        bankStatement.Completed = false; // TODO
                        bankStatement.Icon      = "upload";
                        bankStatement.Skippable = skippable;

                        group1.Items.Add(bankStatement);
                    }

                    // Add data upload item

                    // TODO: Check if the last data upload was into the current month

                    EomItem dataUploadItem = new EomItem();
                    dataUploadItem.Id        = "BankTransactionData-" + assetAccount.Identity.ToString(CultureInfo.InvariantCulture);
                    dataUploadItem.Icon      = "upload";
                    dataUploadItem.Completed = false; // todo
                    dataUploadItem.Name      = String.Format(Resources.Pages.Ledgers.EndOfMonth_UploadTransactionDataFor,
                                                             assetAccount.Name, "CSV");
                    dataUploadItem.Skippable = false;

                    group1.Items.Add(dataUploadItem);

                    // Check if we need to add a resync of the hotwallet's native ledger

                    if (CurrentOrganization.FinancialAccounts.AssetsBitcoinHot != null) // has hotwallet
                    {
                        Int64 cashSatoshisInLedger =
                            CurrentOrganization.FinancialAccounts.AssetsBitcoinHot.GetForeignCurrencyBalanceDeltaCents(
                                Constants.DateTimeLow, Constants.DateTimeHigh).Cents;

                        Int64 cashSatoshisInHotwallet =
                            HotBitcoinAddresses.GetSatoshisInHotwallet(CurrentOrganization)[BitcoinChain.Cash];

                        if (cashSatoshisInHotwallet != cashSatoshisInLedger)
                        {
                            // Resync required

                            EomItem resyncSatoshiCountItem = new EomItem();
                            resyncSatoshiCountItem.Id        = "ResyncSatoshisInLedger";
                            resyncSatoshiCountItem.Icon      = "approve";
                            resyncSatoshiCountItem.Completed = false;
                            resyncSatoshiCountItem.Skippable = false;
                            resyncSatoshiCountItem.Callback  = "ResyncSatoshisInLedger";
                            resyncSatoshiCountItem.Name      = Resources.Pages.Ledgers.EndOfMonth_CheckLedgerAgainstHotWallet;
                            group1.Items.Add(resyncSatoshiCountItem);
                        }
                    }
                }
            }

            // If there are any items in Group 1, OR if an account matching is necessary, then
            // add that as an action item

            if (group1.Items.Count() > 0 || FinancialTransactions.GetUnbalanced(this.CurrentOrganization).Count() > 0)
            {
                EomItem matchAccounts = new EomItem();
                matchAccounts.DependsOn = lastUploadItemId; // may be empty if there's nothing to upload and that's ok
                matchAccounts.Id        = "MatchAccounts";
                matchAccounts.Completed = false;            // we already know there's at least one unbalanced
                matchAccounts.Icon      = "wrench";
                matchAccounts.Skippable = false;
                matchAccounts.Name      = Resources.Pages.Ledgers.EndOfMonth_MatchAccounts;

                group1.Items.Add(matchAccounts);
            }

            if (group1.Items.Count > 0)
            {
                ItemGroups.Add(group1);
            }

            // Group: Payroll and Taxes

            EomItemGroup group2 = new EomItemGroup();

            group2.Header = Resources.Pages.Ledgers.EndOfMonth_Header_PayrollTaxes;
            group2.Id     = "PayrollTaxes";

            ReportRequirement vatRequired = VatReport.IsRequired(this.CurrentOrganization);

            if (vatRequired == ReportRequirement.Required || vatRequired == ReportRequirement.Completed)
            {
                EomItem vatReport = new EomItem();
                vatReport.Id        = "VatReport";
                vatReport.Callback  = "CreateVatReport";
                vatReport.Completed = (vatRequired == ReportRequirement.Completed ? true : false);
                vatReport.Name      = String.Format(Resources.Pages.Ledgers.EndOfMonth_CreateVatReport,
                                                    (vatReport.Completed
                        ? VatReport.LastReportDescription(this.CurrentOrganization)
                        : VatReport.NextReportDescription(this.CurrentOrganization)));
                vatReport.Icon = "document";

                group2.Items.Add(vatReport);
            }

            Payroll payroll = Payroll.ForOrganization(this.CurrentOrganization);

            if (payroll.Any())
            {
                // There is active payroll

                // TODO: Taxes for last month and processing for this month
            }
            else
            {
                EomItem payrollInactive = new EomItem();
                payrollInactive.Id        = "PayrollInactive";
                payrollInactive.Completed = true;
                payrollInactive.Name      = Resources.Pages.Ledgers.EndOfMonth_PayrollInactive;
                payrollInactive.Icon      = "document";
                group2.Items.Add(payrollInactive);
            }

            if (group2.Items.Count > 0)
            {
                ItemGroups.Add(group2);
            }

            // Group: Closure of Ledgers and Annual Reports

            int lastClosedYear = CurrentOrganization.Parameters.FiscalBooksClosedUntilYear;

            if (lastClosedYear - 1 < DateTime.UtcNow.Year)
            {
                EomItemGroup groupReports = new EomItemGroup();

                groupReports.Header = Resources.Pages.Ledgers.EndOfMonth_Header_AnnualReports;
                EomItem itemCloseYear = new EomItem();
                itemCloseYear.Id       = "CloseLedgers";
                itemCloseYear.Callback = "CloseLedgers";
                itemCloseYear.Icon     = "document";
                itemCloseYear.Name     = String.Format(Resources.Pages.Ledgers.EndOfMonth_CloseLedgersFor,
                                                       lastClosedYear + 1);

                groupReports.Items.Add(itemCloseYear);
                ItemGroups.Add(groupReports);
            }
        }