using Xunit; using Newtonsoft.Json.Linq; using FluentAssertions; namespace raven_integration { public class ContractCrud { /// /// Full CRUD for a Contract, including a concurrency violation check. /// Contract has a richer required-field set than most objects (billing override /// type enums, response time, etc.) so this test exercises the full model round-trip. /// /// ContractOverrideType enum: PriceDiscount = 1, CostMarkup = 2 /// [Fact] public async Task CRUD() { var token = await Util.GetTokenAsync("BizAdmin"); // ------------------------------------------------------------------- // CREATE // responseTime: TimeSpan JSON format is "HH:MM:SS" // partsOverrideType / serviceRatesOverrideType / travelRatesOverrideType: // 1 = PriceDiscount, 2 = CostMarkup // ------------------------------------------------------------------- var name = Util.Uniquify("Test Contract"); var payload = $$""" {"id":0,"concurrency":0,"name":"{{name}}","active":true,"notes":"The quick brown fox jumped over the six lazy dogs!","wiki":null,"customFields":"{}","tags":[],"responseTime":"01:00:00","contractServiceRatesOnly":false,"contractTravelRatesOnly":false,"partsOverridePct":10.0,"partsOverrideType":1,"serviceRatesOverridePct":5.0,"serviceRatesOverrideType":1,"travelRatesOverridePct":0.0,"travelRatesOverrideType":1,"alertNotes":"Contract alert text"} """; ApiResponse a = await Util.PostAsync("contract", token, payload); Util.ValidateDataReturnResponseOk(a); long Id = a.ObjectResponse["data"]["id"].Value(); Id.Should().BeGreaterThan(0); a.ObjectResponse["data"]["name"].Value().Should().Be(name); a.ObjectResponse["data"]["partsOverrideType"].Value().Should().Be(1); // ------------------------------------------------------------------- // GET // ------------------------------------------------------------------- a = await Util.GetAsync($"contract/{Id}", token); Util.ValidateDataReturnResponseOk(a); a.ObjectResponse["data"]["name"].Value().Should().Be(name); a.ObjectResponse["data"]["alertNotes"].Value().Should().Be("Contract alert text"); var concurrency = a.ObjectResponse["data"]["concurrency"].Value(); // ------------------------------------------------------------------- // PUT — Contract PUT returns the full updated object (not just concurrency) // ------------------------------------------------------------------- var updatedName = Util.Uniquify("Updated Contract"); var putPayload = $$""" {"id":{{Id}},"concurrency":{{concurrency}},"name":"{{updatedName}}","active":true,"notes":"Updated notes","wiki":null,"customFields":"{}","tags":[],"responseTime":"02:00:00","contractServiceRatesOnly":true,"contractTravelRatesOnly":false,"partsOverridePct":15.0,"partsOverrideType":2,"serviceRatesOverridePct":0.0,"serviceRatesOverrideType":1,"travelRatesOverridePct":5.0,"travelRatesOverrideType":1,"alertNotes":"Updated alert"} """; a = await Util.PutAsync("contract", token, putPayload); Util.ValidateHTTPStatusCode(a, 200); // PUT returns the full updated contract object a.ObjectResponse["data"]["name"].Value().Should().Be(updatedName); a.ObjectResponse["data"]["partsOverrideType"].Value().Should().Be(2, "should have changed to CostMarkup"); var newConcurrency = a.ObjectResponse["data"]["concurrency"].Value(); newConcurrency.Should().NotBe(concurrency, "concurrency should have been bumped"); // Verify update persisted a = await Util.GetAsync($"contract/{Id}", token); Util.ValidateDataReturnResponseOk(a); a.ObjectResponse["data"]["name"].Value().Should().Be(updatedName); a.ObjectResponse["data"]["contractServiceRatesOnly"].Value().Should().BeTrue(); // ------------------------------------------------------------------- // CONCURRENCY VIOLATION: PUT with stale concurrency should return 409 // ------------------------------------------------------------------- a = await Util.PutAsync("contract", token, putPayload); // putPayload has the old concurrency Util.ValidateConcurrencyError(a); // ------------------------------------------------------------------- // DELETE // ------------------------------------------------------------------- a = await Util.DeleteAsync($"contract/{Id}", token); Util.ValidateHTTPStatusCode(a, 204); // Confirm deleted a = await Util.GetAsync($"contract/{Id}", token); Util.ValidateResponseNotFound(a); } }//eoc }//eons