Example #1
0
        public void MigrateDependenciesTo(Payout migrationTarget)
        {
            if (Identity > 0 && migrationTarget.Identity > 0)
            {
                // Persisted payout migration

                SwarmDb.GetDatabaseForWriting().MovePayoutDependencies(Identity, migrationTarget.Identity);
            }
            else
            {
                // In-memory migration: this payout isn't in database yet

                this.DependentCashAdvancesPayback.ForEach(item => migrationTarget.DependentCashAdvancesPayback.Add(item));
                this.DependentCashAdvancesPayout.ForEach(item => migrationTarget.DependentCashAdvancesPayout.Add(item));
                this.DependentExpenseClaims.ForEach(item => migrationTarget.DependentExpenseClaims.Add(item));
                this.DependentInvoices.ForEach(item => migrationTarget.DependentInvoices.Add(item));
                this.DependentSalariesNet.ForEach(item => migrationTarget.DependentSalariesNet.Add(item));
                this.DependentSalariesTax.ForEach(item => migrationTarget.DependentSalariesTax.Add(item));

                this.DependentCashAdvancesPayback = new CashAdvances();
                this.DependentCashAdvancesPayout  = new CashAdvances();
                this.DependentExpenseClaims       = new ExpenseClaims();
                this.DependentInvoices            = new InboundInvoices();
                this.DependentSalariesNet         = new Salaries();
                this.DependentSalariesTax         = new Salaries();
            }
            migrationTarget.RecalculateAmount();
            RecalculateAmount();
        }
Example #2
0
        public static Payout Create(Payout payout)
        {
            throw new NotImplementedException(); // Seems not to be needed

            // This is quite unique in PW4 -- this is the only class which is pre-constructed and
            // can take an instance of its own kind as parameter in creation

            // TODO: Create in database

            // return payout;
        }
Example #3
0
        public static Payout FromDependency(IHasIdentity dependency)
        {
            int payoutId = SwarmDb.GetDatabaseForReading().GetPayoutIdFromDependency(dependency);

            if (payoutId == 0)
            {
                throw new ArgumentException("Supplied item does not have an associated payout");
            }

            return(Payout.FromIdentity(payoutId));
        }
Example #4
0
        public static Payout Create (Payout payout)
        {
            throw new NotImplementedException(); // Seems not to be needed

            // This is quite unique in PW4 -- this is the only class which is pre-constructed and
            // can take an instance of its own kind as parameter in creation

            // TODO: Create in database

            return payout;
        }
Example #5
0
        public static Payout FromDependency(IHasIdentity dependency, FinancialDependencyType dependencyType = FinancialDependencyType.Unknown)
        {
            int payoutId = 0;

            if (dependencyType == FinancialDependencyType.Unknown)
            {
                payoutId = SwarmDb.GetDatabaseForReading().GetPayoutIdFromDependency(dependency);
            }
            else
            {
                payoutId = SwarmDb.GetDatabaseForReading().GetPayoutIdFromDependency(dependency, dependencyType);
            }

            if (payoutId == 0)
            {
                throw new ArgumentException("Supplied item does not have an associated payout");
            }

            return(Payout.FromIdentity(payoutId));
        }
