public async Task UpdateWithProductionDetails()
            {
                var result = await CreateCostEntity(User);

                var updateModel = new UpdateCostModel
                {
                    ProductionDetails = new ProductionDetail
                    {
                        Data = new Dictionary <string, dynamic>
                        {
                            { "type", "AIPE" },
                            { "Prop", new { prop = "Test prop" } }
                        }
                    }
                };

                var updatedResult = await Browser.Put($"/v1/costs/{result.Id}", w =>
                {
                    w.User(User);
                    w.JsonBody(updateModel);
                });

                var updateResponse = Deserialize <OperationResponse>(updatedResult, HttpStatusCode.OK);

                updateResponse.Success.Should().BeTrue();
            }
            public async Task GetCustomFormData()
            {
                var cost = await CreateCostEntity(User);

                var updateModel = new UpdateCostModel
                {
                    ProductionDetails = new ProductionDetail
                    {
                        Data = new Dictionary <string, dynamic>
                        {
                            { "type", "AIPE" },
                            { "talentCompanies", new[] { "TalentCo1", "TalentCo2" } }
                        }
                    }
                };

                var updatedResult = await Browser.Put($"/v1/costs/{cost.Id}", w =>
                {
                    w.User(User);
                    w.JsonBody(updateModel);
                });

                var updateResponse = Deserialize <OperationResponse>(updatedResult, HttpStatusCode.OK);

                updateResponse.Success.Should().BeTrue();

                var latestStage = await GetCostLatestStage(cost.Id, User);

                var latestRevision = await GetCostLatestRevision(cost.Id, latestStage.Id, User);

                var productionDetailsForm = Deserialize <CustomFormDataModel>(
                    await Browser.Get($"/v1/costs/{cost.Id}/custom-form-data/{latestRevision.ProductDetailsId}", w => w.User(User)),
                    HttpStatusCode.OK);

                var type            = productionDetailsForm.Data.Value <string>("type");
                var talentCompanies = productionDetailsForm.Data["talentCompanies"].Values <string>().ToArray();

                type.Should().Be(updateModel.ProductionDetails.Data["type"]);
                talentCompanies.Should().BeEquivalentTo(updateModel.ProductionDetails.Data["talentCompanies"]);
            }
            public async Task AddExpectedApprovals(string costTitle, string contentType, string productionType, string[] expectedApprovals)
            {
                await CreateCostEntity(User);

                var approverName = $"{Guid.NewGuid()}approver";
                var approver     = await CreateUser(approverName, Roles.CostApprover);

                var cost = Deserialize <E.Cost>(await CreateCost(User, new CreateCostModel
                {
                    TemplateId   = CostTemplate.Id,
                    StageDetails = new StageDetails
                    {
                        Data = new Dictionary <string, dynamic>
                        {
                            { "title", costTitle },
                            { "agencyProducer", new [] { "bob" } },
                            { "description", "123" },
                            { "budgetRegion", new AbstractTypeValue {
                                  Key = Constants.BudgetRegion.AsiaPacific
                              } },
                            { "organisation", new core.Builders.DictionaryValue {
                                  Key = "SMO"
                              } },
                            { "smo", "OTHER EUROPE" },
                            { "contentType", new { id = Guid.NewGuid(), key = contentType, value = contentType } },
                            { "campaign", "test" },
                            { "productionType", new { id = Guid.NewGuid(), key = productionType, value = productionType } },
                            { "agencyTrackingNumber", "122" },
                            { "agencyCurrency", "GBP" },
                            { "isAIPE", "true" },
                            { "projectId", "123456789" },
                            { "costNumber", "AC123123456789" },
                            { "approvalStage", CostStages.Aipe.ToString() },
                            { "initialBudget", 123123123 },
                            { "targetBudget", 453453454 },
                            { "agency", new PgStageDetailsForm.AbstractTypeAgency
                              {
                                  Id             = User.AgencyId,
                                  AbstractTypeId = User.Agency.AbstractTypes.FirstOrDefault().Id,
                                  Name           = User.Agency.Name
                              } }
                        }
                    }
                }), HttpStatusCode.Created);

                var updateModel = new UpdateCostModel
                {
                    ProductionDetails = new ProductionDetail
                    {
                        Data = new Dictionary <string, dynamic>
                        {
                            { "type", "AIPE" },
                            { "talentCompanies", new[] { "TalentCo1", "TalentCo2" } }
                        }
                    }
                };

                var updateResponse = Deserialize <OperationResponse>(await Browser.Put($"/v1/costs/{cost.Id}", w =>
                {
                    w.User(User);
                    w.JsonBody(updateModel);
                }), HttpStatusCode.OK);

                // this should create a default currency
                await GetDefaultCurrency();

                updateResponse.Success.Should().BeTrue();

                // let's move to next stage
                await SetCostStatus(cost, E.CostStageRevisionStatus.Approved);
                await ExecuteActionAndValidateResponse(cost.Id, CostAction.NextStage, User);

                var latestStage = await GetCostLatestStage(cost.Id, User);

                var latestRevision = await GetCostLatestRevision(cost.Id, latestStage.Id, User);

                // latest revision id is not really latest revision any more - it's the previous one (AIPE)

                var currency = await GetDefaultCurrency();

                var lineItemSection = await EFContext.CostLineItemSectionTemplate.FirstOrDefaultAsync(ts => ts.Name == Constants.CostSection.Production);

                await CreateCostLineItems(cost.Id, latestStage.Id, latestRevision.Id, new List <CostLineItemModel>
                {
                    new CostLineItemModel
                    {
                        Name              = "Item1",
                        Value             = 4128423942,
                        LocalCurrencyId   = currency.Id,
                        TemplateSectionId = lineItemSection.Id
                    }
                },
                                          User);

                var approvalsUrl = ApprovalsUrl(cost.Id, latestStage.Id, latestRevision.Id);

                var approvals = new[]
                {
                    new ApprovalModel
                    {
                        Status             = E.ApprovalStatus.New,
                        Type               = E.ApprovalType.IPM,
                        ValidBusinessRoles = new[] { "s" },
                        ApprovalMembers    = new List <ApprovalModel.Member>
                        {
                            new ApprovalModel.Member
                            {
                                Id    = approver.Id,
                                Email = $"{approverName}@adstream.com"
                            }
                        }
                    },
                    new ApprovalModel
                    {
                        Status             = E.ApprovalStatus.New,
                        Type               = E.ApprovalType.Brand,
                        ValidBusinessRoles = new[] { "s" },
                        ApprovalMembers    = new List <ApprovalModel.Member>()
                    }
                };

                await Browser.Post(approvalsUrl, r =>
                {
                    r.User(User);
                    r.JsonBody(approvals);
                });

                var approvalsResponse = Deserialize <ApprovalModel[]>(
                    await Browser.Get(approvalsUrl, w => w.User(User)), HttpStatusCode.OK);

                approvalsResponse.Should().HaveCount(2);
                var ipmApproval = approvalsResponse.First(a => a.Type == E.ApprovalType.IPM);

                ipmApproval.ApprovalMembers.Should().HaveCount(1);
                ipmApproval.ApprovalMembers[0].Email.Should().Be($"{approverName}@adstream.com");
            }
            public async Task AddExpectedApprovalsAIPE(string costTitle, string contentType, string productionType, string[] expectedApprovals)
            {
                await CreateCostEntity(User);

                var approverName = $"{Guid.NewGuid()}Brandapprover";
                var approver     = await CreateUser(approverName, Roles.CostApprover, null, plugins.Constants.BusinessRole.BrandManager);

                var cost = Deserialize <E.Cost>(await CreateCost(User, new CreateCostModel
                {
                    TemplateId   = CostTemplate.Id,
                    StageDetails = new StageDetails
                    {
                        Data = new Dictionary <string, dynamic>
                        {
                            { "title", costTitle },
                            { "agencyProducer", new [] { "bob" } },
                            { "description", "123" },
                            { "budgetRegion", new AbstractTypeValue {
                                  Key = Constants.BudgetRegion.AsiaPacific
                              } },
                            { "organisation", new core.Builders.DictionaryValue {
                                  Key = "SMO"
                              } },
                            { "smo", "OTHER EUROPE" },
                            { "contentType", new { id = Guid.NewGuid(), key = contentType, value = contentType } },
                            { "campaign", "test" },
                            { "productionType", new { id = Guid.NewGuid(), key = productionType, value = productionType } },
                            { "agencyTrackingNumber", "122" },
                            { "agencyCurrency", "GBP" },
                            { "isAIPE", "true" },
                            { "projectId", "123456789" },
                            { "costNumber", "AC123123456789" },
                            { "approvalStage", CostStages.Aipe.ToString() },
                            { "initialBudget", 123123123 },
                            { "targetBudget", 453453454 },
                            { "agency", new PgStageDetailsForm.AbstractTypeAgency
                              {
                                  Id             = User.AgencyId,
                                  AbstractTypeId = User.Agency.AbstractTypes.FirstOrDefault().Id,
                                  Name           = User.Agency.Name
                              } }
                        }
                    }
                }), HttpStatusCode.Created);

                var updateModel = new UpdateCostModel
                {
                    ProductionDetails = new ProductionDetail
                    {
                        Data = new Dictionary <string, dynamic>
                        {
                            { "type", "AIPE" },
                            { "talentCompanies", new[] { "TalentCo1", "TalentCo2" } }
                        }
                    }
                };

                var updateResponse = Deserialize <OperationResponse>(await Browser.Put($"/v1/costs/{cost.Id}", w =>
                {
                    w.User(User);
                    w.JsonBody(updateModel);
                }), HttpStatusCode.OK);

                updateResponse.Success.Should().BeTrue();
                var latestStage = await GetCostLatestStage(cost.Id, User);

                var latestRevision = await GetCostLatestRevision(cost.Id, latestStage.Id, User);

                var approvalsUrl = ApprovalsUrl(cost.Id, latestStage.Id, latestRevision.Id);

                var approvals = new[]
                {
                    new ApprovalModel
                    {
                        Status             = E.ApprovalStatus.New,
                        Type               = E.ApprovalType.Brand,
                        ValidBusinessRoles = new[] { "s" },
                        ApprovalMembers    = new List <ApprovalModel.Member>
                        {
                            new ApprovalModel.Member
                            {
                                Id    = approver.Id,
                                Email = $"{approverName}@adstream.com"
                            }
                        }
                    }
                };

                await Browser.Post(approvalsUrl, r =>
                {
                    r.User(User);
                    r.JsonBody(approvals);
                });

                var approvalsResponse = Deserialize <ApprovalModel[]>(
                    await Browser.Get(approvalsUrl, w => w.User(User)), HttpStatusCode.OK);

                approvalsResponse.Should().HaveCount(1);
                var brandApproval = approvalsResponse.First(a => a.Type == E.ApprovalType.Brand);

                brandApproval.ApprovalMembers.Should().HaveCount(1);
                brandApproval.ApprovalMembers[0].Email.Should().Be($"{approverName}@adstream.com");
            }
        protected async Task AddApprover(Cost cost, CostUser owner, CostUser approver)
        {
            var updateModel = new UpdateCostModel
            {
                ProductionDetails = new ProductionDetail
                {
                    Data = new Dictionary <string, dynamic>
                    {
                        { "type", "AIPE" },
                        { "talentCompanies", new[] { "TalentCo1", "TalentCo2" } }
                    }
                }
            };

            // Cost update triggers generation of Approval sections
            Deserialize <OperationResponse>(await Browser.Put($"/v1/costs/{cost.Id}", w =>
            {
                w.User(owner);
                w.JsonBody(updateModel);
            }), HttpStatusCode.OK);



            // Now add approval member
            var latestStage = await GetCostLatestStage(cost.Id, owner);

            var latestRevision = await GetCostLatestRevision(cost.Id, latestStage.Id, owner);

            var currency = await GetDefaultCurrency();

            var lineItemSection = await EFContext.CostLineItemSectionTemplate.FirstOrDefaultAsync(ts => ts.Name == plugins.Constants.CostSection.Production);

            await CreateCostLineItems(cost.Id, latestStage.Id, latestRevision.Id, new List <CostLineItemModel>
            {
                new CostLineItemModel
                {
                    Name              = "Item1",
                    Value             = 1000000,
                    LocalCurrencyId   = currency.Id,
                    TemplateSectionId = lineItemSection.Id
                }
            },
                                      User);

            var approvalsUrl = ApprovalsUrl(cost.Id, latestStage.Id, latestRevision.Id);

            var approvals = new[]
            {
                new ApprovalModel
                {
                    Status             = ApprovalStatus.New,
                    Type               = ApprovalType.IPM,
                    ValidBusinessRoles = new[] { "s" },
                    ApprovalMembers    = new List <ApprovalModel.Member>
                    {
                        new ApprovalModel.Member
                        {
                            Id    = approver.Id,
                            Email = approver.Email
                        }
                    }
                },
                new ApprovalModel
                {
                    Status          = ApprovalStatus.New,
                    Type            = ApprovalType.Brand,
                    ApprovalMembers = new List <ApprovalModel.Member>(),
                    Requisitioners  = new List <RequisitionerModel>
                    {
                        new RequisitionerModel
                        {
                            Id    = approver.Id,
                            Email = approver.Email
                        }
                    }
                }
            };

            await Browser.Post(approvalsUrl, r =>
            {
                r.User(owner);
                r.JsonBody(approvals);
            });
        }