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(); }
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; }
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)); }
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; }
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)); }
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 }
public TaskPayout (Payout payout) : base (payout.Identity, "Payout #" + payout.Identity, DateTime.Now, payout.ExpectedTransactionDate) { }
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)); }
public void MigrateDependenciesTo(Payout migrationTarget) { SwarmDb.GetDatabaseForWriting().MovePayoutDependencies(Identity, migrationTarget.Identity); migrationTarget.RecalculateAmount(); RecalculateAmount(); }
public void MigrateDependenciesTo (Payout migrationTarget) { SwarmDb.GetDatabaseForWriting().MovePayoutDependencies(this.Identity, migrationTarget.Identity); migrationTarget.RecalculateAmount(); this.RecalculateAmount(); }