Example #6
0
        public static void TestMultisigPayout()
        {
            throw new InvalidOperationException("This function is only for testing purposes. It pays real money. Don't use except for dev/test.");

            // disable "code unreachable" warning for this code
            // ReSharper disable once CSharpWarnings::CS0162
            #pragma warning disable 162,219
            Organization organization = Organization.Sandbox; // a few testing cents here in test environment

            string bitcoinTestAddress = "3KS6AuQbZARSvqnaHoHfL1Xhm3bTLFAzoK";

            // Make a small test payment to a multisig address

            TransactionBuilder txBuilder = null; // TODO TODO TODO TODO  new TransactionBuilder();
            Int64 satoshis = new Money(100, Currency.FromCode("SEK")).ToCurrency(Currency.BitcoinCore).Cents;
            BitcoinTransactionInputs inputs      = null;
            Int64 satoshisMaximumAnticipatedFees = BitcoinUtility.GetRecommendedFeePerThousandBytesSatoshis(BitcoinChain.Cash) * 20; // assume max 20k transaction size

            try
            {
                inputs = BitcoinUtility.GetInputsForAmount(organization, satoshis + satoshisMaximumAnticipatedFees);
            }
            catch (NotEnoughFundsException)
            {
                Debugger.Break();
            }

            // If we arrive at this point, the previous function didn't throw, and we have enough money. Add the inputs to the transaction.

            txBuilder = txBuilder.AddCoins(inputs.Coins);
            txBuilder = txBuilder.AddKeys(inputs.PrivateKeys);
            Int64 satoshisInput = inputs.AmountSatoshisTotal;

            // Add outputs and prepare notifications

            Int64 satoshisUsed = 0;
            //Dictionary<int, List<string>> notificationSpecLookup = new Dictionary<int, List<string>>();
            //Dictionary<int, List<Int64>> notificationAmountLookup = new Dictionary<int, List<Int64>>();
            Payout            masterPayoutPrototype = Payout.Empty;
            HotBitcoinAddress changeAddress         = HotBitcoinAddress.OrganizationWalletZero(organization, BitcoinChain.Core);

            // Add the test payment

            if (bitcoinTestAddress.StartsWith("1")) // regular address
            {
                txBuilder = txBuilder.Send(new BitcoinPubKeyAddress(bitcoinTestAddress),
                                           new Satoshis(satoshis));
            }
            else if (bitcoinTestAddress.StartsWith("3")) // multisig
            {
                txBuilder = txBuilder.Send(new BitcoinScriptAddress(bitcoinTestAddress, Network.Main),
                                           new Satoshis(satoshis));
            }
            else
            {
                throw new InvalidOperationException("Unhandled address case");
            }
            satoshisUsed += satoshis;

            // Set change address to wallet slush

            txBuilder.SetChange(new BitcoinPubKeyAddress(changeAddress.Address));

            // Add fee

            int transactionSizeBytes = txBuilder.EstimateSize(txBuilder.BuildTransaction(false)) + inputs.Count;
            // +inputs.Count for size variability

            Int64 feeSatoshis = (transactionSizeBytes / 1000 + 1) *
                                BitcoinUtility.GetRecommendedFeePerThousandBytesSatoshis(BitcoinChain.Cash);

            txBuilder     = txBuilder.SendFees(new Satoshis(feeSatoshis));
            satoshisUsed += feeSatoshis;

            // Sign transaction - ready to execute

            Transaction txReady = txBuilder.BuildTransaction(true);

            // Verify that transaction is ready

            if (!txBuilder.Verify(txReady))
            {
                // Transaction was not signed with the correct keys. This is a serious condition.

                NotificationStrings primaryStrings = new NotificationStrings();
                primaryStrings[NotificationString.OrganizationName] = organization.Name;

                OutboundComm.CreateNotification(organization, NotificationResource.Bitcoin_PrivateKeyError,
                                                primaryStrings);

                throw new InvalidOperationException("Transaction is not signed enough");
            }

            // Broadcast transaction

            BitcoinUtility.BroadcastTransaction(txReady, BitcoinChain.Cash);

            // Note the transaction hash

            string transactionHash = txReady.GetHash().ToString();

            // Delete all old inputs, adjust balance for addresses (re-register unused inputs)

            inputs.AsUnspents.DeleteAll();

            // Log the new unspent created by change (if there is any)

            if (satoshisInput - satoshisUsed > 0)
            {
                SwarmDb.GetDatabaseForWriting()
                .CreateHotBitcoinAddressUnspentConditional(changeAddress.Identity, transactionHash,
                                                           +/* the change address seems to always get index 0? is this a safe assumption? */ 0, satoshisInput - satoshisUsed, /* confirmation count*/ 0);
            }

            // Restore "code unreachable", "unsued var" warnings
            #pragma warning restore 162,219

            // This puts the ledger out of sync, so only do this on Sandbox for various small-change (cents) testing
        }
Example #7
0
 public TaskPayout (Payout payout)
     : base (payout.Identity, "Payout #" + payout.Identity, DateTime.Now, payout.ExpectedTransactionDate)
 {
     
 }
