예제 #1
0
        public static void InitializeProcessing(string guid, string accountIdString)
        {
            // Start an async thread that does all the work, then return

            AuthenticationData authData = GetAuthenticationDataAndCulture();

            int accountId            = Int32.Parse(accountIdString);
            FinancialAccount account = FinancialAccount.FromIdentity(accountId);

            if (account.Organization.Identity != authData.CurrentOrganization.Identity ||
                !authData.Authority.HasAccess(new Access(authData.CurrentOrganization, AccessAspect.Bookkeeping,
                                                         AccessType.Write)))
            {
                throw new UnauthorizedAccessException();
            }

            Thread initThread = new Thread(ProcessUploadThread);

            ProcessThreadArguments args = new ProcessThreadArguments
            {
                Guid = guid, Organization = authData.CurrentOrganization, Account = account
            };

            initThread.Start(args);
        }
        public static AjaxCallResult InitializeExpensifyProcessing(string guidFiles, string guidProgress)
        {
            // Start an async thread that does all the work, then return

            AuthenticationData authData = GetAuthenticationDataAndCulture();
            ProgressBarBackend progress = new ProgressBarBackend(guidProgress);

            progress.Set(0); // Set to 0 first, esp. in case of previous files
            progress.Set(1); // Then to 1, just to indicate life

            Thread initThread = new Thread(ProcessExpensifyUploadThread);

            ProcessThreadArguments args = new ProcessThreadArguments
            {
                GuidFiles    = guidFiles,
                GuidProgress = guidProgress,
                Organization = authData.CurrentOrganization,
                CurrentUser  = authData.CurrentUser
            };

            initThread.Start(args);

            return(new AjaxCallResult {
                Success = true
            });
        }
        public static void InitializeProcessing(string guid, string accountIdString)
        {
            // Start an async thread that does all the work, then return

            AuthenticationData authData = GetAuthenticationDataAndCulture();

            int accountId = Int32.Parse(accountIdString);
            FinancialAccount account = FinancialAccount.FromIdentity(accountId);

            if (account.Organization.Identity != authData.CurrentOrganization.Identity ||
                !authData.CurrentUser.HasAccess(new Access(authData.CurrentOrganization, AccessAspect.Bookkeeping, AccessType.Write)))
            {
                throw new UnauthorizedAccessException();
            }

            Thread initThread = new Thread(ProcessUploadThread);

            ProcessThreadArguments args = new ProcessThreadArguments
                                              {Guid = guid, Organization = authData.CurrentOrganization, Account = account};

            initThread.Start(args);
        }
