private static string GetVendor(PgPurchaseOrderDTO purchaseDto, PgProductionDetailsForm productionDetails)
        {
            var code = productionDetails?.DirectPaymentVendor != null
                ? productionDetails.DirectPaymentVendor.SapVendorCode
                : purchaseDto.AgencyLabels.GetSapVendorCode();

            return(code);
        }
        private PgPurchaseOrder.LongTextField GetLongTextField(CostStageRevisionStatusChanged stageRevisionStatusChanged,
                                                               PgPurchaseOrderDTO purchaseOrderDto, PgStageDetailsForm stageDetailsForm, PgPurchaseOrderResponse purchaseOrderResponse,
                                                               decimal paymentAmount, string currencyCode, CostType costType)
        {
            var longText = new PgPurchaseOrder.LongTextField();

            switch (stageRevisionStatusChanged.Status)
            {
            case CostStageRevisionStatus.PendingBrandApproval:
                longText.VN.AddRange(new[] {
                    "Purchase order does not authorize committing funds without approved EPCAT sheet.",
                    "The services within this Purchase Order can only be ordered from 3rd parties after EPCAT approval."
                });
                var productionTypeIfProductionCost = stageDetailsForm.ProductionType != null ? $"{stageDetailsForm.ProductionType.Key} " : "";
                longText.BN.Add($"{purchaseOrderDto.CostStageRevisionName} APPROVED {costType} {productionTypeIfProductionCost}{purchaseOrderResponse?.PoNumber}".TrimEnd());

                longText.AN.Add($"{_appSettings.FrontendUrl.TrimEnd('/')}/#/cost/{stageRevisionStatusChanged.AggregateId}/review");
                break;

            case CostStageRevisionStatus.PendingCancellation:
                longText.VN.Add("PROJECT CANCELLED. PLEASE CANCEL PO AND REQUEST CN FOR ANY AMOUNTS PAID");
                longText.BN.Add($"PROJECT CANCELLED. PLEASE CANCEL PO {purchaseOrderResponse?.PoNumber} AND REQUEST CN FOR ANY AMOUNTS PAID");
                break;

            case CostStageRevisionStatus.Approved:
                if (purchaseOrderDto.CostStageRevisionKey == CostStages.FinalActual.ToString() || purchaseOrderDto.CostStageRevisionKey == CostStages.FinalActualRevision.ToString())
                {
                    //ADC-2412
                    //Strange issue when the payment amount looks something like -1560.00000000000000000000000000002
                    paymentAmount = Math.Round(paymentAmount, 2);
                    // Get calculated credit amount
                    if (paymentAmount < 0)
                    {
                        longText.BN.Add($"A credit note of { paymentAmount } {currencyCode} is needed, please update PO accordingly.");
                    }
                }
                break;
            }
            return(longText);
        }
        public async Task <PgPurchaseOrder> GetPurchaseOrder(CostStageRevisionStatusChanged stageRevisionStatusChanged)
        {
            var costData = await _efContext.Cost
                           .Include(c => c.LatestCostStageRevision)
                           .ThenInclude(csr => csr.CostStage)
                           .Where(c => c.Id == stageRevisionStatusChanged.AggregateId)
                           .Include(c => c.Parent)
                           .ThenInclude(p => p.Agency)
                           .Select(c => new
            {
                BrandName                 = c.Project.Brand != null ? c.Project.Brand.Name : string.Empty,
                CostNumber                = c.CostNumber,
                CostId                    = c.Id,
                StageDetailsData          = c.LatestCostStageRevision.StageDetails.Data,
                ProductionDetailsData     = c.LatestCostStageRevision.ProductDetails.Data,
                LatestCostStageRevisionId = c.LatestCostStageRevision.Id,
                AgencyLabels              = c.Parent.Agency.Labels,
                CostStageRevisionKey      = c.LatestCostStageRevision.CostStage.Key,
                CostStageRevisionName     = c.LatestCostStageRevision.CostStage.Name,
                Requisitioner             = c.LatestCostStageRevision.Approvals
                                            .Where(a => a.Type == ApprovalType.Brand && a.Requisitioners.Any())
                                            .SelectMany(a => a.Requisitioners)
                                            .Select(r => r.CostUser)
                                            .FirstOrDefault(),
                CostType     = c.CostType,
                ExchangeRate = c.ExchangeRate
            })
                           .FirstOrDefaultAsync();

            if (costData == null)
            {
                _logger.Error($"Couldn't find cost with id {stageRevisionStatusChanged.AggregateId}");
                return(null);
            }

            var purchaseOrderDto = new PgPurchaseOrderDTO
            {
                BrandName                 = costData.BrandName,
                CostNumber                = costData.CostNumber,
                StageDetailsData          = costData.StageDetailsData,
                ProductionDetailsData     = costData.ProductionDetailsData,
                LatestCostStageRevisionId = costData.LatestCostStageRevisionId,
                AgencyLabels              = costData.AgencyLabels,
                CostStageRevisionKey      = costData.CostStageRevisionKey,
                CostStageRevisionName     = costData.CostStageRevisionName,
                RequisitionerEmail        = costData.Requisitioner?.Email,
                TNumber = costData.Requisitioner?.FederationId
            };

            var stageDetailsForm      = JsonConvert.DeserializeObject <PgStageDetailsForm>(purchaseOrderDto.StageDetailsData);
            var productionDetailsForm = purchaseOrderDto.ProductionDetailsData != null?JsonConvert.DeserializeObject <PgProductionDetailsForm>(purchaseOrderDto.ProductionDetailsData) : null;

            var paymentAmount = await GetTotals(stageRevisionStatusChanged.CostStageRevisionId, costData.ExchangeRate);

            var applicableCurrencyCode = await _currencyService.GetCurrencyCode(stageDetailsForm.AgencyCurrency, productionDetailsForm);

            var ledgerMaterialCode = await _ledgerMaterialCode.GetLedgerMaterialCodes(purchaseOrderDto.LatestCostStageRevisionId);

            var purchaseOrderResponse = await _customDataService.GetCustomData <PgPurchaseOrderResponse>(purchaseOrderDto.LatestCostStageRevisionId, CustomObjectDataKeys.PgPurchaseOrderResponse);

            var paymentDetails = await _customDataService.GetCustomData <PgPaymentDetails>(purchaseOrderDto.LatestCostStageRevisionId, CustomObjectDataKeys.PgPaymentDetails);

            var purchaseOrder = new PgPurchaseOrder
            {
                BasketName         = GetBasketName(purchaseOrderDto, stageDetailsForm),
                Description        = GetDescription(purchaseOrderDto, stageDetailsForm),
                TotalAmount        = paymentAmount.TotalAmount,
                PaymentAmount      = paymentAmount.PaymentAmount,
                StartDate          = stageRevisionStatusChanged.TimeStamp,
                CostNumber         = purchaseOrderDto.CostNumber ?? "",
                Currency           = applicableCurrencyCode,
                CategoryId         = ledgerMaterialCode?.MgCode ?? "",
                GL                 = ledgerMaterialCode?.GlCode ?? "",
                DeliveryDate       = GetDeliveryDate(stageRevisionStatusChanged.TimeStamp),
                IONumber           = !string.IsNullOrEmpty(paymentDetails?.IoNumber) ? $"00{paymentDetails.IoNumber}" : "",
                LongText           = GetLongTextField(stageRevisionStatusChanged, purchaseOrderDto, stageDetailsForm, purchaseOrderResponse, paymentAmount.PaymentAmount, applicableCurrencyCode, costData.CostType),
                TNumber            = purchaseOrderDto.TNumber ?? "",
                RequisitionerEmail = purchaseOrderDto.RequisitionerEmail ?? "",
                Vendor             = GetVendor(purchaseOrderDto, productionDetailsForm) ?? "",
                PoNumber           = paymentDetails?.PoNumber ?? "",
                AccountCode        = purchaseOrderResponse?.AccountCode ?? "",
                ItemIdCode         = purchaseOrderResponse?.ItemIdCode ?? "",
                GrNumbers          = await GetGrNumbers(stageRevisionStatusChanged),
                Commodity          = GetCommodity(costData.CostType, stageDetailsForm)
            };

            return(purchaseOrder);
        }
        public async Task <List <XMGOrder> > GetXMGOrder(string costNumber)
        {
            var costData = await _efContext.Cost
                           .Include(c => c.Project).ThenInclude(p => p.Brand)
                           .Include(c => c.CostStages).ThenInclude(cs => cs.CostStageRevisions).ThenInclude(csr => csr.StageDetails)
                           .Include(c => c.CostStages).ThenInclude(cs => cs.CostStageRevisions).ThenInclude(csr => csr.ProductDetails)
                           .Include(c => c.CostStages).ThenInclude(cs => cs.CostStageRevisions).ThenInclude(csr => csr.Approvals).ThenInclude(a => a.Requisitioners).ThenInclude(am => am.CostUser)
                           .Include(c => c.CostStages).ThenInclude(cs => cs.CostStageRevisions).ThenInclude(csr => csr.CustomObjectData)
                           .Include(c => c.CostStages).ThenInclude(cs => cs.CostStageRevisions).ThenInclude(csr => csr.CostStageRevisionPaymentTotals)
                           .Include(c => c.Parent).ThenInclude(p => p.Agency)
                           .Where(c => c.CostNumber == costNumber)
                           .AsNoTracking()
                           .FirstOrDefaultAsync();

            if (costData == null)
            {
                _logger.Error($"Couldn't find cost number {costNumber}");
                return(null);
            }

            var xmgOrders   = new List <XMGOrder>();
            var revisionIds = costData.CostStages.SelectMany(cs => cs.CostStageRevisions).Select(csr => csr.Id).ToList();
            var grNumbers   = (await _customDataService.GetCustomData <PgPurchaseOrderResponse>(revisionIds, CustomObjectDataKeys.PgPurchaseOrderResponse))?
                              .Select(cd => cd.GrNumber)
                              .Distinct()
                              .ToArray();

            foreach (var costStage in costData.CostStages.OrderBy(cs => cs.StageOrder))
            {
                foreach (var revision in costStage.CostStageRevisions.OrderBy(cs => cs.Created))
                {
                    if (revision.CostStageRevisionPaymentTotals == null || !revision.CostStageRevisionPaymentTotals.Any())      //there is no payment - meaning it hasn't come to XMG yet
                    {
                        continue;
                    }

                    var requisitioner = revision.Approvals.Where(a => a.Type == ApprovalType.Brand && a.Requisitioners.Any())
                                        .SelectMany(a => a.Requisitioners)
                                        .Select(r => r.CostUser)
                                        .FirstOrDefault();
                    var purchaseOrderDto = new PgPurchaseOrderDTO
                    {
                        BrandName                 = costData.Project.Brand.Name,
                        CostNumber                = costData.CostNumber,
                        StageDetailsData          = revision.StageDetails.Data,
                        ProductionDetailsData     = revision.ProductDetails.Data,
                        LatestCostStageRevisionId = revision.Id,
                        AgencyLabels              = costData.Parent.Agency.Labels,
                        CostStageRevisionKey      = costStage.Key,
                        CostStageRevisionName     = costStage.Name,
                        RequisitionerEmail        = requisitioner?.Email,
                        TNumber = requisitioner?.FederationId
                    };

                    var stageDetailsForm      = JsonConvert.DeserializeObject <PgStageDetailsForm>(purchaseOrderDto.StageDetailsData);
                    var productionDetailsForm = purchaseOrderDto.ProductionDetailsData != null?JsonConvert.DeserializeObject <PgProductionDetailsForm>(purchaseOrderDto.ProductionDetailsData) : null;

                    var paymentAmount = revision.GetTotalCalculatedPayment(costData.ExchangeRate ?? 1m);

                    var applicableCurrencyCode = await _currencyService.GetCurrencyCode(stageDetailsForm.AgencyCurrency, productionDetailsForm);

                    var ledgerMaterialCode    = revision.CustomObjectData.GetForm <PgLedgerMaterialCodeModel>(CustomObjectDataKeys.PgMaterialLedgerCodes);
                    var purchaseOrderResponse = revision.CustomObjectData.GetForm <PgPurchaseOrderResponse>(CustomObjectDataKeys.PgPurchaseOrderResponse);
                    var paymentDetails        = revision.CustomObjectData.GetForm <PgPaymentDetails>(CustomObjectDataKeys.PgPaymentDetails);

                    var purchaseOrder = new XMGOrder
                    {
                        BasketName    = GetBasketName(purchaseOrderDto, stageDetailsForm),
                        Description   = GetDescription(purchaseOrderDto, stageDetailsForm),
                        TotalAmount   = paymentAmount.TotalAmount,
                        PaymentAmount = paymentAmount.PaymentAmount,
                        StartDate     = revision.Created,
                        CostNumber    = purchaseOrderDto.CostNumber ?? "",
                        Currency      = applicableCurrencyCode,
                        CategoryId    = ledgerMaterialCode?.MgCode ?? "",
                        GL            = ledgerMaterialCode?.GlCode ?? "",
                        DeliveryDate  = GetDeliveryDate(revision.Created),
                        IONumber      = !string.IsNullOrEmpty(paymentDetails?.IoNumber) ? $"00{paymentDetails?.IoNumber}" : "",
                        LongText      = GetLongTextField(new CostStageRevisionStatusChanged
                        {
                            Status      = revision.Status,
                            AggregateId = costData.Id
                        }, purchaseOrderDto, stageDetailsForm, purchaseOrderResponse, paymentAmount.PaymentAmount, applicableCurrencyCode, costData.CostType),
                        TNumber            = purchaseOrderDto.TNumber ?? "",
                        RequisitionerEmail = purchaseOrderDto.RequisitionerEmail ?? "",
                        Vendor             = GetVendor(purchaseOrderDto, productionDetailsForm) ?? "",
                        PoNumber           = paymentDetails?.PoNumber ?? "",
                        AccountCode        = purchaseOrderResponse?.AccountCode ?? "",
                        ItemIdCode         = purchaseOrderResponse?.ItemIdCode ?? "",
                        GrNumbers          = grNumbers ?? new string[0],
                        Commodity          = GetCommodity(costData.CostType, stageDetailsForm),
                        StageName          = revision.Name,
                        Status             = revision.Status,
                        Created            = revision.Created,
                        Modified           = revision.Modified,
                        RequisitionId      = purchaseOrderResponse?.Requisition,
                        AccumulatedAmount  = costData.GetAccumulatedAmount(revision),
                        PaidSteps          = costData.GetPaidSteps(revision)
                    };
                    xmgOrders.Add(purchaseOrder);
                }
            }

            return(xmgOrders);
        }
        private static string GetDescription(PgPurchaseOrderDTO purchaseOrderDto, PgStageDetailsForm stageDetailsForm)
        {
            var description = string.Format(DesciptionTemplate, stageDetailsForm.ContentType?.Value, stageDetailsForm.BudgetRegion?.Name, purchaseOrderDto.CostNumber);

            return(Truncate(description, 50));
        }
        private static string GetBasketName(PgPurchaseOrderDTO purchaseOrderDto, PgStageDetailsForm stageDetailsForm)
        {
            var basketName = string.Format(BasketNameTemplate, purchaseOrderDto.CostNumber, purchaseOrderDto.BrandName, stageDetailsForm.Description);

            return(Truncate(basketName));
        }