Example #8
0
        public static Payout CreateBitcoinPayoutFromPrototype(Organization organization, Payout prototype, string transactionHash)
        {
            string[] components = prototype.ProtoIdentity.Split('|');
            int      payoutId   = 0;

            // This function is made for complex bitcoin payouts and will typically take many different types of payouts to many people at once.

            if (components.Length == 0)
            {
                // nothing to construct. Exception or return null?

                return(null);
            }

            payoutId = SwarmDb.GetDatabaseForWriting().CreatePayout(organization.Identity, "Bitcoin network", "Multiple",
                                                                    transactionHash, prototype.AmountCents, DateTime.UtcNow, 0);

            foreach (string component in components)
            {
                int foreignId = Int32.Parse(component.Substring(1));

                switch (component[0])
                {
                case 'A':
                    // Cash advance
                    CashAdvance advance = CashAdvance.FromIdentity(foreignId);
                    advance.PaidOut = true;

                    SwarmopsLogEntry.Create(null,
                                            new PayoutCreatedLogEntry(null, advance.Person, organization,
                                                                      organization.Currency, advance.AmountCents / 100.0,
                                                                      "Cash Advance Paid Out"),
                                            advance.Person, advance);

                    OutboundComm.CreateNotificationOfFinancialValidation(advance.Budget, advance.Person,
                                                                         advance.AmountCents / 100.0, advance.Description, NotificationResource.CashAdvance_PaidOut);
                    SwarmDb.GetDatabaseForWriting()
                    .CreatePayoutDependency(payoutId, FinancialDependencyType.CashAdvance,
                                            foreignId);
                    break;

                case 'a':
                    // This is a negative record - payback of cash advance
                    CashAdvance advancePayback = CashAdvance.FromIdentity(foreignId);
                    advancePayback.Open = false;

                    SwarmDb.GetDatabaseForWriting()
                    .CreatePayoutDependency(payoutId, FinancialDependencyType.CashAdvancePayback,
                                            foreignId);

                    break;

                case 'C':
                    // Expense claim
                    ExpenseClaim claim = ExpenseClaim.FromIdentity(foreignId);
                    claim.Repaid = true;
                    claim.Close();

                    OutboundComm.CreateNotificationOfFinancialValidation(claim.Budget, claim.Claimer,
                                                                         claim.AmountCents / 100.0, claim.Description, NotificationResource.ExpenseClaim_PaidOut);
                    SwarmDb.GetDatabaseForWriting()
                    .CreatePayoutDependency(payoutId, FinancialDependencyType.ExpenseClaim,
                                            foreignId);

                    break;

                case 'I':
                    // Invoice
                    InboundInvoice invoice         = InboundInvoice.FromIdentity(foreignId);
                    DateTime       expectedPayment = invoice.DueDate;

                    if (expectedPayment < DateTime.Today)
                    {
                        expectedPayment = DateTime.Today;
                    }

                    SwarmDb.GetDatabaseForWriting()
                    .CreatePayoutDependency(payoutId, FinancialDependencyType.InboundInvoice,
                                            invoice.Identity);

                    // TODO: NOTIFY PAID?

                    invoice.Open = false;
                    break;

                case 'S':
                    // Salary net

                    Salary salaryNet = Salary.FromIdentity(foreignId);
                    SwarmDb.GetDatabaseForWriting().CreatePayoutDependency(payoutId, FinancialDependencyType.Salary,
                                                                           salaryNet.Identity);
                    salaryNet.NetPaid = true;
                    break;

                case 'T':
                    // Tax payout, typically for multiple salaries

                    Salary salaryTax = Salary.FromIdentity(foreignId);
                    SwarmDb.GetDatabaseForWriting().CreatePayoutDependency(payoutId, FinancialDependencyType.SalaryTax,
                                                                           salaryTax.Identity);
                    salaryTax.TaxPaid = true;

                    break;

                default:
                    throw new NotImplementedException();
                }
            }

            // Return the new object by reloading it from database

            return(Payout.FromIdentity(payoutId));
        }
Example #9
0
 public void MigrateDependenciesTo(Payout migrationTarget)
 {
     SwarmDb.GetDatabaseForWriting().MovePayoutDependencies(Identity, migrationTarget.Identity);
     migrationTarget.RecalculateAmount();
     RecalculateAmount();
 }
Example #10
0
 public void MigrateDependenciesTo (Payout migrationTarget)
 {
     SwarmDb.GetDatabaseForWriting().MovePayoutDependencies(this.Identity, migrationTarget.Identity);
     migrationTarget.RecalculateAmount();
     this.RecalculateAmount();
 }