예제 #4
0
        static private ImportResults ProcessImportedData(ExternalBankData import, ProcessThreadArguments args)
        {
            FinancialAccount assetAccount = args.Account;
            FinancialAccount autoDepositAccount = args.Organization.FinancialAccounts.IncomeDonations;
            int autoDepositLimit = 1000; // TODO: this.CurrentOrganization.Parameters.AutoDonationLimit;

            ImportResults result = new ImportResults();
            int count = 0;
            int progressUpdateInterval = import.Records.Length/40;

            if (progressUpdateInterval > 100)
            {
                progressUpdateInterval = 100;
            }

            foreach (ExternalBankDataRecord row in import.Records)  
            {
                // Update progress.

                count++;
                if (progressUpdateInterval < 2 || count % progressUpdateInterval == 0)
                {
                    int percent = (count*99)/import.Records.Length;

                    GuidCache.Set(args.Guid + "-Progress", percent);
                }

                // Update high- and low-water marks.

                if (row.DateTime < result.EarliestTransaction)
                {
                    result.EarliestTransaction = row.DateTime;
                }

                if (row.DateTime > result.LatestTransaction)
                {
                    result.LatestTransaction = row.DateTime;
                }


                string importKey = row.ImportHash;

                Int64 amountCents = row.TransactionNetCents;

                if (amountCents == 0) // defensive programming - these _should_ be duplicated in the interpreter if no "fee" field
                {
                    amountCents = row.TransactionGrossCents;
                }

                if (args.Organization.Identity == 1 && assetAccount.Identity == 1 && PilotInstallationIds.IsPilot(PilotInstallationIds.PiratePartySE))
                {
                    // This is an ugly-as-f**k hack that sorts under the category "just bring our pilots the f**k back to operational
                    // status right f*****g now".

                    // This code can and should be safely removed once the pilot's books are closed for 2014, which should be some time mid-2015.

                    if (row.DateTime < new DateTime(2014,03,22))
                    {
                        result.DuplicateTransactions++;
                        continue;
                    }
                }

                FinancialTransaction transaction = FinancialTransaction.ImportWithStub(args.Organization.Identity, row.DateTime,
                                                                                       assetAccount.Identity, amountCents,
                                                                                       row.Description, importKey,
                                                                                       args.CurrentUser.Identity);

                if (transaction != null)
                {
                    // The transaction was created. Examine if the autobook criteria are true.

                    result.TransactionsImported++;

                    FinancialAccounts accounts = FinancialAccounts.FromBankTransactionTag(row.Description);

                    if (accounts.Count == 1)
                    {
                        // This is a labelled local donation.

                        Geography geography = accounts[0].AssignedGeography;
                        FinancialAccount localAccount = accounts[0];

                        transaction.AddRow(args.Organization.FinancialAccounts.IncomeDonations, -amountCents, args.CurrentUser);
                        transaction.AddRow(args.Organization.FinancialAccounts.CostsLocalDonationTransfers,
                                           amountCents, args.CurrentUser);
                        transaction.AddRow(localAccount, -amountCents, args.CurrentUser);

                        PWEvents.CreateEvent(EventSource.PirateWeb, EventType.LocalDonationReceived,
                                                                     args.CurrentUser.Identity, args.Organization.Identity,
                                                                     geography.Identity, 0,
                                                                     transaction.Identity, localAccount.Identity.ToString());
                    }
                    else if (row.Description.ToLowerInvariant().StartsWith(args.Organization.IncomingPaymentTag))
                    {
                        // Check for previously imported payment group

                        // TODO: MAKE FLEXIBLE - CALL PAYMENTREADERINTERFACE!
                        // HACK HACK HACK HACK

                        PaymentGroup group = PaymentGroup.FromTag(args.Organization,
                                                                  "SEBGM" + DateTime.Today.Year.ToString() +   // TODO: Get tags from org
                                                                  row.Description.Substring(args.Organization.IncomingPaymentTag.Length).Trim());

                        if (group != null && group.Open)
                        {
                            // There was a previously imported and not yet closed payment group matching this transaction
                            // Close the payment group and match the transaction against accounts receivable

                            transaction.Dependency = group;
                            group.Open = false;
                            transaction.AddRow(args.Organization.FinancialAccounts.AssetsOutboundInvoices, -amountCents, args.CurrentUser);
                        }
                    }
                    else if (amountCents < 0)
                    {
                        // Autowithdrawal mechanisms removed, condition kept because of downstream else-if conditions
                    }
                    else if (amountCents > 0)
                    {
                        if (row.FeeCents < 0)
                        {
                            // This is always an autodeposit, if there is a fee (which is never > 0.0)

                            transaction.AddRow(args.Organization.FinancialAccounts.CostsBankFees, -row.FeeCents, args.CurrentUser);
                            transaction.AddRow(autoDepositAccount, -row.TransactionGrossCents, args.CurrentUser);
                        }
                        else if (amountCents < autoDepositLimit * 100)
                        {
                            // Book against autoDeposit account.

                            transaction.AddRow(autoDepositAccount, -amountCents, args.CurrentUser);
                        }
                    }
                }
                else
                {
                    // Transaction was not imported; assume duplicate

                    result.DuplicateTransactions++;
                }
            }

            // Import complete. Return true if the bookkeeping account matches the bank data.

            Int64 databaseAccountBalanceCents = assetAccount.BalanceTotalCents;

            // Subtract any transactions made after the most recent imported transaction.
            // This is necessary in case of Paypal and others which continuously feed the
            // bookkeeping account with new transactions; it will already have fed transactions
            // beyond the end-of-file.

            Int64 beyondEofCents = assetAccount.GetDeltaCents(result.LatestTransaction.AddSeconds(1), DateTime.Now.AddDays(2)); // Caution: the "AddSeconds(1)" is not foolproof, there may be other new txs on the same second.

            if (databaseAccountBalanceCents - beyondEofCents == import.LatestAccountBalanceCents)
            {
                Payouts.AutomatchAgainstUnbalancedTransactions(args.Organization);
                result.AccountBalanceMatchesBank = true;
                result.BalanceMismatchCents = 0;
            }
            else
            {
                result.AccountBalanceMatchesBank = false;
                result.BalanceMismatchCents = (databaseAccountBalanceCents - beyondEofCents) -
                                              import.LatestAccountBalanceCents;
            }

            result.CurrencyCode = args.Organization.Currency.Code;
            return result;
        }