context: // <copyright file="NonUnifiedPart.cs" company="Allors bvba">
  // Copyright (c) Allors bvba. All rights reserved.
  // Licensed under the LGPL license. See LICENSE file in the project root for full license information.
  // </copyright>
  
  using System.Text;
  
  namespace Allors.Domain
  {
      using System.Linq;
  
      using Allors.Meta;
  
      public partial class NonUnifiedPart
      {
          private bool IsDeletable => !this.ExistNonUnifiedGoodsWherePart
              && !this.ExistWorkEffortInventoryProducedsWherePart
              && !this.ExistWorkEffortPartStandardsWherePart
              && !this.ExistPartBillOfMaterialsWherePart
              && !this.ExistPartBillOfMaterialsWhereComponentPart
              && !this.ExistPurchaseInvoiceItemsWherePart
              && !this.ExistPurchaseOrderItemsWherePart
              && !this.ExistSalesInvoiceItemsWherePart
              && !this.ExistShipmentItemsWherePart;
  
          public void BaseOnBuild(ObjectOnBuild method)
          {
              if (!this.ExistInventoryItemKind)
              {
                  this.InventoryItemKind = new InventoryItemKinds(this.Strategy.Session).NonSerialised;
              }
  
              if (!this.ExistUnitOfMeasure)
              {
                  this.UnitOfMeasure = new UnitsOfMeasure(this.Strategy.Session).Piece;
              }
  
              if (!this.ExistDefaultFacility)
              {
                  this.DefaultFacility = this.Strategy.Session.GetSingleton().Settings.DefaultFacility;
              }
  
              this.DeriveName();
          }
  
          public void BaseOnDerive(ObjectOnDerive method)
          {
              var derivation = method.Derivation;
  
              var setings = this.Strategy.Session.GetSingleton().Settings;
  
              if (derivation.ChangeSet.HasChangedRoles(this, new RoleType[] { this.Meta.UnitOfMeasure, this.Meta.DefaultFacility }))
              {
                  this.SyncDefaultInventoryItem();
              }
  
              this.DeriveName();
  
              var identifications = this.ProductIdentifications;
              identifications.Filter.AddEquals(M.ProductIdentification.ProductIdentificationType, new ProductIdentificationTypes(this.Strategy.Session).Part);
              var partIdentification = identifications.FirstOrDefault();
  
              if (partIdentification == null && setings.UsePartNumberCounter)
              {
                  partIdentification = new PartNumberBuilder(this.Strategy.Session)
                      .WithIdentification(setings.NextPartNumber())
                      .WithProductIdentificationType(new ProductIdentificationTypes(this.Strategy.Session).Part).Build();
  
                  this.AddProductIdentification(partIdentification);
              }
  
              this.ProductNumber = partIdentification.Identification;
  
              this.RemoveSuppliedBy();
              foreach (SupplierOffering supplierOffering in this.SupplierOfferingsWherePart)
              {
                  if (supplierOffering.FromDate <= this.Session().Now()
                      && (!supplierOffering.ExistThroughDate || supplierOffering.ThroughDate >= this.Session().Now()))
                  {
                      this.AddSuppliedBy(supplierOffering.Supplier);
                  }
              }
  
              this.DeriveProductCharacteristics(derivation);
              this.DeriveQuantityOnHand();
              this.DeriveAvailableToPromise();
              this.DeriveQuantityCommittedOut();
              this.DeriveQuantityExpectedIn();
  
              var quantityOnHand = 0M;
              var totalCost = 0M;
  
              foreach (InventoryItemTransaction inventoryTransaction in this.InventoryItemTransactionsWherePart)
              {
                  var reason = inventoryTransaction.Reason;
  
                  if (reason.IncreasesQuantityOnHand == true)
                  {
                      quantityOnHand += inventoryTransaction.Quantity;
  
                      var transactionCost = inventoryTransaction.Quantity * inventoryTransaction.Cost;
                      totalCost += transactionCost;
  
                      var averageCost = quantityOnHand > 0 ? totalCost / quantityOnHand : 0M;
                      ((PartWeightedAverageDerivedRoles)this.PartWeightedAverage).AverageCost = decimal.Round(averageCost, 2);
                  }
                  else if (reason.IncreasesQuantityOnHand == false)
                  {
                      quantityOnHand -= inventoryTransaction.Quantity;
  
                      totalCost = quantityOnHand * this.PartWeightedAverage.AverageCost;
                  }
              }
          }
  
          public void BaseOnPostDerive(ObjectOnPostDerive method)
          {
              var deletePermission = new Permissions(this.Strategy.Session).Get(this.Meta.ObjectType, this.Meta.Delete, Operations.Execute);
              if (this.IsDeletable)
              {
                  this.RemoveDeniedPermission(deletePermission);
              }
              else
              {
                  this.AddDeniedPermission(deletePermission);
              }
          }
  
          public void BaseDelete(DeletableDelete method)
          {
              if (this.IsDeletable)
              {
                  foreach (ProductIdentification productIdentification in this.ProductIdentifications)
                  {
                      productIdentification.Delete();
                  }
  
                  foreach (LocalisedText localisedText in this.LocalisedNames)
                  {
                      localisedText.Delete();
                  }
  
                  foreach (LocalisedText localisedText in this.LocalisedDescriptions)
                  {
                      localisedText.Delete();
                  }
  
                  foreach (InventoryItem inventoryItem in this.InventoryItemsWherePart)
                  {
                      inventoryItem.Delete();
                  }
  
                  foreach (PartSubstitute partSubstitute in this.PartSubstitutesWherePart)
                  {
                      partSubstitute.Delete();
                  }
  
                  foreach (PartSubstitute partSubstitute in this.PartSubstitutesWhereSubstitutionPart)
                  {
                      partSubstitute.Delete();
                  }
  
                  foreach (SupplierOffering supplierOffering in this.SupplierOfferingsWherePart)
                  {
                      supplierOffering.Delete();
                  }
              }
          }
  
          private void DeriveName()
          {
              if (!this.ExistName)
              {
                  this.Name = "Part " + (this.PartIdentification() ?? this.UniqueId.ToString());
              }
          }
  
          private void SyncDefaultInventoryItem()
          {
              if (this.InventoryItemKind.IsNonSerialised)
              {
                  var inventoryItems = this.InventoryItemsWherePart;
  
                  if (!inventoryItems.Any(i => i.Facility.Equals(this.DefaultFacility) && i.UnitOfMeasure.Equals(this.UnitOfMeasure)))
                  {
                      var inventoryItem = (InventoryItem)new NonSerialisedInventoryItemBuilder(this.Strategy.Session)
                        .WithFacility(this.DefaultFacility)
                        .WithUnitOfMeasure(this.UnitOfMeasure)
                        .WithPart(this)
                        .Build();
                  }
              }
          }
  
          private void DeriveProductCharacteristics(IDerivation derivation)
          {
              var characteristicsToDelete = this.SerialisedItemCharacteristics.ToList();
  
              if (this.ExistProductType)
              {
                  foreach (SerialisedItemCharacteristicType characteristicType in this.ProductType.SerialisedItemCharacteristicTypes)
                  {
                      var characteristic = this.SerialisedItemCharacteristics.FirstOrDefault(v => Equals(v.SerialisedItemCharacteristicType, characteristicType));
                      if (characteristic == null)
                      {
                          this.AddSerialisedItemCharacteristic(
                              new SerialisedItemCharacteristicBuilder(this.Strategy.Session)
                                  .WithSerialisedItemCharacteristicType(characteristicType)
                                  .Build());
                      }
                      else
                      {
                          characteristicsToDelete.Remove(characteristic);
                      }
                  }
              }
  
              foreach (var characteristic in characteristicsToDelete)
              {
                  this.RemoveSerialisedItemCharacteristic(characteristic);
              }
          }
  
          private void DeriveQuantityOnHand()
          {
              this.QuantityOnHand = 0;
  
              foreach (InventoryItem inventoryItem in this.InventoryItemsWherePart)
              {
                  if (inventoryItem is NonSerialisedInventoryItem nonSerialisedItem)
                  {
                      this.QuantityOnHand += nonSerialisedItem.QuantityOnHand;
                  }
                  else if (inventoryItem is SerialisedInventoryItem serialisedItem)
                  {
                      this.QuantityOnHand += serialisedItem.QuantityOnHand;
                  }
              }
          }
  
          private void DeriveAvailableToPromise()
          {
              this.AvailableToPromise = 0;
  
              foreach (InventoryItem inventoryItem in this.InventoryItemsWherePart)
              {
                  if (inventoryItem is NonSerialisedInventoryItem nonSerialisedItem)
                  {
                      this.AvailableToPromise += nonSerialisedItem.AvailableToPromise;
                  }
                  else if (inventoryItem is SerialisedInventoryItem serialisedItem)
                  {
                      this.AvailableToPromise += serialisedItem.AvailableToPromise;
                  }
              }
          }
  
          private void DeriveQuantityCommittedOut()
          {
              this.QuantityCommittedOut = 0;
  
              foreach (InventoryItem inventoryItem in this.InventoryItemsWherePart)
              {
                  if (inventoryItem is NonSerialisedInventoryItem nonSerialised)
                  {
                      this.QuantityCommittedOut += nonSerialised.QuantityCommittedOut;
                  }
              }
          }
  
          private void DeriveQuantityExpectedIn()
          {
              this.QuantityExpectedIn = 0;
  
              foreach (InventoryItem inventoryItem in this.InventoryItemsWherePart)
              {
                  if (inventoryItem is NonSerialisedInventoryItem nonSerialised)
                  {
  
gt:                     this.QuantityExpectedIn += nonSerialised.QuantityExpectedIn;