using System; using Xunit; using Newtonsoft.Json.Linq; using FluentAssertions; namespace raven_integration { public class ServiceRateCrud { /// /// Full CRUD for a ServiceRate, including concurrency violation and 404 on deleted record. /// [Fact] public async Task CRUD() { var token = await Util.GetTokenAsync("BizAdmin"); // CREATE var name = Util.Uniquify("Test Service Rate"); var payload = $$""" {"id":0,"concurrency":0,"name":"{{name}}","active":true,"notes":null,"wiki":null,"customFields":"{}","tags":[],"accountNumber":null,"cost":50.00,"charge":75.00,"unit":null,"contractOnly":false} """; ApiResponse a = await Util.PostAsync("service-rate", token, payload); Util.ValidateDataReturnResponseOk(a); long Id = a.ObjectResponse["data"]["id"].Value(); Id.Should().BeGreaterThan(0); a.ObjectResponse["data"]["name"].Value().Should().Be(name); // GET a = await Util.GetAsync($"service-rate/{Id}", token); Util.ValidateDataReturnResponseOk(a); a.ObjectResponse["data"]["name"].Value().Should().Be(name); a.ObjectResponse["data"]["cost"].Value().Should().Be(50.00m); var concurrency = a.ObjectResponse["data"]["concurrency"].Value(); // PUT (update name and charge) var updatedName = Util.Uniquify("Updated Service Rate"); var putPayload = $$""" {"id":{{Id}},"concurrency":{{concurrency}},"name":"{{updatedName}}","active":true,"notes":null,"wiki":null,"customFields":"{}","tags":[],"accountNumber":null,"cost":50.00,"charge":80.00,"unit":null,"contractOnly":false} """; a = await Util.PutAsync("service-rate", token, putPayload); Util.ValidateHTTPStatusCode(a, 200); var newConcurrency = a.ObjectResponse["data"]["concurrency"].Value(); newConcurrency.Should().NotBe(concurrency, "concurrency should have been bumped by the update"); // Verify the update was persisted a = await Util.GetAsync($"service-rate/{Id}", token); Util.ValidateDataReturnResponseOk(a); a.ObjectResponse["data"]["name"].Value().Should().Be(updatedName); a.ObjectResponse["data"]["charge"].Value().Should().Be(80.00m); // CONCURRENCY VIOLATION: PUT with stale concurrency should return 409 a = await Util.PutAsync("service-rate", token, putPayload); // putPayload still has old concurrency Util.ValidateConcurrencyError(a); // DELETE a = await Util.DeleteAsync($"service-rate/{Id}", token); Util.ValidateHTTPStatusCode(a, 204); // Confirm deleted a = await Util.GetAsync($"service-rate/{Id}", token); Util.ValidateResponseNotFound(a); } }//eoc public class TravelRateCrud { /// /// Full CRUD for a TravelRate, including concurrency violation and 404 on deleted record. /// [Fact] public async Task CRUD() { var token = await Util.GetTokenAsync("BizAdmin"); // CREATE var name = Util.Uniquify("Test Travel Rate"); var payload = $$""" {"id":0,"concurrency":0,"name":"{{name}}","active":true,"notes":null,"wiki":null,"customFields":"{}","tags":[],"accountNumber":null,"cost":50.00,"charge":75.00,"unit":null,"contractOnly":false} """; ApiResponse a = await Util.PostAsync("travel-rate", token, payload); Util.ValidateDataReturnResponseOk(a); long Id = a.ObjectResponse["data"]["id"].Value(); Id.Should().BeGreaterThan(0); a.ObjectResponse["data"]["name"].Value().Should().Be(name); // GET a = await Util.GetAsync($"travel-rate/{Id}", token); Util.ValidateDataReturnResponseOk(a); a.ObjectResponse["data"]["name"].Value().Should().Be(name); a.ObjectResponse["data"]["cost"].Value().Should().Be(50.00m); var concurrency = a.ObjectResponse["data"]["concurrency"].Value(); // PUT (update name and charge) var updatedName = Util.Uniquify("Updated Travel Rate"); var putPayload = $$""" {"id":{{Id}},"concurrency":{{concurrency}},"name":"{{updatedName}}","active":true,"notes":null,"wiki":null,"customFields":"{}","tags":[],"accountNumber":null,"cost":50.00,"charge":80.00,"unit":null,"contractOnly":false} """; a = await Util.PutAsync("travel-rate", token, putPayload); Util.ValidateHTTPStatusCode(a, 200); var newConcurrency = a.ObjectResponse["data"]["concurrency"].Value(); newConcurrency.Should().NotBe(concurrency, "concurrency should have been bumped by the update"); // Verify the update was persisted a = await Util.GetAsync($"travel-rate/{Id}", token); Util.ValidateDataReturnResponseOk(a); a.ObjectResponse["data"]["name"].Value().Should().Be(updatedName); a.ObjectResponse["data"]["charge"].Value().Should().Be(80.00m); // CONCURRENCY VIOLATION: PUT with stale concurrency should return 409 a = await Util.PutAsync("travel-rate", token, putPayload); // putPayload still has old concurrency Util.ValidateConcurrencyError(a); // DELETE a = await Util.DeleteAsync($"travel-rate/{Id}", token); Util.ValidateHTTPStatusCode(a, 204); // Confirm deleted a = await Util.GetAsync($"travel-rate/{Id}", token); Util.ValidateResponseNotFound(a); } }//eoc public class TaxCodeCrud { /// /// Full CRUD for a TaxCode, including concurrency violation and 404 on deleted record. /// [Fact] public async Task CRUD() { var token = await Util.GetTokenAsync("BizAdmin"); // CREATE var name = Util.Uniquify("Test Tax Code"); var payload = $$""" {"id":0,"concurrency":0,"name":"{{name}}","active":true,"notes":null,"wiki":null,"customFields":"{}","tags":[],"taxAPct":5.0,"taxBPct":2.5,"taxOnTax":false} """; ApiResponse a = await Util.PostAsync("tax-code", token, payload); Util.ValidateDataReturnResponseOk(a); long Id = a.ObjectResponse["data"]["id"].Value(); Id.Should().BeGreaterThan(0); a.ObjectResponse["data"]["name"].Value().Should().Be(name); // GET a = await Util.GetAsync($"tax-code/{Id}", token); Util.ValidateDataReturnResponseOk(a); a.ObjectResponse["data"]["name"].Value().Should().Be(name); a.ObjectResponse["data"]["taxAPct"].Value().Should().Be(5.0m); a.ObjectResponse["data"]["taxBPct"].Value().Should().Be(2.5m); var concurrency = a.ObjectResponse["data"]["concurrency"].Value(); // PUT (update name only; taxAPct and taxBPct stay the same) var updatedName = Util.Uniquify("Updated Tax Code"); var putPayload = $$""" {"id":{{Id}},"concurrency":{{concurrency}},"name":"{{updatedName}}","active":true,"notes":null,"wiki":null,"customFields":"{}","tags":[],"taxAPct":5.0,"taxBPct":2.5,"taxOnTax":false} """; a = await Util.PutAsync("tax-code", token, putPayload); Util.ValidateHTTPStatusCode(a, 200); var newConcurrency = a.ObjectResponse["data"]["concurrency"].Value(); newConcurrency.Should().NotBe(concurrency, "concurrency should have been bumped by the update"); // Verify the update was persisted a = await Util.GetAsync($"tax-code/{Id}", token); Util.ValidateDataReturnResponseOk(a); a.ObjectResponse["data"]["name"].Value().Should().Be(updatedName); a.ObjectResponse["data"]["taxAPct"].Value().Should().Be(5.0m); a.ObjectResponse["data"]["taxBPct"].Value().Should().Be(2.5m); // CONCURRENCY VIOLATION: PUT with stale concurrency should return 409 a = await Util.PutAsync("tax-code", token, putPayload); // putPayload still has old concurrency Util.ValidateConcurrencyError(a); // DELETE a = await Util.DeleteAsync($"tax-code/{Id}", token); Util.ValidateHTTPStatusCode(a, 204); // Confirm deleted a = await Util.GetAsync($"tax-code/{Id}", token); Util.ValidateResponseNotFound(a); } }//eoc }//eons